diff --git a/.gitignore b/.gitignore index c20457a15..af7dd576d 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ frontend/mobile/android/ tmp/ ios android +.idea/modules.xml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d05e1d14c..d8643b9ce 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,6 +16,9 @@ - [PostgreSQL](https://www.postgresql.org/) - Install through brew: `brew install postgresql@15` - It requires you to add all the exports to path so read the end of the installation carefully! +- [Redis](https://redis.io/docs/latest/operate/oss_and_stack/install/install-stack/) + - Install through brew: `brew tap redis-stack/redis-stack` + - Then install: `brew install redis-stack` - [Trunk](https://marketplace.visualstudio.com/items?itemName=Trunk.io) (Recommended!) - Visual Studio Code extension for linting/formatting - [migrate](https://github.com/golang-migrate/migrate) diff --git a/backend/auth/jwt.go b/backend/auth/jwt.go index 5aec8d5e4..fb66f5803 100644 --- a/backend/auth/jwt.go +++ b/backend/auth/jwt.go @@ -276,35 +276,22 @@ func copyCustomClaims(claims *jwt.MapClaims, customClaims map[string]interface{} } } -func GenerateRefreshCookie(value string) *fiber.Cookie { - return &fiber.Cookie{ +func SetResponseTokens(c *fiber.Ctx, tokens *Token) { + c.Set("Authorization", fmt.Sprintf("Bearer %s", tokens.AccessToken)) + c.Cookie(&fiber.Cookie{ Name: "refresh_token", - Value: value, + Value: string(tokens.RefreshToken), Expires: time.Now().Add(constants.REFRESH_TOKEN_EXPIRY), HTTPOnly: true, - } + }) } -func SetResponseTokens(c *fiber.Ctx, tokens *Token) error { - // Set the tokens in the response - // should also blacklist the old refresh and access tokens - - c.Set("Authorization", fmt.Sprintf("Bearer %s", tokens.AccessToken)) +func ExpireResponseTokens(c *fiber.Ctx) { + c.Set("Authorization", "") c.Cookie(&fiber.Cookie{ Name: "refresh_token", - Value: string(tokens.RefreshToken), - Expires: time.Now().Add(constants.REFRESH_TOKEN_EXPIRY), + Value: "", + Expires: time.Now().Add(-time.Hour), HTTPOnly: true, }) - - return nil } - -// func ExpireCookie(name string) *fiber.Cookie { -// return &fiber.Cookie{ -// Name: name, -// Value: "", -// Expires: time.Now().Add(-time.Hour), -// HTTPOnly: true, -// } -// } diff --git a/backend/config/config.go b/backend/config/config.go index ae7097431..487be2715 100644 --- a/backend/config/config.go +++ b/backend/config/config.go @@ -10,6 +10,7 @@ import ( type Settings struct { Application ApplicationSettings Database DatabaseSettings + Redis []RedisSettings SuperUser SuperUserSettings Auth AuthSettings AWS AWSSettings @@ -24,6 +25,7 @@ type Settings struct { type intermediateSettings struct { Application ApplicationSettings `yaml:"application"` Database intermediateDatabaseSettings `yaml:"database"` + Redis []intermediateRedisSettings `yaml:"redis"` SuperUser intermediateSuperUserSettings `yaml:"superuser"` Auth intermediateAuthSettings `yaml:"authsecret"` Calendar intermediateCalendarSettings `yaml:"calendar"` @@ -35,6 +37,16 @@ func (int *intermediateSettings) into() (*Settings, error) { return nil, err } + redisSettings := make([]RedisSettings, len(int.Redis)) + for i, r := range int.Redis { + redisInstance, err := r.into() + if err != nil { + return nil, err + } + + redisSettings[i] = *redisInstance + } + superUserSettings, err := int.SuperUser.into() if err != nil { return nil, err @@ -53,6 +65,7 @@ func (int *intermediateSettings) into() (*Settings, error) { return &Settings{ Application: int.Application, Database: *databaseSettings, + Redis: redisSettings, SuperUser: *superUserSettings, Auth: *authSettings, Calendar: *calendarSettings, diff --git a/backend/config/redis.go b/backend/config/redis.go new file mode 100644 index 000000000..ab1ef9667 --- /dev/null +++ b/backend/config/redis.go @@ -0,0 +1,41 @@ +package config + +import ( + "errors" + + m "github.com/garrettladley/mattress" +) + +type RedisSettings struct { + Username string `yaml:"username"` + Host string `yaml:"host"` + Port uint `yaml:"port"` + Password *m.Secret[string] `yaml:"password"` + DB int `yaml:"db"` + // TLSConfig *TLSConfig `yaml:"tlsconfig"` +} + +func (int *intermediateRedisSettings) into() (*RedisSettings, error) { + password, err := m.NewSecret(int.Password) + if err != nil { + return nil, errors.New("failed to create secret from password") + } + + return &RedisSettings{ + Username: int.Username, + Host: int.Host, + Port: int.Port, + Password: password, + DB: int.DB, + // TLSConfig: int.TLSConfig.into(), + }, nil +} + +type intermediateRedisSettings struct { + Username string `yaml:"username"` + Host string `yaml:"host"` + Port uint `yaml:"port"` + Password string `yaml:"password"` + DB int `yaml:"db"` + // TLSConfig *intermediateTLSConfig `yaml:"tlsconfig"` +} diff --git a/backend/constants/auth.go b/backend/constants/auth.go index 9a014df3b..894f49783 100644 --- a/backend/constants/auth.go +++ b/backend/constants/auth.go @@ -3,8 +3,10 @@ package constants import "time" const ( - ACCESS_TOKEN_EXPIRY time.Duration = time.Minute * 24 * 30 // temporary TODO: change to 60 minutes - REFRESH_TOKEN_EXPIRY time.Duration = time.Minute * 24 * 30 + ACCESS_TOKEN_EXPIRY time.Duration = time.Hour * 12 + REFRESH_TOKEN_EXPIRY time.Duration = time.Hour * 24 * 30 + OTP_LENGTH int = 6 + OTP_EXPIRY time.Duration = time.Minute * 5 CSRF_TOKEN_LENGTH int = 32 ) diff --git a/backend/constants/redis.go b/backend/constants/redis.go new file mode 100644 index 000000000..229acff5b --- /dev/null +++ b/backend/constants/redis.go @@ -0,0 +1,13 @@ +package constants + +import "time" + +const ( + REDIS_MAX_IDLE_CONNECTIONS int = 10 + REDIS_MAX_OPEN_CONNECTIONS int = 100 + TOKEN_BLACKLIST_SKEY string = "token_blacklist" + TOKEN_BLACKLIST_KEY string = "blacklisted" + RATE_LIMIT_DURATION time.Duration = 5 * time.Minute + RATE_LIMIT_MAX_REQUESTS int = 5 + REDIS_TIMEOUT time.Duration = 200 * time.Millisecond +) diff --git a/backend/database/store/active_token.go b/backend/database/store/active_token.go new file mode 100644 index 000000000..0fd669d29 --- /dev/null +++ b/backend/database/store/active_token.go @@ -0,0 +1,39 @@ +package store + +import ( + "context" + "time" +) + +type ActiveTokenInterface interface { + StoreRefreshToken(ctx context.Context, token string, userID string, expiry time.Duration) error + IsActive(ctx context.Context, token string) (bool, error) + GetRefreshToken(ctx context.Context, token string) (string, error) + DeleteRefreshToken(ctx context.Context, token string) error +} + +type ActiveToken struct { + StoreClient StoreClientInterface +} + +func NewActiveToken(storeClient StoreClientInterface) *ActiveToken { + return &ActiveToken{ + StoreClient: storeClient, + } +} + +func (a *ActiveToken) StoreRefreshToken(ctx context.Context, token string, userID string, expiry time.Duration) error { + return a.StoreClient.Set(ctx, token, userID, expiry) +} + +func (a *ActiveToken) GetRefreshToken(ctx context.Context, token string) (string, error) { + return a.StoreClient.Get(ctx, token) +} + +func (a *ActiveToken) IsActive(ctx context.Context, token string) (bool, error) { + return a.StoreClient.Exists(ctx, token) +} + +func (a *ActiveToken) DeleteRefreshToken(ctx context.Context, token string) error { + return a.StoreClient.Del(ctx, token) +} diff --git a/backend/database/store/blacklist.go b/backend/database/store/blacklist.go new file mode 100644 index 000000000..22ff6ac67 --- /dev/null +++ b/backend/database/store/blacklist.go @@ -0,0 +1,36 @@ +package store + +import ( + "context" + "time" + + "github.com/GenerateNU/sac/backend/constants" +) + +type BlacklistInterface interface { + BlacklistToken(ctx context.Context, token string, expiry time.Duration) error + IsTokenBlacklisted(ctx context.Context, token string) (bool, error) +} + +type Blacklist struct { + storeClient StoreClientInterface +} + +func NewBlacklist(storeClient StoreClientInterface) *Blacklist { + return &Blacklist{ + storeClient: storeClient, + } +} + +func (b *Blacklist) BlacklistToken(ctx context.Context, token string, expiry time.Duration) error { + err := b.storeClient.SetAdd(ctx, constants.TOKEN_BLACKLIST_SKEY, token) + if err != nil { + return err + } + + return b.storeClient.Set(ctx, token, constants.TOKEN_BLACKLIST_KEY, expiry) +} + +func (b *Blacklist) IsTokenBlacklisted(ctx context.Context, token string) (bool, error) { + return b.storeClient.SetIsMember(ctx, constants.TOKEN_BLACKLIST_SKEY, token) +} diff --git a/backend/database/store/limiter.go b/backend/database/store/limiter.go new file mode 100644 index 000000000..c7bd0e3f0 --- /dev/null +++ b/backend/database/store/limiter.go @@ -0,0 +1,50 @@ +package store + +import ( + "context" + "time" +) + +// LimiterInterface is an implementation of https://github.com/gofiber/storage +type LimiterInterface interface { + Get(key string) ([]byte, error) + Set(key string, val []byte, exp time.Duration) error + Delete(key string) error + Reset() error + Close() error +} + +type Limiter struct { + StoreClient StoreClientInterface +} + +func NewLimiter(storeClient StoreClientInterface) *Limiter { + return &Limiter{ + StoreClient: storeClient, + } +} + +func (l *Limiter) Get(key string) ([]byte, error) { + value, err := l.StoreClient.Get(context.Background(), key) + if err != nil { + return nil, err + } + + return []byte(value), nil +} + +func (l *Limiter) Set(key string, val []byte, exp time.Duration) error { + return l.StoreClient.Set(context.Background(), key, string(val), exp) +} + +func (l *Limiter) Delete(key string) error { + return l.StoreClient.Del(context.Background(), key) +} + +func (l *Limiter) Reset() error { + return l.StoreClient.FlushAll(context.Background()) +} + +func (l *Limiter) Close() error { + return l.StoreClient.Close(context.Background()) +} diff --git a/backend/database/store/redis.go b/backend/database/store/redis.go new file mode 100644 index 000000000..f8235c1f2 --- /dev/null +++ b/backend/database/store/redis.go @@ -0,0 +1,94 @@ +package store + +import ( + "bytes" + "fmt" + "log/slog" + "os/exec" + + "github.com/GenerateNU/sac/backend/config" +) + +type Stores struct { + Limiter LimiterInterface + Blacklist BlacklistInterface + ActiveToken ActiveTokenInterface +} + +func NewStores(limiter LimiterInterface, blacklist BlacklistInterface, activeToken ActiveTokenInterface) *Stores { + return &Stores{ + Limiter: limiter, + Blacklist: blacklist, + ActiveToken: activeToken, + } +} + +func ConfigureRedis(settings config.Settings) *Stores { + var activeTokens *ActiveToken + var blacklist *Blacklist + var limiter *Limiter + + for _, service := range settings.Redis { + client := NewRedisClient(service.Username, service.Host, service.Port, service.Password, service.DB) + switch service.Username { + case "redis_active_tokens": + activeTokens = NewActiveToken(client) + case "redis_blacklist": + blacklist = NewBlacklist(client) + case "redis_limiter": + limiter = NewLimiter(client) + default: + slog.Error("unknown redis service", service.Username, "skipping...") + } + } + + stores := NewStores(limiter, blacklist, activeTokens) + + MustEstablishConn() + + return stores +} + +// TODO: this will be a part of a larger function that will check all services +func MustEstablishConn() { + isRunning, err := isDockerComposeRunning() + if err != nil { + panic(err) + } + + if !*isRunning { + if err := restartServices(); err != nil { + panic(err) + } + } +} + +func isDockerComposeRunning() (*bool, error) { + cmd := exec.Command("docker-compose", "ps", "-q") + + var out bytes.Buffer + cmd.Stdout = &out + err := cmd.Run() + if err != nil { + return nil, fmt.Errorf("error checking if docker-compose is running: %s", err.Error()) + } + + result := out.Len() > 0 + return &result, nil +} + +func restartServices() error { + cmd := exec.Command("docker-compose", "up", "-d") + + var out bytes.Buffer + cmd.Stdout = &out + cmd.Stderr = &out + + err := cmd.Run() + if err != nil { + return fmt.Errorf("error restarting services: %s \nconsole output: %s", err.Error(), out.String()) + } + + slog.Info("Services restarted successfully.") + return nil +} diff --git a/backend/database/store/store.go b/backend/database/store/store.go new file mode 100644 index 000000000..074765484 --- /dev/null +++ b/backend/database/store/store.go @@ -0,0 +1,76 @@ +package store + +import ( + "context" + "fmt" + "runtime" + "time" + + "github.com/GenerateNU/sac/backend/constants" + m "github.com/garrettladley/mattress" + "github.com/redis/go-redis/v9" +) + +type StoreClientInterface interface { + Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error + Get(ctx context.Context, key string) (string, error) + Del(ctx context.Context, key string) error + Exists(ctx context.Context, key string) (bool, error) + SetAdd(ctx context.Context, key string, members ...interface{}) error + SetIsMember(ctx context.Context, key string, member interface{}) (bool, error) + FlushAll(ctx context.Context) error + Close(ctx context.Context) error +} + +type RedisClient struct { + client *redis.Client +} + +func NewRedisClient(username, host string, port uint, password *m.Secret[string], db int) *RedisClient { + client := redis.NewClient(&redis.Options{ + Username: username, + Addr: fmt.Sprintf("%s:%d", host, port), + Password: password.Expose(), + DB: db, + PoolSize: 10 * runtime.GOMAXPROCS(0), + MaxActiveConns: constants.REDIS_MAX_OPEN_CONNECTIONS, + MaxIdleConns: constants.REDIS_MAX_IDLE_CONNECTIONS, + }) + + return &RedisClient{ + client: client, + } +} + +func (r *RedisClient) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error { + return r.client.Set(ctx, key, value, expiration).Err() +} + +func (r *RedisClient) Get(ctx context.Context, key string) (string, error) { + return r.client.Get(ctx, key).Result() +} + +func (r *RedisClient) Del(ctx context.Context, key string) error { + return r.client.Del(ctx, key).Err() +} + +func (r *RedisClient) Exists(ctx context.Context, key string) (bool, error) { + result, err := r.client.Exists(ctx, key).Result() + return result > 0, err +} + +func (r *RedisClient) SetAdd(ctx context.Context, key string, members ...interface{}) error { + return r.client.SAdd(ctx, key, members...).Err() +} + +func (r *RedisClient) SetIsMember(ctx context.Context, key string, member interface{}) (bool, error) { + return r.client.SIsMember(ctx, key, member).Result() +} + +func (r *RedisClient) FlushAll(ctx context.Context) error { + return r.client.FlushAll(ctx).Err() +} + +func (r *RedisClient) Close(ctx context.Context) error { + return r.client.Close() +} diff --git a/backend/docker-compose.yml b/backend/docker-compose.yml new file mode 100644 index 000000000..e46632407 --- /dev/null +++ b/backend/docker-compose.yml @@ -0,0 +1,35 @@ +services: + redis-active-tokens: + image: redis/redis-stack-server:latest + container_name: redis_active_tokens + ports: + - 6379:6379 + environment: + - REDIS_PASSWORD=redispassword!#1 + volumes: + - redis-active-data:/data + + redis-blacklist: + image: redis/redis-stack-server:latest + container_name: redis_blacklist + ports: + - 6380:6379 + environment: + - REDIS_PASSWORD=redispassword!#2 + volumes: + - redis-blacklist-data:/data + + redis-limiter: + image: redis/redis-stack-server:latest + container_name: redis_limiter + ports: + - 6381:6379 + environment: + - REDIS_PASSWORD=redispassword!#3 + volumes: + - redis-limiter-data:/data + +volumes: + redis-active-data: + redis-blacklist-data: + redis-limiter-data: diff --git a/backend/entities/auth/base/controller.go b/backend/entities/auth/base/controller.go index 0b2189416..52a671e97 100644 --- a/backend/entities/auth/base/controller.go +++ b/backend/entities/auth/base/controller.go @@ -39,15 +39,12 @@ func (a *AuthController) Login(c *fiber.Ctx) error { return utilities.InvalidJSON() } - user, tokens, err := a.authService.Login(userBody) + user, tokens, err := a.authService.Login(c.UserContext(), userBody) if err != nil { return err } - err = auth.SetResponseTokens(c, tokens) - if err != nil { - return err - } + auth.SetResponseTokens(c, tokens) return c.Status(http.StatusOK).JSON(user) } @@ -73,15 +70,12 @@ func (a *AuthController) Register(c *fiber.Ctx) error { return utilities.InvalidJSON() } - user, tokens, err := a.authService.Register(userBody) + user, tokens, err := a.authService.Register(c.UserContext(), userBody) if err != nil { return err } - err = auth.SetResponseTokens(c, tokens) - if err != nil { - return err - } + auth.SetResponseTokens(c, tokens) return c.Status(http.StatusCreated).JSON(user) } @@ -106,17 +100,14 @@ func (a *AuthController) Refresh(c *fiber.Ctx) error { return utilities.InvalidCookies() } - tokens, err := a.authService.Refresh(refreshBody.RefreshToken) + tokens, err := a.authService.Refresh(c.UserContext(), refreshBody.RefreshToken) if err != nil { return err } - err = auth.SetResponseTokens(c, tokens) - if err != nil { - return err - } + auth.SetResponseTokens(c, tokens) - return utilities.FiberMessage(c, http.StatusOK, "success") + return c.SendStatus(http.StatusOK) } // Logout godoc @@ -130,12 +121,13 @@ func (a *AuthController) Refresh(c *fiber.Ctx) error { // @Success 200 {object} utilities.SuccessResponse // @Router /auth/logout [post] func (a *AuthController) Logout(c *fiber.Ctx) error { - err := a.authService.Logout(c) - if err != nil { + if err := a.authService.Logout(c.UserContext(), c.Get("Authorization"), c.Cookies("refresh_token")); err != nil { return err } - return utilities.FiberMessage(c, http.StatusOK, "success") + auth.ExpireResponseTokens(c) + + return c.SendStatus(http.StatusOK) } // ForgotPassword godoc @@ -163,7 +155,7 @@ func (a *AuthController) ForgotPassword(c *fiber.Ctx) error { return err } - return utilities.FiberMessage(c, http.StatusOK, "success") + return c.SendStatus(http.StatusOK) } // VerifyPasswordResetToken godoc @@ -192,7 +184,7 @@ func (a *AuthController) VerifyPasswordResetToken(c *fiber.Ctx) error { return err } - return utilities.FiberMessage(c, http.StatusOK, "success") + return c.SendStatus(http.StatusOK) } // SendCode godoc @@ -220,7 +212,7 @@ func (a *AuthController) SendCode(c *fiber.Ctx) error { return err } - return utilities.FiberMessage(c, http.StatusOK, "success") + return c.SendStatus(http.StatusOK) } // VerifyEmail godoc @@ -248,5 +240,5 @@ func (a *AuthController) VerifyEmail(c *fiber.Ctx) error { return err } - return utilities.FiberMessage(c, http.StatusOK, "success") + return c.SendStatus(http.StatusOK) } diff --git a/backend/entities/auth/base/routes.go b/backend/entities/auth/base/routes.go index b79cbd818..1e5c86744 100644 --- a/backend/entities/auth/base/routes.go +++ b/backend/entities/auth/base/routes.go @@ -1,6 +1,7 @@ package base import ( + "github.com/GenerateNU/sac/backend/constants" "github.com/GenerateNU/sac/backend/types" ) @@ -15,11 +16,9 @@ func Auth(params types.RouteParams) { auth.Post("/login", authController.Login) auth.Post("/refresh", authController.Refresh) - // TODO: rate limit - auth.Post("/send-code", authController.SendCode) + auth.Post("/send-code", params.UtilityMiddleware.Limiter(constants.RATE_LIMIT_MAX_REQUESTS, constants.RATE_LIMIT_DURATION), authController.SendCode) auth.Post("/verify-email", authController.VerifyEmail) - // TODO: rate limit - auth.Post("/forgot-password", authController.ForgotPassword) + auth.Post("/forgot-password", params.UtilityMiddleware.Limiter(constants.RATE_LIMIT_MAX_REQUESTS, constants.RATE_LIMIT_DURATION), authController.ForgotPassword) auth.Post("/verify-reset", authController.VerifyPasswordResetToken) } diff --git a/backend/entities/auth/base/service.go b/backend/entities/auth/base/service.go index c2ebc4371..c8a0c5415 100644 --- a/backend/entities/auth/base/service.go +++ b/backend/entities/auth/base/service.go @@ -1,31 +1,34 @@ package base import ( + "context" "errors" "fmt" "log/slog" "time" "github.com/GenerateNU/sac/backend/auth" + "github.com/GenerateNU/sac/backend/constants" authEntities "github.com/GenerateNU/sac/backend/entities/auth" "github.com/GenerateNU/sac/backend/entities/models" "github.com/GenerateNU/sac/backend/entities/users" usersEntities "github.com/GenerateNU/sac/backend/entities/users/base" + "github.com/GenerateNU/sac/backend/errs" "github.com/GenerateNU/sac/backend/types" + "github.com/GenerateNU/sac/backend/utilities" - "github.com/gofiber/fiber/v2" "github.com/golang-jwt/jwt" "gorm.io/gorm" ) type AuthServiceInterface interface { GetRole(id string) (*models.UserRole, error) - Register(userBody usersEntities.CreateUserRequestBody) (*models.User, *auth.Token, error) - Login(userBody authEntities.LoginResponseBody) (*models.User, *auth.Token, error) - Refresh(refreshToken string) (*auth.Token, error) - Logout(c *fiber.Ctx) error + Register(ctx context.Context, userBody usersEntities.CreateUserRequestBody) (*models.User, *auth.Token, error) + Login(ctx context.Context, userBody authEntities.LoginResponseBody) (*models.User, *auth.Token, error) + Refresh(ctx context.Context, refreshToken string) (*auth.Token, error) + Logout(ctx context.Context, accessToken string, refreshToken string) error SendCode(email string) error VerifyEmail(emailBody VerifyEmailRequestBody) error @@ -42,7 +45,7 @@ func NewAuthService(serviceParams types.ServiceParams) AuthServiceInterface { return &AuthService{serviceParams} } -func (a *AuthService) Login(loginBody authEntities.LoginResponseBody) (*models.User, *auth.Token, error) { +func (a *AuthService) Login(ctx context.Context, loginBody authEntities.LoginResponseBody) (*models.User, *auth.Token, error) { if err := utilities.Validate(a.Validate, loginBody, *utilities.NewMaybeError("password", auth.ValidatePassword(loginBody.Password))); err != nil { return nil, nil, err } @@ -75,10 +78,16 @@ func (a *AuthService) Login(loginBody authEntities.LoginResponseBody) (*models.U return nil, nil, err } + storeRefreshTokenCtx, storeRefreshTokenCancel := context.WithTimeoutCause(ctx, constants.REDIS_TIMEOUT, errs.ErrRedisTimeout) + defer storeRefreshTokenCancel() + if err := a.Stores.ActiveToken.StoreRefreshToken(storeRefreshTokenCtx, string(tokens.RefreshToken), user.ID.String(), constants.REFRESH_TOKEN_EXPIRY); err != nil { + return nil, nil, err + } + return user, tokens, nil } -func (a *AuthService) Register(userBody usersEntities.CreateUserRequestBody) (*models.User, *auth.Token, error) { +func (a *AuthService) Register(ctx context.Context, userBody usersEntities.CreateUserRequestBody) (*models.User, *auth.Token, error) { if err := utilities.Validate(a.Validate, userBody, *utilities.NewMaybeError("password", auth.ValidatePassword(userBody.Password))); err != nil { return nil, nil, err } @@ -111,7 +120,9 @@ func (a *AuthService) Register(userBody usersEntities.CreateUserRequestBody) (*m return nil, nil, err } - _, tokens, err := a.Login(authEntities.LoginResponseBody{Email: user.Email, Password: userBody.Password}) + loginCtx, loginCancel := context.WithTimeoutCause(ctx, constants.REDIS_TIMEOUT, errs.ErrRedisTimeout) + defer loginCancel() + _, tokens, err := a.Login(loginCtx, authEntities.LoginResponseBody{Email: user.Email, Password: userBody.Password}) if err != nil { return nil, nil, err } @@ -119,7 +130,29 @@ func (a *AuthService) Register(userBody usersEntities.CreateUserRequestBody) (*m return user, tokens, nil } -func (a *AuthService) Refresh(refreshToken string) (*auth.Token, error) { +func (a *AuthService) Refresh(ctx context.Context, refreshToken string) (*auth.Token, error) { + isActiveCtx, isActiveCancel := context.WithTimeoutCause(ctx, constants.REDIS_TIMEOUT, errs.ErrRedisTimeout) + defer isActiveCancel() + isActive, err := a.Stores.ActiveToken.IsActive(isActiveCtx, refreshToken) + if err != nil { + return nil, err + } + + if !isActive { + return nil, utilities.Unauthorized() + } + + isBlacklistedCtx, isBlacklistedCancel := context.WithTimeoutCause(ctx, constants.REDIS_TIMEOUT, errs.ErrRedisTimeout) + defer isBlacklistedCancel() + isblacklisted, err := a.Stores.Blacklist.IsTokenBlacklisted(isBlacklistedCtx, refreshToken) + if err != nil { + return nil, err + } + + if isblacklisted { + return nil, utilities.Unauthorized() + } + claims, err := a.JWT.ExtractClaims(refreshToken, auth.RefreshToken) if err != nil { return nil, err @@ -148,6 +181,24 @@ func (a *AuthService) Refresh(refreshToken string) (*auth.Token, error) { return nil, err } + blackListCtx, blackListCancel := context.WithTimeoutCause(ctx, constants.REDIS_TIMEOUT, errs.ErrRedisTimeout) + defer blackListCancel() + if err := a.Stores.Blacklist.BlacklistToken(blackListCtx, refreshToken, time.Until(time.Unix(int64(claims["exp"].(float64)), 0))); err != nil { + return nil, err + } + + deleteRefreshTokenCtx, deleteRefreshTokenCancel := context.WithTimeoutCause(ctx, constants.REDIS_TIMEOUT, errs.ErrRedisTimeout) + defer deleteRefreshTokenCancel() + if err := a.Stores.ActiveToken.DeleteRefreshToken(deleteRefreshTokenCtx, refreshToken); err != nil { + return nil, err + } + + storeRefreshTokenCtx, storeRefreshTokenCancel := context.WithTimeoutCause(ctx, constants.REDIS_TIMEOUT, errs.ErrRedisTimeout) + defer storeRefreshTokenCancel() + if err := a.Stores.ActiveToken.StoreRefreshToken(storeRefreshTokenCtx, string(tokens.RefreshToken), claims["iss"].(string), constants.REFRESH_TOKEN_EXPIRY); err != nil { + return nil, err + } + return tokens, nil } @@ -272,12 +323,12 @@ func (a *AuthService) SendCode(email string) error { return nil } - otp, err := auth.GenerateOTP(6) + otp, err := auth.GenerateOTP(constants.OTP_LENGTH) if err != nil { return fmt.Errorf("failed to generate OTP: %w", err) } - if err := SaveToken(a.DB, user.ID, *otp, models.EmailVerificationType, time.Now().Add(time.Minute*5).UTC()); err != nil { + if err := SaveToken(a.DB, user.ID, *otp, models.EmailVerificationType, time.Now().Add(constants.OTP_EXPIRY).UTC()); err != nil { return err } @@ -349,16 +400,62 @@ func (a *AuthService) VerifyEmail(emailBody VerifyEmailRequestBody) error { return nil } -func (a *AuthService) Logout(c *fiber.Ctx) error { - c.Cookie(&fiber.Cookie{ - Name: "refresh_token", - Value: "", - Expires: time.Now().Add(-time.Hour), - HTTPOnly: true, - }) - c.Set("Authorization ", "") +func (a *AuthService) Logout(ctx context.Context, accessToken string, refreshToken string) error { + if accessToken == "" { + return utilities.Unauthorized() + } + + token, err := utilities.SplitBearerToken(accessToken) + if err != nil { + return utilities.Unauthorized() + } + + blacklistAccessTokenCtx, blacklistAccessTokenCancel := context.WithTimeoutCause(ctx, constants.REDIS_TIMEOUT, errs.ErrRedisTimeout) + defer blacklistAccessTokenCancel() + if err = blacklist(blacklistAccessTokenCtx, a, token); err != nil { + return utilities.Unauthorized() + } - // TODO: blacklist the refresh token + if refreshToken == "" { + return utilities.Unauthorized() + } + + isActiveCtx, isActiveCancel := context.WithTimeoutCause(ctx, constants.REDIS_TIMEOUT, errs.ErrRedisTimeout) + defer isActiveCancel() + isActive, err := a.Stores.ActiveToken.IsActive(isActiveCtx, refreshToken) + if err != nil { + return utilities.Unauthorized() + } + + if !isActive { + return utilities.Unauthorized() + } + + blacklistRefreshTokenCtx, blacklistRefreshTokenCancel := context.WithTimeoutCause(ctx, constants.REDIS_TIMEOUT, errs.ErrRedisTimeout) + defer blacklistRefreshTokenCancel() + if err := blacklist(blacklistRefreshTokenCtx, a, &refreshToken); err != nil { + return utilities.Unauthorized() + } + + deleteRefreshTokenCtx, deleteRefreshTokenCancel := context.WithTimeoutCause(ctx, constants.REDIS_TIMEOUT, errs.ErrRedisTimeout) + defer deleteRefreshTokenCancel() + if err := a.Stores.ActiveToken.DeleteRefreshToken(deleteRefreshTokenCtx, refreshToken); err != nil { + return err + } + + return nil +} + +func blacklist(ctx context.Context, a *AuthService, token *string) error { + claims, err := a.JWT.ExtractClaims(*token, auth.AccessToken) + if err != nil { + return err + } else { + exp, ok := claims["exp"].(float64) + if ok { + _ = a.Stores.Blacklist.BlacklistToken(ctx, *token, time.Until(time.Unix(int64(exp), 0))) + } + } return nil } diff --git a/backend/entities/auth/models.go b/backend/entities/auth/models.go index dc65fbb76..0c7415a07 100644 --- a/backend/entities/auth/models.go +++ b/backend/entities/auth/models.go @@ -9,7 +9,3 @@ type UpdatePasswordRequestBody struct { OldPassword string `json:"old_password" validate:"required"` // MARK: must be validated manually NewPassword string `json:"new_password" validate:"required,not_equal_if_not_empty=OldPassword"` // MARK: must be validated manually } - -type RefreshTokenRequestBody struct { - RefreshToken string `json:"refresh_token" validate:"required"` -} diff --git a/backend/errs/redis.go b/backend/errs/redis.go new file mode 100644 index 000000000..2223823c0 --- /dev/null +++ b/backend/errs/redis.go @@ -0,0 +1,5 @@ +package errs + +import "errors" + +var ErrRedisTimeout = errors.New("redis timeout") diff --git a/backend/go.mod b/backend/go.mod index 2e4146a5a..013d87529 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -18,11 +18,13 @@ require ( github.com/huandu/go-assert v1.1.6 github.com/joho/godotenv v1.5.1 github.com/mcnijman/go-emailaddress v1.1.1 + github.com/redis/go-redis/v9 v9.5.1 github.com/resend/resend-go/v2 v2.6.0 github.com/sahilm/fuzzy v0.1.1 github.com/spf13/viper v1.18.2 github.com/swaggo/swag v1.16.3 go.opentelemetry.io/otel/sdk v1.27.0 + go.opentelemetry.io/otel/trace v1.27.0 golang.org/x/crypto v0.23.0 golang.org/x/text v0.15.0 gorm.io/driver/postgres v1.5.7 @@ -41,6 +43,8 @@ require ( ) require ( + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect @@ -50,7 +54,6 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect go.opentelemetry.io/contrib v1.17.0 // indirect go.opentelemetry.io/otel/metric v1.27.0 // indirect - go.opentelemetry.io/otel/trace v1.27.0 // indirect go.uber.org/atomic v1.11.0 // indirect ) diff --git a/backend/go.sum b/backend/go.sum index 5319c6380..b0981411c 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -16,10 +16,18 @@ github.com/awnumar/memguard v0.22.5 h1:PH7sbUVERS5DdXh3+mLo8FDcl1eIeVjJVYMnyuYpv github.com/awnumar/memguard v0.22.5/go.mod h1:+APmZGThMBWjnMlKiSM1X7MVpbIVewen2MTkqWkA/zE= github.com/aws/aws-sdk-go v1.53.8 h1:eoqGb1WOHIrCFKo1d51cMcnt1ralfLFaEqRkC5Zzv8k= github.com/aws/aws-sdk-go v1.53.8/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dhui/dktest v0.4.1 h1:/w+IWuDXVymg3IrRJCHHOkMK10m9aNVMOyD0X12YVTg= github.com/dhui/dktest v0.4.1/go.mod h1:DdOqcUpL7vgyP4GlF3X3w7HbSlz8cEQzwewPveYEQbA= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= @@ -164,6 +172,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/redis/go-redis/v9 v9.5.1 h1:H1X4D3yHPaYrkL5X06Wh6xNVM/pX0Ft4RV0vMGvLBh8= +github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= github.com/resend/resend-go/v2 v2.6.0 h1:bHwF79iCYC3V9H7/DL0MAIoz0hiAqM+Rq9G4EhgooyE= github.com/resend/resend-go/v2 v2.6.0/go.mod h1:ihnxc7wPpSgans8RV8d8dIF4hYWVsqMK5KxXAr9LIos= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= diff --git a/backend/main.go b/backend/main.go index f420ec916..57ddcf942 100644 --- a/backend/main.go +++ b/backend/main.go @@ -6,11 +6,11 @@ import ( "fmt" "log/slog" "net" - "os" "path/filepath" "github.com/GenerateNU/sac/backend/config" "github.com/GenerateNU/sac/backend/database" + "github.com/GenerateNU/sac/backend/database/store" _ "github.com/GenerateNU/sac/backend/docs" "github.com/GenerateNU/sac/backend/integrations" "github.com/GenerateNU/sac/backend/integrations/email" @@ -20,6 +20,7 @@ import ( "github.com/GenerateNU/sac/backend/server" "github.com/GenerateNU/sac/backend/telemetry" "github.com/GenerateNU/sac/backend/tests/api/mocks" + "github.com/GenerateNU/sac/backend/utilities" ) func main() { @@ -33,17 +34,17 @@ func main() { config, err := config.GetConfiguration(*configPath, *useDevDotEnv) if err != nil { - exit("Error getting configuration: %s", err.Error()) + utilities.Exit("Error getting configuration: %s", err.Error()) } err = checkServerRunning(config.Application.Host, config.Application.Port) if err == nil { - exit("A server is already running on %s:%d.\n", config.Application.Host, config.Application.Port) + utilities.Exit("A server is already running on %s:%d.\n", config.Application.Host, config.Application.Port) } db, err := database.ConfigureDB(*config) if err != nil { - exit("Error migrating database: %s", err.Error()) + utilities.Exit("Error migrating database: %s", err.Error()) } if *onlyMigrate { @@ -56,16 +57,18 @@ func main() { err := pinecone.Seed(db) if err != nil { - exit("Error seeding PineconeDB: %s\n", err.Error()) + utilities.Exit("Error seeding PineconeDB: %s\n", err.Error()) } return } err = database.ConnPooling(db) if err != nil { - exit("Error with connection pooling: %s", err.Error()) + utilities.Exit("Error with connection pooling: %s", err.Error()) } + stores := store.ConfigureRedis(*config) + integrations := configureIntegrations(config, *connectToPinecone) tp := telemetry.InitTracer() @@ -78,11 +81,11 @@ func main() { } }() - app := server.Init(db, integrations, *config) + app := server.Init(db, stores, integrations, *config) err = app.Listen(fmt.Sprintf("%s:%d", config.Application.Host, config.Application.Port)) if err != nil { - exit("Error starting server: %s", err.Error()) + utilities.Exit("Error starting server: %s", err.Error()) } } @@ -96,11 +99,6 @@ func checkServerRunning(host string, port uint16) error { return nil } -func exit(format string, a ...interface{}) { - fmt.Fprintf(os.Stderr, format, a...) - os.Exit(0) -} - func configureIntegrations(config *config.Settings, connectToPinecone bool) integrations.Integrations { openAi := search.NewOpenAIClient(config.OpenAI) var pinecone search.SearchClientInterface @@ -131,5 +129,6 @@ func configureIntegrations(config *config.Settings, connectToPinecone bool) inte Search: pinecone, OAuth: oauthResources, } + return integrations } diff --git a/backend/middleware/auth/auth.go b/backend/middleware/auth/auth.go index eb950b3be..99be76f45 100644 --- a/backend/middleware/auth/auth.go +++ b/backend/middleware/auth/auth.go @@ -1,11 +1,14 @@ package auth import ( + "context" "fmt" "slices" "strings" "github.com/GenerateNU/sac/backend/auth" + "github.com/GenerateNU/sac/backend/constants" + "github.com/GenerateNU/sac/backend/errs" "github.com/GenerateNU/sac/backend/locals" "github.com/GenerateNU/sac/backend/utilities" "github.com/google/uuid" @@ -64,9 +67,16 @@ func (m *AuthMiddlewareService) Authenticate(c *fiber.Ctx) error { return utilities.Unauthorized() } - // if auth.IsBlacklisted(*accessToken) { - // return errors.Unauthorized.FiberError(c) - // } + blacklistCtx, blacklistCancel := context.WithTimeoutCause(c.UserContext(), constants.REDIS_TIMEOUT, errs.ErrRedisTimeout) + defer blacklistCancel() + isBlacklisted, err := m.Stores.Blacklist.IsTokenBlacklisted(blacklistCtx, *accessToken) + if err != nil { + return utilities.InternalServerError() + } + + if isBlacklisted { + return utilities.Unauthorized() + } locals.SetCustomClaims(c, claims) diff --git a/backend/middleware/auth/middleware.go b/backend/middleware/auth/middleware.go index 97b3cafa5..22045ac85 100644 --- a/backend/middleware/auth/middleware.go +++ b/backend/middleware/auth/middleware.go @@ -3,6 +3,7 @@ package auth import ( "github.com/GenerateNU/sac/backend/auth" "github.com/GenerateNU/sac/backend/config" + "github.com/GenerateNU/sac/backend/database/store" "github.com/go-playground/validator/v10" "github.com/gofiber/fiber/v2" "gorm.io/gorm" @@ -20,12 +21,14 @@ type AuthMiddlewareService struct { DB *gorm.DB Validate *validator.Validate Auth config.AuthSettings + Stores *store.Stores } -func New(db *gorm.DB, validate *validator.Validate, authSettings config.AuthSettings) *AuthMiddlewareService { +func New(db *gorm.DB, validate *validator.Validate, authSettings config.AuthSettings, stores *store.Stores) *AuthMiddlewareService { return &AuthMiddlewareService{ DB: db, Validate: validate, Auth: authSettings, + Stores: stores, } } diff --git a/backend/middleware/utility/limiter.go b/backend/middleware/utility/limiter.go index 6f08befdf..39d29bf30 100644 --- a/backend/middleware/utility/limiter.go +++ b/backend/middleware/utility/limiter.go @@ -21,5 +21,6 @@ func (u *UtilityMiddlewareService) Limiter(rate int, expiration time.Duration) f LimitReached: func(c *fiber.Ctx) error { return utilities.NewAPIError(http.StatusTooManyRequests, errors.New("too many requests")) }, + Storage: u.Stores.Limiter, }) } diff --git a/backend/middleware/utility/middleware.go b/backend/middleware/utility/middleware.go index cd940ea93..2f582e913 100644 --- a/backend/middleware/utility/middleware.go +++ b/backend/middleware/utility/middleware.go @@ -3,6 +3,7 @@ package utility import ( "time" + "github.com/GenerateNU/sac/backend/database/store" "github.com/gofiber/fiber/v2" ) @@ -13,10 +14,12 @@ type UtilityMiddlewareInterface interface { type UtilityMiddlewareService struct { paginator fiber.Handler + Stores *store.Stores } -func New(paginator fiber.Handler) *UtilityMiddlewareService { +func New(paginator fiber.Handler, stores *store.Stores) *UtilityMiddlewareService { return &UtilityMiddlewareService{ paginator: paginator, + Stores: stores, } } diff --git a/backend/server/server.go b/backend/server/server.go index 0a4fd9f29..3178afc45 100644 --- a/backend/server/server.go +++ b/backend/server/server.go @@ -8,6 +8,8 @@ import ( authenticator "github.com/GenerateNU/sac/backend/auth" "github.com/GenerateNU/sac/backend/config" + "github.com/GenerateNU/sac/backend/database/store" + auth "github.com/GenerateNU/sac/backend/entities/auth/base" categories "github.com/GenerateNU/sac/backend/entities/categories/base" clubs "github.com/GenerateNU/sac/backend/entities/clubs/base" @@ -44,7 +46,7 @@ import ( // @host 127.0.0.1:8080 // @BasePath / // @schemes http -func Init(db *gorm.DB, integrations integrations.Integrations, settings config.Settings) *fiber.App { +func Init(db *gorm.DB, stores *store.Stores, integrations integrations.Integrations, settings config.Settings) *fiber.App { app := newFiberApp(settings.Application) validate, err := utilities.RegisterCustomValidators() @@ -53,8 +55,8 @@ func Init(db *gorm.DB, integrations integrations.Integrations, settings config.S } jwt := authenticator.NewJWTClient(settings.Auth, jwt.SigningMethodHS256) - authMiddleware := authMiddleware.New(db, validate, settings.Auth) - utilityMiddleware := utilityMiddleware.New(fiberpaginate.New()) + authMiddleware := authMiddleware.New(db, validate, settings.Auth, stores) + utilityMiddleware := utilityMiddleware.New(fiberpaginate.New(), stores) apiv1 := app.Group("/api/v1") @@ -68,6 +70,7 @@ func Init(db *gorm.DB, integrations integrations.Integrations, settings config.S &settings.Auth, jwt, &settings.Calendar, + stores, integrations, ), ) diff --git a/backend/tests/api/helpers/app.go b/backend/tests/api/helpers/app.go index 755c1be79..ce529b6b8 100644 --- a/backend/tests/api/helpers/app.go +++ b/backend/tests/api/helpers/app.go @@ -38,8 +38,10 @@ func spawnApp() (*TestApp, error) { return nil, err } + stores := ConfigureRedisMock() + return &TestApp{ - App: server.Init(connectionWithDB, *NewMockDependencies(), *configuration), + App: server.Init(connectionWithDB, stores, *NewMockDependencies(), *configuration), Address: fmt.Sprintf("http://%s", listener.Addr().String()), Conn: connectionWithDB, Settings: *configuration, diff --git a/backend/tests/api/helpers/redis.go b/backend/tests/api/helpers/redis.go new file mode 100644 index 000000000..581b00ff3 --- /dev/null +++ b/backend/tests/api/helpers/redis.go @@ -0,0 +1,30 @@ +package helpers + +import ( + "github.com/GenerateNU/sac/backend/database/store" + "github.com/GenerateNU/sac/backend/tests/api/mocks" +) + +type StoresMock struct { + Limiter store.LimiterInterface + Blacklist store.BlacklistInterface + ActiveToken store.ActiveTokenInterface +} + +func NewStoresMock(limiter store.LimiterInterface, blacklist store.BlacklistInterface, activeToken store.ActiveTokenInterface) *store.Stores { + return &store.Stores{ + Limiter: limiter, + Blacklist: blacklist, + ActiveToken: activeToken, + } +} + +func ConfigureRedisMock() *store.Stores { + limiter := mocks.NewLimiterMock(mocks.NewRedisMockClient()) + blacklist := mocks.NewBlacklistMock(mocks.NewRedisMockClient()) + activeToken := mocks.NewActiveTokenMock(mocks.NewRedisMockClient()) + + stores := NewStoresMock(limiter, blacklist, activeToken) + + return stores +} diff --git a/backend/tests/api/mocks/redis_mock.go b/backend/tests/api/mocks/redis_mock.go new file mode 100644 index 000000000..db10d70fd --- /dev/null +++ b/backend/tests/api/mocks/redis_mock.go @@ -0,0 +1,124 @@ +package mocks + +import ( + "context" + "time" + + "github.com/GenerateNU/sac/backend/database/store" +) + +// RedisMockClient implements StoreClientInterface +type RedisMockClient struct{} + +func NewRedisMockClient() *RedisMockClient { + return &RedisMockClient{} +} + +func (r *RedisMockClient) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error { + return nil +} + +func (r *RedisMockClient) Get(ctx context.Context, key string) (string, error) { + return "", nil +} + +func (r *RedisMockClient) Del(ctx context.Context, key string) error { + return nil +} + +func (r *RedisMockClient) Exists(ctx context.Context, key string) (bool, error) { + return false, nil +} + +func (r *RedisMockClient) SetAdd(ctx context.Context, key string, members ...interface{}) error { + return nil +} + +func (r *RedisMockClient) SetIsMember(ctx context.Context, key string, member interface{}) (bool, error) { + return false, nil +} + +func (r *RedisMockClient) FlushAll(ctx context.Context) error { + return nil +} + +func (r *RedisMockClient) Close(ctx context.Context) error { + return nil +} + +// ActiveTokenMock implements ActiveTokenInterface +type ActiveTokenMock struct { + StoreClient store.StoreClientInterface +} + +func NewActiveTokenMock(storeClient store.StoreClientInterface) *ActiveTokenMock { + return &ActiveTokenMock{ + StoreClient: storeClient, + } +} + +func (a *ActiveTokenMock) StoreRefreshToken(ctx context.Context, token string, userID string, expiry time.Duration) error { + return nil +} + +func (a *ActiveTokenMock) GetRefreshToken(ctx context.Context, token string) (string, error) { + return "", nil +} + +func (a *ActiveTokenMock) IsActive(ctx context.Context, token string) (bool, error) { + return false, nil +} + +func (a *ActiveTokenMock) DeleteRefreshToken(ctx context.Context, token string) error { + return nil +} + +// BlacklistMock implements BlacklistInterface +type BlacklistMock struct { + StoreClient store.StoreClientInterface +} + +func NewBlacklistMock(storeClient store.StoreClientInterface) *BlacklistMock { + return &BlacklistMock{ + StoreClient: storeClient, + } +} + +func (b *BlacklistMock) BlacklistToken(ctx context.Context, token string, expiry time.Duration) error { + return nil +} + +func (b *BlacklistMock) IsTokenBlacklisted(ctx context.Context, token string) (bool, error) { + return false, nil +} + +// LimiterMock implements LimiterInterface +type LimiterMock struct { + StoreClient store.StoreClientInterface +} + +func NewLimiterMock(storeClient store.StoreClientInterface) *LimiterMock { + return &LimiterMock{ + StoreClient: storeClient, + } +} + +func (l *LimiterMock) Get(key string) ([]byte, error) { + return nil, nil +} + +func (l *LimiterMock) Set(key string, val []byte, exp time.Duration) error { + return nil +} + +func (l *LimiterMock) Delete(key string) error { + return nil +} + +func (l *LimiterMock) Reset() error { + return nil +} + +func (l *LimiterMock) Close() error { + return nil +} diff --git a/backend/types/params.go b/backend/types/params.go index 47a65a348..750c3f86d 100644 --- a/backend/types/params.go +++ b/backend/types/params.go @@ -3,6 +3,7 @@ package types import ( "github.com/GenerateNU/sac/backend/auth" "github.com/GenerateNU/sac/backend/config" + "github.com/GenerateNU/sac/backend/database/store" "github.com/GenerateNU/sac/backend/integrations" authMiddleware "github.com/GenerateNU/sac/backend/middleware/auth" utilityMiddleware "github.com/GenerateNU/sac/backend/middleware/utility" @@ -33,16 +34,18 @@ type ServiceParams struct { Auth *config.AuthSettings JWT auth.JWTClientInterface Calendar *config.CalendarSettings + Stores *store.Stores Integrations integrations.Integrations } -func NewServiceParams(db *gorm.DB, validate *validator.Validate, auth *config.AuthSettings, jwt auth.JWTClientInterface, calendar *config.CalendarSettings, integrations integrations.Integrations) ServiceParams { +func NewServiceParams(db *gorm.DB, validate *validator.Validate, auth *config.AuthSettings, jwt auth.JWTClientInterface, calendar *config.CalendarSettings, stores *store.Stores, integrations integrations.Integrations) ServiceParams { return ServiceParams{ DB: db, Validate: validate, Auth: auth, JWT: jwt, Calendar: calendar, + Stores: stores, Integrations: integrations, } } diff --git a/backend/utilities/exit.go b/backend/utilities/exit.go new file mode 100644 index 000000000..71defedf1 --- /dev/null +++ b/backend/utilities/exit.go @@ -0,0 +1,11 @@ +package utilities + +import ( + "fmt" + "os" +) + +func Exit(format string, a ...interface{}) { + fmt.Fprintf(os.Stderr, format, a...) + os.Exit(0) +} diff --git a/backend/utilities/manipulator.go b/backend/utilities/manipulator.go index 9d37e0764..b1b36bf38 100644 --- a/backend/utilities/manipulator.go +++ b/backend/utilities/manipulator.go @@ -34,3 +34,12 @@ func MapJsonTags[From any, Into any](from From, intoType *Into) (*Into, error) { func NormalizeEmail(email string) string { return strings.ToLower(email) } + +func SplitBearerToken(accessToken string) (*string, error) { + token := strings.Split(accessToken, "Bearer ") + if len(token) != 2 { + return nil, fmt.Errorf("invalid token") + } + + return &token[1], nil +} diff --git a/cli/cmd/redis.go b/cli/cmd/redis.go new file mode 100644 index 000000000..ca78e9eec --- /dev/null +++ b/cli/cmd/redis.go @@ -0,0 +1,61 @@ +package cmd + +import ( + "fmt" + "os" + + "github.com/GenerateNU/sac/cli/helpers" + "github.com/spf13/cobra" +) + +var redisCmd = &cobra.Command{ + Use: "redis", + Aliases: []string{"redis"}, + Short: "Redis management commands", +} + +func init() { + rootCmd.AddCommand(redisCmd) + redisCmd.AddCommand(redisInitCmd) + redisCmd.AddCommand(redisDownCmd) + redisCmd.AddCommand(redisRestartCmd) +} + +var redisInitCmd = &cobra.Command{ + Use: "up", + Short: "Start the Redis container(s)", + Args: cobra.NoArgs, + Run: func(cmd *cobra.Command, args []string) { + err := helpers.UpRedis() + if err != nil { + fmt.Println(err) + os.Exit(1) + } + }, +} + +var redisDownCmd = &cobra.Command{ + Use: "down", + Short: "Stop the Redis container(s)", + Args: cobra.NoArgs, + Run: func(cmd *cobra.Command, args []string) { + err := helpers.DownRedis() + if err != nil { + fmt.Println(err) + os.Exit(1) + } + }, +} + +var redisRestartCmd = &cobra.Command{ + Use: "restart", + Short: "Restart the Redis container(s)", + Args: cobra.NoArgs, + Run: func(cmd *cobra.Command, args []string) { + err := helpers.RestartRedis() + if err != nil { + fmt.Println(err) + os.Exit(1) + } + }, +} diff --git a/cli/go.sum b/cli/go.sum index b1cae943d..457707513 100644 --- a/cli/go.sum +++ b/cli/go.sum @@ -1,92 +1,37 @@ github.com/GenerateNU/sac/backend v0.0.0-20240427140745-74eb4ec0f597 h1:bhattf8C4aGIdJ+0L168MztGMKcznF0ZiEDhvLlHMEU= -github.com/GenerateNU/sac/backend v0.0.0-20240427140745-74eb4ec0f597/go.mod h1:VEuNTR6WQ0OQ5fjMjoRcIymCMjRLdRUM611roK9yQYQ= github.com/awnumar/memcall v0.2.0 h1:sRaogqExTOOkkNwO9pzJsL8jrOV29UuUW7teRMfbqtI= -github.com/awnumar/memcall v0.2.0/go.mod h1:S911igBPR9CThzd/hYQQmTc9SWNu3ZHIlCGaWsWsoJo= github.com/awnumar/memguard v0.22.5 h1:PH7sbUVERS5DdXh3+mLo8FDcl1eIeVjJVYMnyuYpvuI= -github.com/awnumar/memguard v0.22.5/go.mod h1:+APmZGThMBWjnMlKiSM1X7MVpbIVewen2MTkqWkA/zE= -github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= -github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/garrettladley/mattress v0.4.0 h1:ZB3iqyc5q6bqIryNfsh2FMcbMdnV1XEryvqivouceQE= -github.com/garrettladley/mattress v0.4.0/go.mod h1:OWKIRc9wC3gtD3Ng/nUuNEiR1TJvRYLmn/KZYw9nl5Q= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= -github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= -github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= -github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo= -github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= -github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= -github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= -github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= -github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= -github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= -github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= -github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= -github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 h1:985EYyeCOxTpcgOTJpflJUwOeEz0CQOdPt73OzpE9F8= -golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= -gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cli/helpers/backend.go b/cli/helpers/backend.go index 498042e83..34cbf1eb8 100644 --- a/cli/helpers/backend.go +++ b/cli/helpers/backend.go @@ -11,6 +11,11 @@ func RunBackend() error { return fmt.Errorf("error initializing database: %w", err) } + err = UpRedis() + if err != nil { + return fmt.Errorf("error initializing redis: %w", err) + } + err = Execute(exec.Command("go", "run", "main.go"), BACKEND_DIR) if err != nil { return fmt.Errorf("error running backend: %w", err) diff --git a/cli/helpers/redis.go b/cli/helpers/redis.go new file mode 100644 index 000000000..5b4af4006 --- /dev/null +++ b/cli/helpers/redis.go @@ -0,0 +1,33 @@ +package helpers + +import ( + "fmt" + "os/exec" +) + +func UpRedis() error { + err := Execute(exec.Command("docker-compose", "up", "-d"), BACKEND_DIR) + if err != nil { + return fmt.Errorf("error initializing redis: %w", err) + } + + return nil +} + +func DownRedis() error { + err := Execute(exec.Command("docker-compose", "down"), BACKEND_DIR) + if err != nil { + return fmt.Errorf("error stopping redis: %w", err) + } + + return nil +} + +func RestartRedis() error { + err := Execute(exec.Command("docker-compose", "restart"), BACKEND_DIR) + if err != nil { + return fmt.Errorf("error restarting redis: %w", err) + } + + return nil +} diff --git a/config/local.yml b/config/local.yml index 2b1afe5fa..54a93ac0e 100644 --- a/config/local.yml +++ b/config/local.yml @@ -16,3 +16,19 @@ auth: refreshkey: amk*2!gG}1i"8D9RwJS$p calendar: maxterminationdate: 12-31-2024 +redis: + - username: redis_active_tokens + host: 127.0.0.1 + port: 6379 + password: redis_active_token!#1 + db: 0 + - username: redis_blacklist + host: 127.0.0.1 + port: 6380 + password: redis_blacklist!#2 + db: 0 + - username: redis_limiter + host: 127.0.0.1 + port: 6381 + password: redis_limiter!#3 + db: 0 diff --git a/go.work.sum b/go.work.sum index 69986c7fb..a07a013cf 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1,3 +1,4 @@ +cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic= cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk= cloud.google.com/go v0.110.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y= @@ -33,6 +34,11 @@ cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiV cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/firestore v1.14.0/go.mod h1:96MVaHLsEhbvkBEdZgfN+AS/GIkco1LRpH9Xp9YZfzQ= +cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= +cloud.google.com/go/longrunning v0.5.4/go.mod h1:zqNVncI0BOP8ST6XQD1+VcvuShMmq7+xFSzOL++V0dI= +cloud.google.com/go/spanner v1.51.0/go.mod h1:c5KNo5LQ1X5tJwma9rSQZsXNBDNvj4/n8BVc3LNahq0= +cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= cloud.google.com/go/contactcenterinsights v1.11.3/go.mod h1:HHX5wrz5LHVAwfI2smIotQG9x8Qd6gYilaHcLLLmNis= cloud.google.com/go/container v1.27.1/go.mod h1:b1A1gJeTBXVLQ6GGw9/9M4FG94BEGsqJ5+t4d/3N7O4= cloud.google.com/go/containeranalysis v0.11.3/go.mod h1:kMeST7yWFQMGjiG9K7Eov+fPNQcGhb8mXj/UcTiWw9U= @@ -145,6 +151,7 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2 h1:+5VZ72z0Qan5Bog5C+ZkgSq github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 h1:u/LLAOFgsMv7HmNL4Qufg58y+qElGOt5qv0z1mURkRY= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0/go.mod h1:2e8rMJtl2+2j+HXbTBwnyGpm5Nou7KhvSfxOq8JpTag= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest/adal v0.9.16 h1:P8An8Z9rH1ldbOLdFpxYorgOt2sywL9V24dAwWHPuGc= @@ -155,14 +162,16 @@ github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+Z github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/ClickHouse/clickhouse-go v1.4.3/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI= +github.com/GenerateNU/sac/backend v0.0.0-20240427140745-74eb4ec0f597/go.mod h1:VEuNTR6WQ0OQ5fjMjoRcIymCMjRLdRUM611roK9yQYQ= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/ClickHouse/clickhouse-go v1.4.3 h1:iAFMa2UrQdR5bHJ2/yaSLffZkxpcOYQMCUuKeNXGdqc= github.com/ClickHouse/clickhouse-go v1.4.3/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI= github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM= github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/a-h/htmlformat v0.0.0-20231108124658-5bd994fe268e h1:Eog54DQpku7NpPNff9wzQYT61TGu9jjq5N8UhAkqIgw= github.com/a-h/htmlformat v0.0.0-20231108124658-5bd994fe268e/go.mod h1:FMIm5afKmEfarNbIXOaPHFY8X7fo+fRQB6I9MPG2nB0= @@ -172,8 +181,10 @@ github.com/a-h/pathvars v0.0.14 h1:5/C0U5zuUtvAfVQCR5vow4E4MIRU7QIOLz8z26EeeQw= github.com/a-h/pathvars v0.0.14/go.mod h1:7rLTtvDVyKneR/N65hC0lh2sZ2KRyAmWFaOvv00uxb0= github.com/a-h/protocol v0.0.0-20230224160810-b4eec67c1c22 h1:ehNdbGOAR8KTrLY/S90/9RJ4p/cgeNdt1sRt0DSiRWs= github.com/a-h/protocol v0.0.0-20230224160810-b4eec67c1c22/go.mod h1:Gm0KywveHnkiIhqFSMZglXwWZRQICg3KDWLYdglv/d8= -github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY= +github.com/a-h/templ v0.2.697/go.mod h1:5cqsugkq9IerRNucNsI4DEamdHPsoGMQy99DzydLhM8= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= github.com/apache/arrow/go/v10 v10.0.1 h1:n9dERvixoC/1JjDmBcs9FPaEryoANa2sCgVFo6ez9cI= @@ -183,6 +194,9 @@ github.com/apache/thrift v0.16.0 h1:qEy6UW60iVOlUy+b9ZR0d5WzUWYGOo4HfopoyBaNmoY= github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/awnumar/memcall v0.2.0/go.mod h1:S911igBPR9CThzd/hYQQmTc9SWNu3ZHIlCGaWsWsoJo= +github.com/awnumar/memguard v0.22.5/go.mod h1:+APmZGThMBWjnMlKiSM1X7MVpbIVewen2MTkqWkA/zE= +github.com/aws/aws-sdk-go v1.51.30/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/aws/aws-sdk-go v1.50.5 h1:H2Aadcgwr7a2aqS6ZwcE+l1mA6ZrTseYCvjw2QLmxIA= github.com/aws/aws-sdk-go v1.50.5/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/aws/aws-sdk-go-v2 v1.16.16 h1:M1fj4FE2lB4NzRb9Y0xdWsn2P0+2UHVxwKyOa4YJNjk= @@ -211,13 +225,14 @@ github.com/aws/aws-sdk-go-v2/service/s3 v1.27.11 h1:3/gm/JTX9bX8CpzTgIlrtYpB3EVB github.com/aws/aws-sdk-go-v2/service/s3 v1.27.11/go.mod h1:fmgDANqTUCxciViKl9hb/zD5LFbvPINFRgWhDbR+vZo= github.com/aws/smithy-go v1.13.3 h1:l7LYxGuzK6/K+NzJ2mC+VvLUbae0sL3bXU//04MkmnA= github.com/aws/smithy-go v1.13.3/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cli/browser v1.3.0 h1:LejqCrpWr+1pRqmEPDGnTZOjsMe7sehifLynZJuqJpo= github.com/cli/browser v1.3.0/go.mod h1:HH8s+fOAxjhQoBUAsKuPCbqUuxZDhQ2/aD+SzsEfBTk= @@ -234,12 +249,22 @@ github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmf github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369 h1:XNT/Zf5l++1Pyg08/HV04ppB0gKxAqtZQBRYiYrUuYk= github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dhui/dktest v0.4.1/go.mod h1:DdOqcUpL7vgyP4GlF3X3w7HbSlz8cEQzwewPveYEQbA= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dvsekhvalnov/jose2go v1.6.0 h1:Y9gnSnP4qEI0+/uQkHvFXeD2PLPJeXEL+ySMEA2EjTY= github.com/dvsekhvalnov/jose2go v1.6.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= @@ -254,6 +279,23 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/form3tech-oss/jwt-go v3.2.5+incompatible h1:/l4kBbb4/vGSsdtB5nUe8L7B9mImVMaBPw9L/0TBHU8= github.com/form3tech-oss/jwt-go v3.2.5+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fsouza/fake-gcs-server v1.17.0/go.mod h1:D1rTE4YCyHFNa99oyJJ5HyclvN/0uQR+pM/VdlL83bw= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/garrettladley/fiberpaginate v1.0.5/go.mod h1:MHVWGQkhtnt2kE8F0wkTF5iUQOyqZlRktfcGgBLRBv0= +github.com/garrettladley/mattress v0.4.0/go.mod h1:OWKIRc9wC3gtD3Ng/nUuNEiR1TJvRYLmn/KZYw9nl5Q= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/fsouza/fake-gcs-server v1.17.0 h1:OeH75kBZcZa3ZE+zz/mFdJ2btt9FgqfjI7gIh9+5fvk= github.com/fsouza/fake-gcs-server v1.17.0/go.mod h1:D1rTE4YCyHFNa99oyJJ5HyclvN/0uQR+pM/VdlL83bw= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= @@ -262,12 +304,22 @@ github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gG github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gobuffalo/here v0.6.0 h1:hYrd0a6gDmWxBM4TnrGw8mQg24iSVoIkHEk7FodQcBI= github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM= github.com/gocql/gocql v0.0.0-20210515062232-b7ef815b4556 h1:N/MD/sr6o61X+iZBAT2qEUF023s4KbA8RWfKzl0L6MQ= github.com/gocql/gocql v0.0.0-20210515062232-b7ef815b4556/go.mod h1:DL0ekTmBSTdlNF25Orwt/JMzqIq3EJ4MVa/J/uK64OY= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/gofiber/contrib/otelfiber v1.0.10/go.mod h1:jN6AvS1HolDHTQHFURsV+7jSX96FpXYeKH6nmkq8AIw= +github.com/gofiber/fiber/v2 v2.52.4/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= +github.com/gofiber/swagger v1.0.0/go.mod h1:QrYNF1Yrc7ggGK6ATsJ6yfH/8Zi5bu9lA7wB8TmCecg= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-migrate/migrate/v4 v4.17.1/go.mod h1:m8hinFyWBn0SA4QKHuKh175Pm9wjmxj3S2Mia7dbXzM= github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs= github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= @@ -281,6 +333,12 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-github/v39 v39.2.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/flatbuffers v2.0.8+incompatible h1:ivUb1cGomAB101ZM1T0nOiWz9pSrTMoa9+EiY7igmkM= github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= @@ -303,10 +361,14 @@ github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56 github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/googleapis/google-cloud-go-testing v0.0.0-20210719221736-1c9a4c676720 h1:zC34cGQu69FG7qzJ3WiKW244WfhDC3xxYMeNOX2gtUQ= github.com/googleapis/google-cloud-go-testing v0.0.0-20210719221736-1c9a4c676720/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg= github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= +github.com/h2non/gock v1.2.0/go.mod h1:tNhoxHYW2W42cYkYb1WqzdbYIieALC99kpYr7rH/BQk= +github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= @@ -315,6 +377,8 @@ github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hashicorp/consul/api v1.25.1 h1:CqrdhYzc8XZuPnhIYZWH45toM0LB9ZeYr/gvpLVI3PE= github.com/hashicorp/consul/api v1.25.1/go.mod h1:iiLVwR/htV7mas/sy0O+XSuEnrdBUUydemjxcUrAt4g= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/consul/sdk v0.14.1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= @@ -322,6 +386,13 @@ github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+ github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= +github.com/huandu/go-assert v1.1.6/go.mod h1:JuIfbmYG9ykwvuxoJ3V8TB5QP+3+ajIA54Y44TmkMxs= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= @@ -341,14 +412,25 @@ github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa h1:s+4MhCQ6YrzisK6 github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw= github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgx/v4 v4.18.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU= github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/k0kubun/pp v2.3.0+incompatible h1:EKhKbi34VQDWJtq+zpsKSEhkHHs9w2P8Izbq8IhLVSo= github.com/k0kubun/pp v2.3.0+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= @@ -357,11 +439,30 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNU github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4= github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= +github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/ktrysmt/go-bitbucket v0.6.4/go.mod h1:9u0v3hsd2rqCHRIpbir1oP7F58uo5dq19sBYvuMoyQ4= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/markbates/pkger v0.15.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mcnijman/go-emailaddress v1.1.1/go.mod h1:5whZrhS8Xp5LxO8zOD35BC+b76kROtsh+dPomeRt/II= github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= github.com/ktrysmt/go-bitbucket v0.6.4 h1:C8dUGp0qkwncKtAnozHCbbqhptefzEd1I0sfnuy9rYQ= github.com/ktrysmt/go-bitbucket v0.6.4/go.mod h1:9u0v3hsd2rqCHRIpbir1oP7F58uo5dq19sBYvuMoyQ4= @@ -378,12 +479,14 @@ github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpsp github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI= github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= github.com/mutecomm/go-sqlcipher/v4 v4.4.0 h1:sV1tWCWGAVlPhNGT95Q+z/txFxuhAYWwHD1afF5bMZg= @@ -398,6 +501,8 @@ github.com/nats-io/nkeys v0.4.6 h1:IzVe95ru2CT6ta874rt9saQRkWfe2nFj1NtvYSLqMzY= github.com/nats-io/nkeys v0.4.6/go.mod h1:4DxZNzenSVd1cYQoAa8948QY3QDjrHfcfVADymtkpts= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= +github.com/neo4j/neo4j-go-driver v1.8.1-0.20200803113522-b626aa943eba/go.mod h1:ncO5VaFWh0Nrt+4KT4mOZboaczBZcLuHrG+/sUeP8gI= github.com/neo4j/neo4j-go-driver v1.8.1-0.20200803113522-b626aa943eba h1:fhFP5RliM2HW/8XdcO5QngSfFli9GcRIpMXvypTQt6E= github.com/neo4j/neo4j-go-driver v1.8.1-0.20200803113522-b626aa943eba/go.mod h1:ncO5VaFWh0Nrt+4KT4mOZboaczBZcLuHrG+/sUeP8gI= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= @@ -405,11 +510,25 @@ github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU= github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pierrec/lz4/v4 v4.1.16 h1:kQPfno+wyx6C5572ABwV+Uo3pDFzQ7yhyGchSyRda0c= github.com/pierrec/lz4/v4 v4.1.16/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/resend/resend-go/v2 v2.6.0/go.mod h1:ihnxc7wPpSgans8RV8d8dIF4hYWVsqMK5KxXAr9LIos= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo= github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk= @@ -424,6 +543,11 @@ github.com/rqlite/gorqlite v0.0.0-20230708021416-2acd02b70b79 h1:V7x0hCAgL8lNGez github.com/rqlite/gorqlite v0.0.0-20230708021416-2acd02b70b79/go.mod h1:xF/KoXmrRyahPfo5L7Szb5cAAUl53dMWBh9cMruGEZg= github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po= github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sagikazarmark/crypt v0.17.0/go.mod h1:SMtHTvdmsZMuY/bpZoqokSoChIrcJ/epOxZN58PbZDg= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/sagikazarmark/crypt v0.17.0 h1:ZA/7pXyjkHoK4bW4mIdnCLvL8hd+Nrbiw7Dqk7D4qUk= github.com/sagikazarmark/crypt v0.17.0/go.mod h1:SMtHTvdmsZMuY/bpZoqokSoChIrcJ/epOxZN58PbZDg= @@ -437,6 +561,33 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5I github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= +github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60= +github.com/snowflakedb/gosnowflake v1.6.19/go.mod h1:FM1+PWUdwB9udFDsXdfD58NONC0m+MlOSmQRvimobSM= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/swaggo/files/v2 v2.0.0/go.mod h1:24kk2Y9NYEJ5lHuCra6iVwkMjIekMCaFq/0JQj66kyM= +github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk= +github.com/tinylib/msgp v1.1.9/go.mod h1:BCXGB54lDD8qUEPmiG0cQQUANC4IUQyB2ItS2UDlO/k= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.52.0/go.mod h1:hf5C4QnVMkNXMspnsUlfM3WitlgYflyhHYoKol/szxQ= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/snowflakedb/gosnowflake v1.6.19 h1:KSHXrQ5o7uso25hNIzi/RObXtnSGkFgie91X82KcvMY= github.com/snowflakedb/gosnowflake v1.6.19/go.mod h1:FM1+PWUdwB9udFDsXdfD58NONC0m+MlOSmQRvimobSM= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= @@ -459,13 +610,11 @@ github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCO github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= -github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b h1:7gd+rd8P3bqcn/96gOZa3F5dpJr/vEiDQYlNb/y2uNs= gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE= -go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k= go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI= go.etcd.io/etcd/client/pkg/v3 v3.5.10 h1:kfYIdQftBnbAq8pUWFXfpuuxFSKzlmM5cSn76JByiT0= go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U= @@ -483,43 +632,35 @@ go.mongodb.org/mongo-driver v1.7.5 h1:ny3p0reEpgsR2cfA5cjgwFZg3Cv/ofFh/8jbhGtz9V go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib v1.17.0/go.mod h1:gIzjwWFoGazJmtCaDgViqOSJPde2mCWzv60o0bWPcZs= +go.opentelemetry.io/contrib/propagators/b3 v1.17.0/go.mod h1:IkfUfMpKWmynvvE0264trz0sf32NRTZL4nuAN9AbWRc= +go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.26.0/go.mod h1:zVZ8nz+VSggWmnh6tTsJqXQ7rU4xLwRtna1M4x5jq58= +go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4= +go.opentelemetry.io/otel/oteltest v1.0.0-RC3/go.mod h1:xpzajI9JBRr7gX63nO6kAmImmYIAtuQblZ36Z+LfCjE= +go.opentelemetry.io/otel/sdk v1.26.0/go.mod h1:0p8MXpqLeJ0pzcszQQN4F0S5FVjBLgypeGSngLsmirs= +go.opentelemetry.io/otel/sdk/metric v0.39.0/go.mod h1:piDIRgjcK7u0HCL5pCA4e74qpK/jk3NiUoAHATVAmiI= +go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= -golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= -golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= -golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= @@ -556,21 +697,9 @@ golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= -golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750= google.golang.org/api v0.149.0/go.mod h1:Mwn1B7JTXrzXtnvmzQE2BD6bYZQ8DShKZDZbeN9I7qI= @@ -580,6 +709,13 @@ google.golang.org/api v0.153.0 h1:N1AwGhielyKFaUqH07/ZSIQR3uNPcV7NVw0vj+j4iR4= google.golang.org/api v0.153.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= +google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI= google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405/go.mod h1:3WDQMjmJk36UQhjQ89emUzb1mdaHcPeeAh4SCBKznB4= @@ -606,10 +742,13 @@ google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGm google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/postgres v1.5.4 h1:Iyrp9Meh3GmbSuyIAGyjkN+n9K+GHX9b9MqsTL4EJCo= -gorm.io/driver/postgres v1.5.4/go.mod h1:Bgo89+h0CRcdA33Y6frlaHHVuTdOf87pmyzwW9C/BH0= -lukechampine.com/frand v1.4.2 h1:RzFIpOvkMXuPMBb9maa4ND4wjBn71E1Jpf8BzJHMaVw= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/postgres v1.5.7/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA= +gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= lukechampine.com/frand v1.4.2/go.mod h1:4S/TM2ZgrKejMcKMbeLjISpJMO+/eZ1zu3vYX9dtj3s= lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=