feat: registrationBegin method without email;
fix: missing sqlc query parameter name; feat: util for generating security codes; feat: enums package
This commit is contained in:
@@ -12,11 +12,11 @@ type BannedUser struct {
|
|||||||
ID int64
|
ID int64
|
||||||
UserID int64
|
UserID int64
|
||||||
Date pgtype.Timestamp
|
Date pgtype.Timestamp
|
||||||
Reason pgtype.Text
|
Reason *string
|
||||||
ExpiresAt pgtype.Timestamp
|
ExpiresAt pgtype.Timestamp
|
||||||
BannedBy pgtype.Text
|
BannedBy *string
|
||||||
Pardoned pgtype.Bool
|
Pardoned *bool
|
||||||
PardonedBy pgtype.Text
|
PardonedBy *string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfirmationCode struct {
|
type ConfirmationCode struct {
|
||||||
@@ -25,17 +25,17 @@ type ConfirmationCode struct {
|
|||||||
CodeType int32
|
CodeType int32
|
||||||
CodeHash string
|
CodeHash string
|
||||||
ExpiresAt pgtype.Timestamp
|
ExpiresAt pgtype.Timestamp
|
||||||
Used pgtype.Bool
|
Used *bool
|
||||||
Deleted pgtype.Bool
|
Deleted *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type LoginInformation struct {
|
type LoginInformation struct {
|
||||||
ID int64
|
ID int64
|
||||||
UserID int64
|
UserID int64
|
||||||
Email pgtype.Text
|
Email *string
|
||||||
PasswordHash string
|
PasswordHash string
|
||||||
TotpEncrypted pgtype.Text
|
TotpEncrypted *string
|
||||||
Email2faEnabled pgtype.Bool
|
Email2faEnabled *bool
|
||||||
PasswordChangeDate pgtype.Timestamp
|
PasswordChangeDate pgtype.Timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,41 +43,41 @@ type Profile struct {
|
|||||||
ID int64
|
ID int64
|
||||||
UserID int64
|
UserID int64
|
||||||
Name string
|
Name string
|
||||||
Bio pgtype.Text
|
Bio *string
|
||||||
AvatarUrl pgtype.Text
|
AvatarUrl *string
|
||||||
Birthday pgtype.Timestamp
|
Birthday pgtype.Timestamp
|
||||||
Color pgtype.Text
|
Color *string
|
||||||
ColorGrad pgtype.Text
|
ColorGrad *string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProfileSetting struct {
|
type ProfileSetting struct {
|
||||||
ID int64
|
ID int64
|
||||||
ProfileID int64
|
ProfileID int64
|
||||||
HideFulfilled pgtype.Bool
|
HideFulfilled *bool
|
||||||
HideProfileDetails pgtype.Bool
|
HideProfileDetails *bool
|
||||||
HideForUnauthenticated pgtype.Bool
|
HideForUnauthenticated *bool
|
||||||
HideBirthday pgtype.Bool
|
HideBirthday *bool
|
||||||
HideDates pgtype.Bool
|
HideDates *bool
|
||||||
Captcha pgtype.Bool
|
Captcha *bool
|
||||||
FollowersOnlyInteraction pgtype.Bool
|
FollowersOnlyInteraction *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Session struct {
|
type Session struct {
|
||||||
ID int64
|
ID int64
|
||||||
UserID int64
|
UserID int64
|
||||||
Guid pgtype.UUID
|
Guid pgtype.UUID
|
||||||
Name pgtype.Text
|
Name *string
|
||||||
Platform pgtype.Text
|
Platform *string
|
||||||
LatestIp pgtype.Text
|
LatestIp *string
|
||||||
LoginTime pgtype.Timestamp
|
LoginTime pgtype.Timestamp
|
||||||
LastSeenDate pgtype.Timestamp
|
LastSeenDate pgtype.Timestamp
|
||||||
Terminated pgtype.Bool
|
Terminated *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
ID int64
|
ID int64
|
||||||
Username string
|
Username string
|
||||||
Verified pgtype.Bool
|
Verified *bool
|
||||||
RegistrationDate pgtype.Timestamp
|
RegistrationDate pgtype.Timestamp
|
||||||
Deleted pgtype.Bool
|
Deleted *bool
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ VALUES ( $1, $2, $3, $4) RETURNING id, user_id, date, reason, expires_at, banned
|
|||||||
type CreateBannedUserParams struct {
|
type CreateBannedUserParams struct {
|
||||||
UserID int64
|
UserID int64
|
||||||
ExpiresAt pgtype.Timestamp
|
ExpiresAt pgtype.Timestamp
|
||||||
Reason pgtype.Text
|
Reason *string
|
||||||
BannedBy pgtype.Text
|
BannedBy *string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateBannedUser(ctx context.Context, arg CreateBannedUserParams) (BannedUser, error) {
|
func (q *Queries) CreateBannedUser(ctx context.Context, arg CreateBannedUserParams) (BannedUser, error) {
|
||||||
@@ -45,24 +45,18 @@ func (q *Queries) CreateBannedUser(ctx context.Context, arg CreateBannedUserPara
|
|||||||
}
|
}
|
||||||
|
|
||||||
const createConfirmationCode = `-- name: CreateConfirmationCode :one
|
const createConfirmationCode = `-- name: CreateConfirmationCode :one
|
||||||
INSERT INTO confirmation_codes(user_id, code_type, code_hash, expires_at)
|
INSERT INTO confirmation_codes(user_id, code_type, code_hash)
|
||||||
VALUES ($1, $2, crypt($3, gen_salt('bf')), $4) RETURNING id, user_id, code_type, code_hash, expires_at, used, deleted
|
VALUES ($1, $2, crypt($3::text, gen_salt('bf'))) RETURNING id, user_id, code_type, code_hash, expires_at, used, deleted
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateConfirmationCodeParams struct {
|
type CreateConfirmationCodeParams struct {
|
||||||
UserID int64
|
UserID int64
|
||||||
CodeType int32
|
CodeType int32
|
||||||
Crypt string
|
Code string
|
||||||
ExpiresAt pgtype.Timestamp
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateConfirmationCode(ctx context.Context, arg CreateConfirmationCodeParams) (ConfirmationCode, error) {
|
func (q *Queries) CreateConfirmationCode(ctx context.Context, arg CreateConfirmationCodeParams) (ConfirmationCode, error) {
|
||||||
row := q.db.QueryRow(ctx, createConfirmationCode,
|
row := q.db.QueryRow(ctx, createConfirmationCode, arg.UserID, arg.CodeType, arg.Code)
|
||||||
arg.UserID,
|
|
||||||
arg.CodeType,
|
|
||||||
arg.Crypt,
|
|
||||||
arg.ExpiresAt,
|
|
||||||
)
|
|
||||||
var i ConfirmationCode
|
var i ConfirmationCode
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
@@ -83,7 +77,7 @@ VALUES ( $1, $2, crypt($3::text, gen_salt('bf')) ) RETURNING id, user_id, email,
|
|||||||
|
|
||||||
type CreateLoginInformationParams struct {
|
type CreateLoginInformationParams struct {
|
||||||
UserID int64
|
UserID int64
|
||||||
Email pgtype.Text
|
Email *string
|
||||||
Password string
|
Password string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,11 +104,11 @@ VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING id, user_id, name, bio, avatar_url
|
|||||||
type CreateProfileParams struct {
|
type CreateProfileParams struct {
|
||||||
UserID int64
|
UserID int64
|
||||||
Name string
|
Name string
|
||||||
Bio pgtype.Text
|
Bio *string
|
||||||
Birthday pgtype.Timestamp
|
Birthday pgtype.Timestamp
|
||||||
AvatarUrl pgtype.Text
|
AvatarUrl *string
|
||||||
Color pgtype.Text
|
Color *string
|
||||||
ColorGrad pgtype.Text
|
ColorGrad *string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateProfile(ctx context.Context, arg CreateProfileParams) (Profile, error) {
|
func (q *Queries) CreateProfile(ctx context.Context, arg CreateProfileParams) (Profile, error) {
|
||||||
@@ -170,9 +164,9 @@ VALUES ($1, $2, $3, $4) RETURNING id, user_id, guid, name, platform, latest_ip,
|
|||||||
|
|
||||||
type CreateSessionParams struct {
|
type CreateSessionParams struct {
|
||||||
UserID int64
|
UserID int64
|
||||||
Name pgtype.Text
|
Name *string
|
||||||
Platform pgtype.Text
|
Platform *string
|
||||||
LatestIp pgtype.Text
|
LatestIp *string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateSession(ctx context.Context, arg CreateSessionParams) (Session, error) {
|
func (q *Queries) CreateSession(ctx context.Context, arg CreateSessionParams) (Session, error) {
|
||||||
@@ -331,18 +325,18 @@ WHERE users.username = $1 AND ($2 IS FALSE OR profile_settings.hide_for_unauthen
|
|||||||
|
|
||||||
type GetProfileByUsernameRestrictedParams struct {
|
type GetProfileByUsernameRestrictedParams struct {
|
||||||
Username string
|
Username string
|
||||||
Column2 pgtype.Bool
|
Column2 *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetProfileByUsernameRestrictedRow struct {
|
type GetProfileByUsernameRestrictedRow struct {
|
||||||
Username string
|
Username string
|
||||||
Name string
|
Name string
|
||||||
Birthday pgtype.Timestamp
|
Birthday pgtype.Timestamp
|
||||||
Bio pgtype.Text
|
Bio *string
|
||||||
AvatarUrl pgtype.Text
|
AvatarUrl *string
|
||||||
Color pgtype.Text
|
Color *string
|
||||||
ColorGrad pgtype.Text
|
ColorGrad *string
|
||||||
HideProfileDetails pgtype.Bool
|
HideProfileDetails *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetProfileByUsernameRestricted(ctx context.Context, arg GetProfileByUsernameRestrictedParams) (GetProfileByUsernameRestrictedRow, error) {
|
func (q *Queries) GetProfileByUsernameRestricted(ctx context.Context, arg GetProfileByUsernameRestrictedParams) (GetProfileByUsernameRestrictedRow, error) {
|
||||||
@@ -405,17 +399,17 @@ LIMIT 20 OFFSET 20 * $1
|
|||||||
`
|
`
|
||||||
|
|
||||||
type GetProfilesRestrictedParams struct {
|
type GetProfilesRestrictedParams struct {
|
||||||
Column1 pgtype.Int4
|
Column1 *int32
|
||||||
Column2 pgtype.Bool
|
Column2 *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetProfilesRestrictedRow struct {
|
type GetProfilesRestrictedRow struct {
|
||||||
Username string
|
Username string
|
||||||
Name string
|
Name string
|
||||||
AvatarUrl pgtype.Text
|
AvatarUrl *string
|
||||||
Color pgtype.Text
|
Color *string
|
||||||
ColorGrad pgtype.Text
|
ColorGrad *string
|
||||||
HideProfileDetails pgtype.Bool
|
HideProfileDetails *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetProfilesRestricted(ctx context.Context, arg GetProfilesRestrictedParams) ([]GetProfilesRestrictedRow, error) {
|
func (q *Queries) GetProfilesRestricted(ctx context.Context, arg GetProfilesRestrictedParams) ([]GetProfilesRestrictedRow, error) {
|
||||||
@@ -558,7 +552,7 @@ type GetUserByLoginCredentialsRow struct {
|
|||||||
ID int64
|
ID int64
|
||||||
Username string
|
Username string
|
||||||
PasswordHash string
|
PasswordHash string
|
||||||
TotpEncrypted pgtype.Text
|
TotpEncrypted *string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetUserByLoginCredentials(ctx context.Context, arg GetUserByLoginCredentialsParams) (GetUserByLoginCredentialsRow, error) {
|
func (q *Queries) GetUserByLoginCredentials(ctx context.Context, arg GetUserByLoginCredentialsParams) (GetUserByLoginCredentialsRow, error) {
|
||||||
@@ -654,11 +648,11 @@ WHERE id = $1
|
|||||||
|
|
||||||
type UpdateBannedUserParams struct {
|
type UpdateBannedUserParams struct {
|
||||||
ID int64
|
ID int64
|
||||||
Reason pgtype.Text
|
Reason *string
|
||||||
ExpiresAt pgtype.Timestamp
|
ExpiresAt pgtype.Timestamp
|
||||||
BannedBy pgtype.Text
|
BannedBy *string
|
||||||
Pardoned pgtype.Bool
|
Pardoned *bool
|
||||||
PardonedBy pgtype.Text
|
PardonedBy *string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateBannedUser(ctx context.Context, arg UpdateBannedUserParams) error {
|
func (q *Queries) UpdateBannedUser(ctx context.Context, arg UpdateBannedUserParams) error {
|
||||||
@@ -681,8 +675,8 @@ WHERE id = $1
|
|||||||
|
|
||||||
type UpdateConfirmationCodeParams struct {
|
type UpdateConfirmationCodeParams struct {
|
||||||
ID int64
|
ID int64
|
||||||
Used pgtype.Bool
|
Used *bool
|
||||||
Deleted pgtype.Bool
|
Deleted *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateConfirmationCode(ctx context.Context, arg UpdateConfirmationCodeParams) error {
|
func (q *Queries) UpdateConfirmationCode(ctx context.Context, arg UpdateConfirmationCodeParams) error {
|
||||||
@@ -699,10 +693,10 @@ WHERE users.username = $1 AND login_informations.user_id = users.id
|
|||||||
|
|
||||||
type UpdateLoginInformationByUsernameParams struct {
|
type UpdateLoginInformationByUsernameParams struct {
|
||||||
Username string
|
Username string
|
||||||
Email pgtype.Text
|
Email *string
|
||||||
Password string
|
Password string
|
||||||
TotpEncrypted pgtype.Text
|
TotpEncrypted *string
|
||||||
Email2faEnabled pgtype.Bool
|
Email2faEnabled *bool
|
||||||
PasswordChangeDate pgtype.Timestamp
|
PasswordChangeDate pgtype.Timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -728,11 +722,11 @@ WHERE username = $1
|
|||||||
type UpdateProfileByUsernameParams struct {
|
type UpdateProfileByUsernameParams struct {
|
||||||
Username string
|
Username string
|
||||||
Name string
|
Name string
|
||||||
Bio pgtype.Text
|
Bio *string
|
||||||
Birthday pgtype.Timestamp
|
Birthday pgtype.Timestamp
|
||||||
AvatarUrl pgtype.Text
|
AvatarUrl *string
|
||||||
Color pgtype.Text
|
Color *string
|
||||||
ColorGrad pgtype.Text
|
ColorGrad *string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateProfileByUsername(ctx context.Context, arg UpdateProfileByUsernameParams) error {
|
func (q *Queries) UpdateProfileByUsername(ctx context.Context, arg UpdateProfileByUsernameParams) error {
|
||||||
@@ -763,13 +757,13 @@ WHERE id = $1
|
|||||||
|
|
||||||
type UpdateProfileSettingsParams struct {
|
type UpdateProfileSettingsParams struct {
|
||||||
ID int64
|
ID int64
|
||||||
HideFulfilled pgtype.Bool
|
HideFulfilled *bool
|
||||||
HideProfileDetails pgtype.Bool
|
HideProfileDetails *bool
|
||||||
HideForUnauthenticated pgtype.Bool
|
HideForUnauthenticated *bool
|
||||||
HideBirthday pgtype.Bool
|
HideBirthday *bool
|
||||||
HideDates pgtype.Bool
|
HideDates *bool
|
||||||
Captcha pgtype.Bool
|
Captcha *bool
|
||||||
FollowersOnlyInteraction pgtype.Bool
|
FollowersOnlyInteraction *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateProfileSettings(ctx context.Context, arg UpdateProfileSettingsParams) error {
|
func (q *Queries) UpdateProfileSettings(ctx context.Context, arg UpdateProfileSettingsParams) error {
|
||||||
@@ -794,12 +788,12 @@ WHERE id = $1
|
|||||||
|
|
||||||
type UpdateSessionParams struct {
|
type UpdateSessionParams struct {
|
||||||
ID int64
|
ID int64
|
||||||
Name pgtype.Text
|
Name *string
|
||||||
Platform pgtype.Text
|
Platform *string
|
||||||
LatestIp pgtype.Text
|
LatestIp *string
|
||||||
LoginTime pgtype.Timestamp
|
LoginTime pgtype.Timestamp
|
||||||
LastSeenDate pgtype.Timestamp
|
LastSeenDate pgtype.Timestamp
|
||||||
Terminated pgtype.Bool
|
Terminated *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateSession(ctx context.Context, arg UpdateSessionParams) error {
|
func (q *Queries) UpdateSession(ctx context.Context, arg UpdateSessionParams) error {
|
||||||
@@ -823,8 +817,8 @@ WHERE id = $1
|
|||||||
|
|
||||||
type UpdateUserParams struct {
|
type UpdateUserParams struct {
|
||||||
ID int64
|
ID int64
|
||||||
Verified pgtype.Bool
|
Verified *bool
|
||||||
Deleted pgtype.Bool
|
Deleted *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) error {
|
func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) error {
|
||||||
@@ -840,8 +834,8 @@ WHERE username = $1
|
|||||||
|
|
||||||
type UpdateUserByUsernameParams struct {
|
type UpdateUserByUsernameParams struct {
|
||||||
Username string
|
Username string
|
||||||
Verified pgtype.Bool
|
Verified *bool
|
||||||
Deleted pgtype.Bool
|
Deleted *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateUserByUsername(ctx context.Context, arg UpdateUserByUsernameParams) error {
|
func (q *Queries) UpdateUserByUsername(ctx context.Context, arg UpdateUserByUsernameParams) error {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
errs "easywish/internal/errors"
|
errs "easywish/internal/errors"
|
||||||
"easywish/internal/models"
|
"easywish/internal/models"
|
||||||
"easywish/internal/utils"
|
"easywish/internal/utils"
|
||||||
|
"easywish/internal/utils/enums"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
@@ -27,18 +28,50 @@ func NewAuthService(_log *zap.Logger, _dbctx database.DbContext) AuthService {
|
|||||||
|
|
||||||
func (a *authServiceImpl) RegistrationBegin(request models.RegistrationBeginRequest) (bool, error) {
|
func (a *authServiceImpl) RegistrationBegin(request models.RegistrationBeginRequest) (bool, error) {
|
||||||
|
|
||||||
|
var user database.User
|
||||||
|
var generatedCode string
|
||||||
|
|
||||||
helper, db, _ := database.NewDbHelperTransaction(a.dbctx)
|
helper, db, _ := database.NewDbHelperTransaction(a.dbctx)
|
||||||
|
defer helper.Rollback()
|
||||||
|
|
||||||
user, err := db.TXQueries.CreateUser(db.CTX, request.Username) // TODO: validation
|
var err error
|
||||||
|
|
||||||
if err != nil {
|
if user, err = db.TXQueries.CreateUser(db.CTX, request.Username); err != nil { // TODO: validation
|
||||||
a.log.Error("Failed to add user to database", zap.Error(err))
|
a.log.Error("Failed to add user to database", zap.Error(err))
|
||||||
return false, errs.ErrServerError
|
return false, errs.ErrServerError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.log.Info("Registraion of a new user", zap.String("username", user.Username), zap.Int64("id", user.ID))
|
||||||
|
|
||||||
|
if _, err = db.TXQueries.CreateLoginInformation(db.CTX, database.CreateLoginInformationParams{
|
||||||
|
UserID: user.ID,
|
||||||
|
Email: request.Email,
|
||||||
|
Password: request.Password, // Hashed in database
|
||||||
|
}); err != nil {
|
||||||
|
a.log.Error("Failed to add login information for user to database", zap.Error(err))
|
||||||
|
return false, errs.ErrServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
if generatedCode, err = utils.GenerateSecure6DigitNumber(); err != nil {
|
||||||
|
a.log.Error("Failed to generate a registration code", zap.Error(err))
|
||||||
|
return false, errs.ErrServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = db.TXQueries.CreateConfirmationCode(db.CTX, database.CreateConfirmationCodeParams{
|
||||||
|
UserID: user.ID,
|
||||||
|
CodeType: int32(enums.RegistrationCodeType),
|
||||||
|
Code: generatedCode, // Hashed in database
|
||||||
|
}); err != nil {
|
||||||
|
a.log.Error("Failed to add registration code to database", zap.Error(err))
|
||||||
|
return false, errs.ErrServerError
|
||||||
|
}
|
||||||
|
|
||||||
a.log.Info("Registered a new user", zap.String("username", user.Username))
|
a.log.Info("Registered a new user", zap.String("username", user.Username))
|
||||||
|
|
||||||
helper.Commit()
|
helper.Commit()
|
||||||
|
|
||||||
|
a.log.Debug("Declated registration code for a new user", zap.String("username", user.Username), zap.String("code", generatedCode))
|
||||||
|
|
||||||
// TODO: Send verification email
|
// TODO: Send verification email
|
||||||
|
|
||||||
return true, nil
|
return true, nil
|
||||||
|
|||||||
8
backend/internal/utils/enums/enums.go
Normal file
8
backend/internal/utils/enums/enums.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package enums
|
||||||
|
|
||||||
|
type ConfirmationCodeType int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
RegistrationCodeType ConfirmationCodeType = iota
|
||||||
|
PasswordResetCodeType
|
||||||
|
)
|
||||||
26
backend/internal/utils/securityCode.go
Normal file
26
backend/internal/utils/securityCode.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GenerateSecure6DigitNumber() (string, error) {
|
||||||
|
// Generate a random number between 0 and 999999 (inclusive)
|
||||||
|
// This ensures we get a 6-digit number, including those starting with 0
|
||||||
|
max := 1000000 // Upper bound (exclusive)
|
||||||
|
b := make([]byte, 4) // A 4-byte slice is sufficient for a 32-bit integer
|
||||||
|
|
||||||
|
if _, err := io.ReadFull(rand.Reader, b); err != nil {
|
||||||
|
return "", fmt.Errorf("failed to read random bytes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert bytes to an integer
|
||||||
|
// We use a simple modulo operation to get a number within our desired range.
|
||||||
|
// While this introduces a slight bias for very large ranges, for 1,000,000
|
||||||
|
// it's negligible and simpler than more complex methods like rejection sampling.
|
||||||
|
num := int(uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])) % max
|
||||||
|
|
||||||
|
return fmt.Sprintf("%06d", num), nil
|
||||||
|
}
|
||||||
@@ -94,8 +94,8 @@ WHERE users.username = $1;
|
|||||||
--: Confirmation Code Object {{{
|
--: Confirmation Code Object {{{
|
||||||
|
|
||||||
;-- name: CreateConfirmationCode :one
|
;-- name: CreateConfirmationCode :one
|
||||||
INSERT INTO confirmation_codes(user_id, code_type, code_hash, expires_at)
|
INSERT INTO confirmation_codes(user_id, code_type, code_hash)
|
||||||
VALUES ($1, $2, crypt($3, gen_salt('bf')), $4) RETURNING *;
|
VALUES ($1, $2, crypt(@code::text, gen_salt('bf'))) RETURNING *;
|
||||||
|
|
||||||
;-- name: GetConfirmationCodeByCode :one
|
;-- name: GetConfirmationCodeByCode :one
|
||||||
SELECT * FROM confirmation_codes
|
SELECT * FROM confirmation_codes
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ sql:
|
|||||||
out: "../backend/internal/database"
|
out: "../backend/internal/database"
|
||||||
sql_package: "pgx/v5"
|
sql_package: "pgx/v5"
|
||||||
emit_prepared_queries: true
|
emit_prepared_queries: true
|
||||||
emit_interface: false
|
emit_pointers_for_null_types: true
|
||||||
database:
|
database:
|
||||||
# managed: true
|
# managed: true
|
||||||
uri: "postgresql://postgres:postgres@localhost:5432/postgres?sslmode=disable"
|
uri: "postgresql://postgres:postgres@localhost:5432/postgres?sslmode=disable"
|
||||||
|
|||||||
Reference in New Issue
Block a user