Add the ability to set passwords on registration
This commit is contained in:
parent
ebb55556d2
commit
334deb1ae7
12 changed files with 485 additions and 26 deletions
|
|
@ -105,6 +105,24 @@ var Users = Table[
|
|||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
PasswordHashType: column{
|
||||
Name: "password_hash_type",
|
||||
DBType: "public.hashtype",
|
||||
Default: "NULL",
|
||||
Comment: "",
|
||||
Nullable: true,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
PasswordHash: column{
|
||||
Name: "password_hash",
|
||||
DBType: "text",
|
||||
Default: "NULL",
|
||||
Comment: "",
|
||||
Nullable: true,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
},
|
||||
Indexes: userIndexes{
|
||||
UserPkey: index{
|
||||
|
|
@ -156,11 +174,13 @@ type userColumns struct {
|
|||
Email column
|
||||
OrganizationID column
|
||||
Username column
|
||||
PasswordHashType column
|
||||
PasswordHash column
|
||||
}
|
||||
|
||||
func (c userColumns) AsSlice() []column {
|
||||
return []column{
|
||||
c.ID, c.ArcgisAccessToken, c.ArcgisLicense, c.ArcgisRefreshToken, c.ArcgisRefreshTokenExpires, c.ArcgisRole, c.DisplayName, c.Email, c.OrganizationID, c.Username,
|
||||
c.ID, c.ArcgisAccessToken, c.ArcgisLicense, c.ArcgisRefreshToken, c.ArcgisRefreshTokenExpires, c.ArcgisRole, c.DisplayName, c.Email, c.OrganizationID, c.Username, c.PasswordHashType, c.PasswordHash,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
28
endpoint.go
28
endpoint.go
|
|
@ -1,7 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
)
|
||||
func getFavicon(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -23,18 +23,36 @@ func getSignup(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
func respondError(w http.ResponseWriter, m string, e error, s int) {
|
||||
slog.Error(m, slog.Int("status", s), slog.String("err", e.Error()))
|
||||
http.Error(w, m, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
func postSignup(w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
log.Printf("Error parsing form: %v", err)
|
||||
http.Error(w, "Failed to process form", http.StatusBadRequest)
|
||||
respondError(w, "Could not parse form", err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
email := r.FormValue("email")
|
||||
username := r.FormValue("username")
|
||||
name := r.FormValue("name")
|
||||
password := r.FormValue("password")
|
||||
terms := r.FormValue("terms")
|
||||
|
||||
log.Printf("Signup - Email: %s, Name: %s, Terms: %s", email, name, terms)
|
||||
slog.Info("Signup",
|
||||
slog.String("username", username),
|
||||
slog.String("name", name))
|
||||
|
||||
if terms != "on" {
|
||||
slog.Error("Terms not agreed", slog.String("terms", terms))
|
||||
http.Error(w, "You must agree to the terms to register", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if err := signupUser(username, name, password); err != nil {
|
||||
respondError(w, "Failed to signup user", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("Form received"))
|
||||
|
|
|
|||
|
|
@ -116,3 +116,73 @@ func (e *ArcgisLicenseType) Scan(value any) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Enum values for Hashtype
|
||||
const (
|
||||
HashtypeBcrypt14 Hashtype = "bcrypt-14"
|
||||
)
|
||||
|
||||
func AllHashtype() []Hashtype {
|
||||
return []Hashtype{
|
||||
HashtypeBcrypt14,
|
||||
}
|
||||
}
|
||||
|
||||
type Hashtype string
|
||||
|
||||
func (e Hashtype) String() string {
|
||||
return string(e)
|
||||
}
|
||||
|
||||
func (e Hashtype) Valid() bool {
|
||||
switch e {
|
||||
case HashtypeBcrypt14:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// useful when testing in other packages
|
||||
func (e Hashtype) All() []Hashtype {
|
||||
return AllHashtype()
|
||||
}
|
||||
|
||||
func (e Hashtype) MarshalText() ([]byte, error) {
|
||||
return []byte(e), nil
|
||||
}
|
||||
|
||||
func (e *Hashtype) UnmarshalText(text []byte) error {
|
||||
return e.Scan(text)
|
||||
}
|
||||
|
||||
func (e Hashtype) MarshalBinary() ([]byte, error) {
|
||||
return []byte(e), nil
|
||||
}
|
||||
|
||||
func (e *Hashtype) UnmarshalBinary(data []byte) error {
|
||||
return e.Scan(data)
|
||||
}
|
||||
|
||||
func (e Hashtype) Value() (driver.Value, error) {
|
||||
return string(e), nil
|
||||
}
|
||||
|
||||
func (e *Hashtype) Scan(value any) error {
|
||||
switch x := value.(type) {
|
||||
case string:
|
||||
*e = Hashtype(x)
|
||||
case []byte:
|
||||
*e = Hashtype(x)
|
||||
case nil:
|
||||
return fmt.Errorf("cannot nil into Hashtype")
|
||||
default:
|
||||
return fmt.Errorf("cannot scan type %T: %v", value, value)
|
||||
}
|
||||
|
||||
if !e.Valid() {
|
||||
return fmt.Errorf("invalid Hashtype value: %s", *e)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,6 +108,8 @@ func (f *Factory) FromExistingUser(m *models.User) *UserTemplate {
|
|||
o.Email = func() null.Val[string] { return m.Email }
|
||||
o.OrganizationID = func() null.Val[int32] { return m.OrganizationID }
|
||||
o.Username = func() string { return m.Username }
|
||||
o.PasswordHashType = func() null.Val[enums.Hashtype] { return m.PasswordHashType }
|
||||
o.PasswordHash = func() null.Val[string] { return m.PasswordHash }
|
||||
|
||||
ctx := context.Background()
|
||||
if m.R.Organization != nil {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,16 @@ func random_enums_ArcgisLicenseType(f *faker.Faker, limits ...string) enums.Arcg
|
|||
return all[f.IntBetween(0, len(all)-1)]
|
||||
}
|
||||
|
||||
func random_enums_Hashtype(f *faker.Faker, limits ...string) enums.Hashtype {
|
||||
if f == nil {
|
||||
f = &defaultFaker
|
||||
}
|
||||
|
||||
var e enums.Hashtype
|
||||
all := e.All()
|
||||
return all[f.IntBetween(0, len(all)-1)]
|
||||
}
|
||||
|
||||
func random_int32(f *faker.Faker, limits ...string) int32 {
|
||||
if f == nil {
|
||||
f = &defaultFaker
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ type UserTemplate struct {
|
|||
Email func() null.Val[string]
|
||||
OrganizationID func() null.Val[int32]
|
||||
Username func() string
|
||||
PasswordHashType func() null.Val[enums.Hashtype]
|
||||
PasswordHash func() null.Val[string]
|
||||
|
||||
r userR
|
||||
f *Factory
|
||||
|
|
@ -126,6 +128,14 @@ func (o UserTemplate) BuildSetter() *models.UserSetter {
|
|||
val := o.Username()
|
||||
m.Username = omit.From(val)
|
||||
}
|
||||
if o.PasswordHashType != nil {
|
||||
val := o.PasswordHashType()
|
||||
m.PasswordHashType = omitnull.FromNull(val)
|
||||
}
|
||||
if o.PasswordHash != nil {
|
||||
val := o.PasswordHash()
|
||||
m.PasswordHash = omitnull.FromNull(val)
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
|
@ -178,6 +188,12 @@ func (o UserTemplate) Build() *models.User {
|
|||
if o.Username != nil {
|
||||
m.Username = o.Username()
|
||||
}
|
||||
if o.PasswordHashType != nil {
|
||||
m.PasswordHashType = o.PasswordHashType()
|
||||
}
|
||||
if o.PasswordHash != nil {
|
||||
m.PasswordHash = o.PasswordHash()
|
||||
}
|
||||
|
||||
o.setModelRels(m)
|
||||
|
||||
|
|
@ -331,6 +347,8 @@ func (m userMods) RandomizeAllColumns(f *faker.Faker) UserMod {
|
|||
UserMods.RandomEmail(f),
|
||||
UserMods.RandomOrganizationID(f),
|
||||
UserMods.RandomUsername(f),
|
||||
UserMods.RandomPasswordHashType(f),
|
||||
UserMods.RandomPasswordHash(f),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -820,6 +838,112 @@ func (m userMods) RandomUsername(f *faker.Faker) UserMod {
|
|||
})
|
||||
}
|
||||
|
||||
// Set the model columns to this value
|
||||
func (m userMods) PasswordHashType(val null.Val[enums.Hashtype]) UserMod {
|
||||
return UserModFunc(func(_ context.Context, o *UserTemplate) {
|
||||
o.PasswordHashType = func() null.Val[enums.Hashtype] { return val }
|
||||
})
|
||||
}
|
||||
|
||||
// Set the Column from the function
|
||||
func (m userMods) PasswordHashTypeFunc(f func() null.Val[enums.Hashtype]) UserMod {
|
||||
return UserModFunc(func(_ context.Context, o *UserTemplate) {
|
||||
o.PasswordHashType = f
|
||||
})
|
||||
}
|
||||
|
||||
// Clear any values for the column
|
||||
func (m userMods) UnsetPasswordHashType() UserMod {
|
||||
return UserModFunc(func(_ context.Context, o *UserTemplate) {
|
||||
o.PasswordHashType = nil
|
||||
})
|
||||
}
|
||||
|
||||
// Generates a random value for the column using the given faker
|
||||
// if faker is nil, a default faker is used
|
||||
// The generated value is sometimes null
|
||||
func (m userMods) RandomPasswordHashType(f *faker.Faker) UserMod {
|
||||
return UserModFunc(func(_ context.Context, o *UserTemplate) {
|
||||
o.PasswordHashType = func() null.Val[enums.Hashtype] {
|
||||
if f == nil {
|
||||
f = &defaultFaker
|
||||
}
|
||||
|
||||
val := random_enums_Hashtype(f)
|
||||
return null.From(val)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Generates a random value for the column using the given faker
|
||||
// if faker is nil, a default faker is used
|
||||
// The generated value is never null
|
||||
func (m userMods) RandomPasswordHashTypeNotNull(f *faker.Faker) UserMod {
|
||||
return UserModFunc(func(_ context.Context, o *UserTemplate) {
|
||||
o.PasswordHashType = func() null.Val[enums.Hashtype] {
|
||||
if f == nil {
|
||||
f = &defaultFaker
|
||||
}
|
||||
|
||||
val := random_enums_Hashtype(f)
|
||||
return null.From(val)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Set the model columns to this value
|
||||
func (m userMods) PasswordHash(val null.Val[string]) UserMod {
|
||||
return UserModFunc(func(_ context.Context, o *UserTemplate) {
|
||||
o.PasswordHash = func() null.Val[string] { return val }
|
||||
})
|
||||
}
|
||||
|
||||
// Set the Column from the function
|
||||
func (m userMods) PasswordHashFunc(f func() null.Val[string]) UserMod {
|
||||
return UserModFunc(func(_ context.Context, o *UserTemplate) {
|
||||
o.PasswordHash = f
|
||||
})
|
||||
}
|
||||
|
||||
// Clear any values for the column
|
||||
func (m userMods) UnsetPasswordHash() UserMod {
|
||||
return UserModFunc(func(_ context.Context, o *UserTemplate) {
|
||||
o.PasswordHash = nil
|
||||
})
|
||||
}
|
||||
|
||||
// Generates a random value for the column using the given faker
|
||||
// if faker is nil, a default faker is used
|
||||
// The generated value is sometimes null
|
||||
func (m userMods) RandomPasswordHash(f *faker.Faker) UserMod {
|
||||
return UserModFunc(func(_ context.Context, o *UserTemplate) {
|
||||
o.PasswordHash = func() null.Val[string] {
|
||||
if f == nil {
|
||||
f = &defaultFaker
|
||||
}
|
||||
|
||||
val := random_string(f)
|
||||
return null.From(val)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Generates a random value for the column using the given faker
|
||||
// if faker is nil, a default faker is used
|
||||
// The generated value is never null
|
||||
func (m userMods) RandomPasswordHashNotNull(f *faker.Faker) UserMod {
|
||||
return UserModFunc(func(_ context.Context, o *UserTemplate) {
|
||||
o.PasswordHash = func() null.Val[string] {
|
||||
if f == nil {
|
||||
f = &defaultFaker
|
||||
}
|
||||
|
||||
val := random_string(f)
|
||||
return null.From(val)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (m userMods) WithParentsCascading() UserMod {
|
||||
return UserModFunc(func(ctx context.Context, o *UserTemplate) {
|
||||
if isDone, _ := userWithParentsCascadingCtx.Value(ctx); isDone {
|
||||
|
|
|
|||
23
go.mod
23
go.mod
|
|
@ -3,23 +3,40 @@ module github.com/Gleipnir-Technology/nidus-sync
|
|||
go 1.24.9
|
||||
|
||||
require (
|
||||
github.com/aarondl/opt v0.0.0-20250607033636-982744e1bd65
|
||||
github.com/alexedwards/scs/v2 v2.9.0
|
||||
github.com/go-chi/chi/v5 v5.2.3
|
||||
github.com/go-webauthn/webauthn v0.14.0
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0
|
||||
github.com/jackc/pgx/v5 v5.7.6
|
||||
github.com/jaswdr/faker/v2 v2.8.1
|
||||
github.com/lib/pq v1.10.9
|
||||
github.com/pressly/goose/v3 v3.26.0
|
||||
github.com/stephenafamo/bob v0.41.1
|
||||
github.com/wasilibs/go-pgquery v0.0.0-20250409022910-10ac41983c07
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||
github.com/go-webauthn/x v0.1.25 // indirect
|
||||
github.com/google/go-tpm v0.9.5 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/mfridman/interpolate v0.0.2 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/pganalyze/pg_query_go/v6 v6.1.0 // indirect
|
||||
github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 // indirect
|
||||
github.com/sethvargo/go-retry v0.3.0 // indirect
|
||||
github.com/stephenafamo/scan v0.7.0 // indirect
|
||||
github.com/tetratelabs/wazero v1.9.0 // indirect
|
||||
github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/crypto v0.40.0 // indirect
|
||||
golang.org/x/sync v0.16.0 // indirect
|
||||
golang.org/x/text v0.27.0 // indirect
|
||||
golang.org/x/crypto v0.42.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/sys v0.36.0 // indirect
|
||||
golang.org/x/text v0.29.0 // indirect
|
||||
google.golang.org/protobuf v1.36.5 // indirect
|
||||
)
|
||||
|
|
|
|||
147
go.sum
147
go.sum
|
|
@ -1,16 +1,66 @@
|
|||
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/aarondl/opt v0.0.0-20250607033636-982744e1bd65 h1:lbdPe4LBNmNDzeQFwNhEc88w90841qv737MI4+aXSYU=
|
||||
github.com/aarondl/opt v0.0.0-20250607033636-982744e1bd65/go.mod h1:+xKBXrTAUOvrDXO5PRwIr4E1wciHY3Glgl+6OkCXknU=
|
||||
github.com/alexedwards/scs/v2 v2.9.0 h1:xa05mVpwTBm1iLeTMNFfAWpKUm4fXAW7CeAViqBVS90=
|
||||
github.com/alexedwards/scs/v2 v2.9.0/go.mod h1:ToaROZxyKukJKT/xLcVQAChi5k6+Pn1Gvmdl7h3RRj8=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
|
||||
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
|
||||
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
|
||||
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
|
||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
|
||||
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
|
||||
github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA=
|
||||
github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/docker v28.2.2+incompatible h1:CjwRSksz8Yo4+RmQ339Dp/D2tGO5JxwYeqtMOEe0LDw=
|
||||
github.com/docker/docker v28.2.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
|
||||
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
|
||||
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||
github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
|
||||
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-webauthn/webauthn v0.14.0 h1:ZLNPUgPcDlAeoxe+5umWG/tEeCoQIDr7gE2Zx2QnhL0=
|
||||
github.com/go-webauthn/webauthn v0.14.0/go.mod h1:QZzPFH3LJ48u5uEPAu+8/nWJImoLBWM7iAH/kSVSo6k=
|
||||
github.com/go-webauthn/x v0.1.25 h1:g/0noooIGcz/yCVqebcFgNnGIgBlJIccS+LYAa+0Z88=
|
||||
github.com/go-webauthn/x v0.1.25/go.mod h1:ieblaPY1/BVCV0oQTsA/VAo08/TWayQuJuo5Q+XxmTY=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/go-tpm v0.9.5 h1:ocUmnDebX54dnW+MQWGQRbdaAcJELsa6PqZhJ48KwVU=
|
||||
github.com/google/go-tpm v0.9.5/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
|
|
@ -21,14 +71,52 @@ github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk=
|
|||
github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
|
||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jaswdr/faker/v2 v2.8.1 h1:2AcPgHDBXYQregFUH9LgVZKfFupc4SIquYhp29sf5wQ=
|
||||
github.com/jaswdr/faker/v2 v2.8.1/go.mod h1:jZq+qzNQr8/P+5fHd9t3txe2GNPnthrTfohtnJ7B+68=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
|
||||
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY=
|
||||
github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg=
|
||||
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/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||
github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=
|
||||
github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo=
|
||||
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
|
||||
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
|
||||
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
|
||||
github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=
|
||||
github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
|
||||
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
|
||||
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
|
||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
||||
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
|
||||
github.com/pganalyze/pg_query_go/v6 v6.1.0 h1:jG5ZLhcVgL1FAw4C/0VNQaVmX1SUJx71wBGdtTtBvls=
|
||||
github.com/pganalyze/pg_query_go/v6 v6.1.0/go.mod h1:nvTHIuoud6e1SfrUaFwHqT0i4b5Nr+1rPWVds3B5+50=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/pressly/goose/v3 v3.26.0 h1:KJakav68jdH0WDvoAcj8+n61WqOIaPGgH0bJWS6jpmM=
|
||||
github.com/pressly/goose/v3 v3.26.0/go.mod h1:4hC1KrritdCxtuFsqgs1R4AU5bWtTAf+cnWvfhf2DNY=
|
||||
github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc=
|
||||
|
|
@ -37,6 +125,10 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94
|
|||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE=
|
||||
github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas=
|
||||
github.com/shirou/gopsutil/v4 v4.25.5 h1:rtd9piuSMGeU8g1RMXjZs9y9luK5BwtnG7dZaQUJAsc=
|
||||
github.com/shirou/gopsutil/v4 v4.25.5/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stephenafamo/bob v0.41.1 h1:xcRPuRMCwtZZ9tS4JIVbZ5Erdm5Dy5dIvbS5kivwPpA=
|
||||
github.com/stephenafamo/bob v0.41.1/go.mod h1:8l55917DM36gF518Iz1MHjLds7KGAfkitJfxISYlth8=
|
||||
github.com/stephenafamo/fakedb v0.0.0-20221230081958-0b86f816ed97 h1:XItoZNmhOih06TC02jK7l3wlpZ0XT/sPQYutDcGOQjg=
|
||||
|
|
@ -47,20 +139,55 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
|||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQl8=
|
||||
github.com/stretchr/testify v1.11.0/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/testcontainers/testcontainers-go v0.38.0 h1:d7uEapLcv2P8AvH8ahLqDMMxda2W9gQN1nRbHS28HBw=
|
||||
github.com/testcontainers/testcontainers-go v0.38.0/go.mod h1:C52c9MoHpWO+C4aqmgSU+hxlR5jlEayWtgYrb8Pzz1w=
|
||||
github.com/testcontainers/testcontainers-go/modules/postgres v0.38.0 h1:KFdx9A0yF94K70T6ibSuvgkQQeX1xKlZVF3hEagXEtY=
|
||||
github.com/testcontainers/testcontainers-go/modules/postgres v0.38.0/go.mod h1:T/QRECND6N6tAKMxF1Za+G2tpwnGEHcODzHRsgIpw9M=
|
||||
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
|
||||
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
|
||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
||||
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
|
||||
github.com/wasilibs/go-pgquery v0.0.0-20250409022910-10ac41983c07 h1:mJdDDPblDfPe7z7go8Dvv1AJQDI3eQ/5xith3q2mFlo=
|
||||
github.com/wasilibs/go-pgquery v0.0.0-20250409022910-10ac41983c07/go.mod h1:Ak17IJ037caFp4jpCw/iQQ7/W74Sqpb1YuKJU6HTKfM=
|
||||
github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52 h1:OvLBa8SqJnZ6P+mjlzc2K7PM22rRUPE1x32G9DTPrC4=
|
||||
github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52/go.mod h1:jMeV4Vpbi8osrE/pKUxRZkVaA0EX7NZN0A9/oRzgpgY=
|
||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
|
||||
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
||||
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
||||
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
|
||||
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
|
||||
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
||||
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
||||
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
|
||||
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
|
||||
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.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
|
||||
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
|
||||
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
|
||||
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
|
||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
|
||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
|
||||
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
|
||||
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
|||
10
migrations/00002_password.sql
Normal file
10
migrations/00002_password.sql
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
-- +goose Up
|
||||
CREATE TYPE HashType AS ENUM (
|
||||
'bcrypt-14');
|
||||
|
||||
ALTER TABLE user_ ADD COLUMN password_hash_type HashType;
|
||||
ALTER TABLE user_ ADD COLUMN password_hash TEXT;
|
||||
-- +goose Down
|
||||
ALTER TABLE user_ DROP COLUMN password_hash;
|
||||
ALTER TABLE user_ DROP COLUMN password_hash_type;
|
||||
DROP TYPE HashType;
|
||||
|
|
@ -28,3 +28,9 @@ var _ sql.Scanner = (*enums.ArcgisLicenseType)(nil)
|
|||
|
||||
// Make sure the type enums.ArcgisLicenseType satisfies database/sql/driver.Valuer
|
||||
var _ driver.Valuer = *new(enums.ArcgisLicenseType)
|
||||
|
||||
// Make sure the type enums.Hashtype satisfies database/sql.Scanner
|
||||
var _ sql.Scanner = (*enums.Hashtype)(nil)
|
||||
|
||||
// Make sure the type enums.Hashtype satisfies database/sql/driver.Valuer
|
||||
var _ driver.Valuer = *new(enums.Hashtype)
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ type User struct {
|
|||
Email null.Val[string] `db:"email" `
|
||||
OrganizationID null.Val[int32] `db:"organization_id" `
|
||||
Username string `db:"username" `
|
||||
PasswordHashType null.Val[enums.Hashtype] `db:"password_hash_type" `
|
||||
PasswordHash null.Val[string] `db:"password_hash" `
|
||||
|
||||
R userR `db:"-" `
|
||||
}
|
||||
|
|
@ -59,7 +61,7 @@ type userR struct {
|
|||
func buildUserColumns(alias string) userColumns {
|
||||
return userColumns{
|
||||
ColumnsExpr: expr.NewColumnsExpr(
|
||||
"id", "arcgis_access_token", "arcgis_license", "arcgis_refresh_token", "arcgis_refresh_token_expires", "arcgis_role", "display_name", "email", "organization_id", "username",
|
||||
"id", "arcgis_access_token", "arcgis_license", "arcgis_refresh_token", "arcgis_refresh_token_expires", "arcgis_role", "display_name", "email", "organization_id", "username", "password_hash_type", "password_hash",
|
||||
).WithParent("user_"),
|
||||
tableAlias: alias,
|
||||
ID: psql.Quote(alias, "id"),
|
||||
|
|
@ -72,6 +74,8 @@ func buildUserColumns(alias string) userColumns {
|
|||
Email: psql.Quote(alias, "email"),
|
||||
OrganizationID: psql.Quote(alias, "organization_id"),
|
||||
Username: psql.Quote(alias, "username"),
|
||||
PasswordHashType: psql.Quote(alias, "password_hash_type"),
|
||||
PasswordHash: psql.Quote(alias, "password_hash"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -88,6 +92,8 @@ type userColumns struct {
|
|||
Email psql.Expression
|
||||
OrganizationID psql.Expression
|
||||
Username psql.Expression
|
||||
PasswordHashType psql.Expression
|
||||
PasswordHash psql.Expression
|
||||
}
|
||||
|
||||
func (c userColumns) Alias() string {
|
||||
|
|
@ -112,10 +118,12 @@ type UserSetter struct {
|
|||
Email omitnull.Val[string] `db:"email" `
|
||||
OrganizationID omitnull.Val[int32] `db:"organization_id" `
|
||||
Username omit.Val[string] `db:"username" `
|
||||
PasswordHashType omitnull.Val[enums.Hashtype] `db:"password_hash_type" `
|
||||
PasswordHash omitnull.Val[string] `db:"password_hash" `
|
||||
}
|
||||
|
||||
func (s UserSetter) SetColumns() []string {
|
||||
vals := make([]string, 0, 10)
|
||||
vals := make([]string, 0, 12)
|
||||
if s.ID.IsValue() {
|
||||
vals = append(vals, "id")
|
||||
}
|
||||
|
|
@ -146,6 +154,12 @@ func (s UserSetter) SetColumns() []string {
|
|||
if s.Username.IsValue() {
|
||||
vals = append(vals, "username")
|
||||
}
|
||||
if !s.PasswordHashType.IsUnset() {
|
||||
vals = append(vals, "password_hash_type")
|
||||
}
|
||||
if !s.PasswordHash.IsUnset() {
|
||||
vals = append(vals, "password_hash")
|
||||
}
|
||||
return vals
|
||||
}
|
||||
|
||||
|
|
@ -180,6 +194,12 @@ func (s UserSetter) Overwrite(t *User) {
|
|||
if s.Username.IsValue() {
|
||||
t.Username = s.Username.MustGet()
|
||||
}
|
||||
if !s.PasswordHashType.IsUnset() {
|
||||
t.PasswordHashType = s.PasswordHashType.MustGetNull()
|
||||
}
|
||||
if !s.PasswordHash.IsUnset() {
|
||||
t.PasswordHash = s.PasswordHash.MustGetNull()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *UserSetter) Apply(q *dialect.InsertQuery) {
|
||||
|
|
@ -188,7 +208,7 @@ func (s *UserSetter) Apply(q *dialect.InsertQuery) {
|
|||
})
|
||||
|
||||
q.AppendValues(bob.ExpressionFunc(func(ctx context.Context, w io.Writer, d bob.Dialect, start int) ([]any, error) {
|
||||
vals := make([]bob.Expression, 10)
|
||||
vals := make([]bob.Expression, 12)
|
||||
if s.ID.IsValue() {
|
||||
vals[0] = psql.Arg(s.ID.MustGet())
|
||||
} else {
|
||||
|
|
@ -249,6 +269,18 @@ func (s *UserSetter) Apply(q *dialect.InsertQuery) {
|
|||
vals[9] = psql.Raw("DEFAULT")
|
||||
}
|
||||
|
||||
if !s.PasswordHashType.IsUnset() {
|
||||
vals[10] = psql.Arg(s.PasswordHashType.MustGetNull())
|
||||
} else {
|
||||
vals[10] = psql.Raw("DEFAULT")
|
||||
}
|
||||
|
||||
if !s.PasswordHash.IsUnset() {
|
||||
vals[11] = psql.Arg(s.PasswordHash.MustGetNull())
|
||||
} else {
|
||||
vals[11] = psql.Raw("DEFAULT")
|
||||
}
|
||||
|
||||
return bob.ExpressSlice(ctx, w, d, start, vals, "", ", ", "")
|
||||
}))
|
||||
}
|
||||
|
|
@ -258,7 +290,7 @@ func (s UserSetter) UpdateMod() bob.Mod[*dialect.UpdateQuery] {
|
|||
}
|
||||
|
||||
func (s UserSetter) Expressions(prefix ...string) []bob.Expression {
|
||||
exprs := make([]bob.Expression, 0, 10)
|
||||
exprs := make([]bob.Expression, 0, 12)
|
||||
|
||||
if s.ID.IsValue() {
|
||||
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
|
||||
|
|
@ -330,6 +362,20 @@ func (s UserSetter) Expressions(prefix ...string) []bob.Expression {
|
|||
}})
|
||||
}
|
||||
|
||||
if !s.PasswordHashType.IsUnset() {
|
||||
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
|
||||
psql.Quote(append(prefix, "password_hash_type")...),
|
||||
psql.Arg(s.PasswordHashType),
|
||||
}})
|
||||
}
|
||||
|
||||
if !s.PasswordHash.IsUnset() {
|
||||
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
|
||||
psql.Quote(append(prefix, "password_hash")...),
|
||||
psql.Arg(s.PasswordHash),
|
||||
}})
|
||||
}
|
||||
|
||||
return exprs
|
||||
}
|
||||
|
||||
|
|
@ -639,6 +685,8 @@ type userWhere[Q psql.Filterable] struct {
|
|||
Email psql.WhereNullMod[Q, string]
|
||||
OrganizationID psql.WhereNullMod[Q, int32]
|
||||
Username psql.WhereMod[Q, string]
|
||||
PasswordHashType psql.WhereNullMod[Q, enums.Hashtype]
|
||||
PasswordHash psql.WhereNullMod[Q, string]
|
||||
}
|
||||
|
||||
func (userWhere[Q]) AliasedAs(alias string) userWhere[Q] {
|
||||
|
|
@ -657,6 +705,8 @@ func buildUserWhere[Q psql.Filterable](cols userColumns) userWhere[Q] {
|
|||
Email: psql.WhereNull[Q, string](cols.Email),
|
||||
OrganizationID: psql.WhereNull[Q, int32](cols.OrganizationID),
|
||||
Username: psql.Where[Q, string](cols.Username),
|
||||
PasswordHashType: psql.WhereNull[Q, enums.Hashtype](cols.PasswordHashType),
|
||||
PasswordHash: psql.WhereNull[Q, string](cols.PasswordHash),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,13 +56,18 @@
|
|||
|
||||
<form method="POST" action="/signup">
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Full Name</label>
|
||||
<label for="name" class="form-label">Display Name</label>
|
||||
<input type="text" class="form-control" name="name" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Email Address</label>
|
||||
<input type="email" class="form-control" name="email" required>
|
||||
<label for="username" class="form-label">Username</label>
|
||||
<input type="username" class="form-control" name="username" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Password</label>
|
||||
<input type="password" class="form-control" name="password" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 form-check">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue