normalize common database errors
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
parent
5ac99ee556
commit
87451560e3
13 changed files with 200 additions and 68 deletions
14
go.mod
14
go.mod
|
@ -10,10 +10,10 @@ require (
|
|||
github.com/alexedwards/argon2id v1.0.0
|
||||
github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964
|
||||
github.com/aws/aws-sdk-go-v2 v1.24.1
|
||||
github.com/aws/aws-sdk-go-v2/config v1.26.3
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.16.14
|
||||
github.com/aws/aws-sdk-go-v2/config v1.26.4
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.16.15
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.11
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.12
|
||||
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.19.6
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.48.0
|
||||
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.26.2
|
||||
|
@ -95,7 +95,7 @@ require (
|
|||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.18.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 // indirect
|
||||
github.com/aws/smithy-go v1.19.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/boombuler/barcode v1.0.1 // indirect
|
||||
|
@ -171,9 +171,9 @@ require (
|
|||
golang.org/x/tools v0.17.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240108191215-35c7eff3a6b1 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect
|
||||
google.golang.org/grpc v1.60.1 // indirect
|
||||
google.golang.org/protobuf v1.32.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
|
|
28
go.sum
28
go.sum
|
@ -37,14 +37,14 @@ github.com/aws/aws-sdk-go-v2 v1.24.1 h1:xAojnj+ktS95YZlDf0zxWBkbFtymPeDP+rvUQIH3
|
|||
github.com/aws/aws-sdk-go-v2 v1.24.1/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 h1:OCs21ST2LrepDfD3lwlQiOqIGp6JiEUqG84GzTDoyJs=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4/go.mod h1:usURWEKSNNAcAZuzRn/9ZYPT8aZQkR7xcCtunK/LkJo=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.26.3 h1:dKuc2jdp10y13dEEvPqWxqLoc0vF3Z9FC45MvuQSxOA=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.26.3/go.mod h1:Bxgi+DeeswYofcYO0XyGClwlrq3DZEXli0kLf4hkGA0=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.16.14 h1:mMDTwwYO9A0/JbOCOG7EOZHtYM+o7OfGWfu0toa23VE=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.16.14/go.mod h1:cniAUh3ErQPHtCQGPT5ouvSAQ0od8caTO9OOuufZOAE=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.26.4 h1:Juj7LhtxNudNUlfX22K5AnLafO+v4eq9PA3VWSCIQs4=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.26.4/go.mod h1:tioqQ7wvxMYnTDpoTTLHhV3Zh+z261i/f2oz+ds8eNI=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.16.15 h1:P0/m1LU08MF2kRzx4P//+7lNjiJod1z4xI2WpWhdpTQ=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.16.15/go.mod h1:pgtMCf7Dx4GWw5EpHOTc2Sy17LIP0A0N2C9nQ83pQ/0=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 h1:c5I5iH+DZcH3xOIMlz3/tCKJDaHFwYEmxvlh2fAcFo8=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11/go.mod h1:cRrYDYAMUohBJUtUnOhydaMHtiK/1NZ0Otc9lIb6O0Y=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.11 h1:I6lAa3wBWfCz/cKkOpAcumsETRkFAl70sWi8ItcMEsM=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.11/go.mod h1:be1NIO30kJA23ORBLqPo1LttEM6tPNSEcjkd1eKzNW0=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.12 h1:0FMZy36RSYvcvVzEf1xbNdebLHZewW40QWP+P8jCMVk=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.12/go.mod h1:+chyahvarkb3HibkNei9IQEM9P5cWD5w2kgXCa3Hh0I=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 h1:vF+Zgd9s+H4vOXd5BMaPWykta2a6Ih0AKLq/X6NYKn4=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10/go.mod h1:6BkRjejp/GR4411UGqkX8+wFMbFbqsUIimfK4XjOKR4=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 h1:nYPe006ktcqUji8S2mqXf9c/7NdiKriOwMvWQHgYztw=
|
||||
|
@ -69,8 +69,8 @@ github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.26.2 h1:A5sGOT/mukuU+4At1
|
|||
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.26.2/go.mod h1:qutL00aW8GSo2D0I6UEOqMvRS3ZyuBrOC1BLe5D2jPc=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.18.6 h1:dGrs+Q/WzhsiUKh82SfTVN66QzyulXuMDTV/G8ZxOac=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.18.6/go.mod h1:+mJNDdF+qiUlNKNC3fxn74WWNN+sOiGOEImje+3ScPM=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.6 h1:Yf2MIo9x+0tyv76GljxzqA3WtC5mw7NmazD2chwjxE4=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.6/go.mod h1:ykf3COxYI0UJmxcfcxcVuz7b6uADi1FkiUz6Eb7AgM8=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 h1:QPMJf+Jw8E1l7zqhZmMlFw6w1NmfkfiSK8mS4zOx3BA=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7/go.mod h1:ykf3COxYI0UJmxcfcxcVuz7b6uADi1FkiUz6Eb7AgM8=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 h1:NzO4Vrau795RkUdSHKEwiR01FaGzGOH1EETJ+5QHnm0=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.26.7/go.mod h1:6h2YuIoxaMSCFf5fi1EgZAwdfkGMgDY+DVfa61uLe4U=
|
||||
github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM=
|
||||
|
@ -531,12 +531,12 @@ google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJ
|
|||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20240108191215-35c7eff3a6b1 h1:/IWabOtPziuXTEtI1KYCpM6Ss7vaAkeMxk+uXV/xvZs=
|
||||
google.golang.org/genproto v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:+Rvu7ElI+aLzyDQhpHMFMMltsD6m7nqpuWDd2CwJw3k=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1 h1:OPXtXn7fNMaXwO3JvOmF1QyTc00jsSFFz1vXXBOdCDo=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 h1:gphdwh0npgs8elJ4T6J+DQJHPVF7RsuJHCfwztUb4J4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA=
|
||||
google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac h1:ZL/Teoy/ZGnzyrqK/Optxxp2pmVh+fmJ97slxSRyzUg=
|
||||
google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:+Rvu7ElI+aLzyDQhpHMFMMltsD6m7nqpuWDd2CwJw3k=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac h1:OZkkudMUu9LVQMCoRUbI/1p5VCo9BOrlvkqMvWtqa6s=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac h1:nUQEQmH/csSvFECKYRv6HWEyypysidKl2I6Qpsglq/0=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
|
|
|
@ -387,7 +387,10 @@ func (p *BoltProvider) addAdmin(admin *Admin) error {
|
|||
return err
|
||||
}
|
||||
if a := bucket.Get([]byte(admin.Username)); a != nil {
|
||||
return fmt.Errorf("admin %q already exists", admin.Username)
|
||||
return util.NewI18nError(
|
||||
fmt.Errorf("%w: admin %q already exists", ErrDuplicatedKey, admin.Username),
|
||||
util.I18nErrorDuplicatedUsername,
|
||||
)
|
||||
}
|
||||
id, err := bucket.NextSequence()
|
||||
if err != nil {
|
||||
|
@ -649,7 +652,10 @@ func (p *BoltProvider) addUser(user *User) error {
|
|||
return err
|
||||
}
|
||||
if u := bucket.Get([]byte(user.Username)); u != nil {
|
||||
return fmt.Errorf("username %v already exists", user.Username)
|
||||
return util.NewI18nError(
|
||||
fmt.Errorf("%w: username %v already exists", ErrDuplicatedKey, user.Username),
|
||||
util.I18nErrorDuplicatedUsername,
|
||||
)
|
||||
}
|
||||
id, err := bucket.NextSequence()
|
||||
if err != nil {
|
||||
|
@ -1121,7 +1127,10 @@ func (p *BoltProvider) addFolder(folder *vfs.BaseVirtualFolder) error {
|
|||
return err
|
||||
}
|
||||
if f := bucket.Get([]byte(folder.Name)); f != nil {
|
||||
return fmt.Errorf("folder %v already exists", folder.Name)
|
||||
return util.NewI18nError(
|
||||
fmt.Errorf("%w: folder %q already exists", ErrDuplicatedKey, folder.Name),
|
||||
util.I18nErrorDuplicatedUsername,
|
||||
)
|
||||
}
|
||||
folder.Users = nil
|
||||
folder.Groups = nil
|
||||
|
@ -1435,7 +1444,10 @@ func (p *BoltProvider) addGroup(group *Group) error {
|
|||
return err
|
||||
}
|
||||
if u := bucket.Get([]byte(group.Name)); u != nil {
|
||||
return fmt.Errorf("group %v already exists", group.Name)
|
||||
return util.NewI18nError(
|
||||
fmt.Errorf("%w: group %q already exists", ErrDuplicatedKey, group.Name),
|
||||
util.I18nErrorDuplicatedUsername,
|
||||
)
|
||||
}
|
||||
id, err := bucket.NextSequence()
|
||||
if err != nil {
|
||||
|
@ -1808,7 +1820,7 @@ func (p *BoltProvider) addShare(share *Share) error {
|
|||
return err
|
||||
}
|
||||
if a := bucket.Get([]byte(share.ShareID)); a != nil {
|
||||
return fmt.Errorf("share %v already exists", share.ShareID)
|
||||
return fmt.Errorf("share %q already exists", share.ShareID)
|
||||
}
|
||||
id, err := bucket.NextSequence()
|
||||
if err != nil {
|
||||
|
@ -2188,7 +2200,10 @@ func (p *BoltProvider) addEventAction(action *BaseEventAction) error {
|
|||
return err
|
||||
}
|
||||
if a := bucket.Get([]byte(action.Name)); a != nil {
|
||||
return fmt.Errorf("event action %s already exists", action.Name)
|
||||
return util.NewI18nError(
|
||||
fmt.Errorf("%w: event action %q already exists", ErrDuplicatedKey, action.Name),
|
||||
util.I18nErrorDuplicatedName,
|
||||
)
|
||||
}
|
||||
id, err := bucket.NextSequence()
|
||||
if err != nil {
|
||||
|
@ -2449,7 +2464,10 @@ func (p *BoltProvider) addEventRule(rule *EventRule) error {
|
|||
return err
|
||||
}
|
||||
if r := bucket.Get([]byte(rule.Name)); r != nil {
|
||||
return fmt.Errorf("event rule %q already exists", rule.Name)
|
||||
return util.NewI18nError(
|
||||
fmt.Errorf("%w: event rule %q already exists", ErrDuplicatedKey, rule.Name),
|
||||
util.I18nErrorDuplicatedName,
|
||||
)
|
||||
}
|
||||
id, err := bucket.NextSequence()
|
||||
if err != nil {
|
||||
|
@ -2618,7 +2636,10 @@ func (p *BoltProvider) addRole(role *Role) error {
|
|||
return err
|
||||
}
|
||||
if r := bucket.Get([]byte(role.Name)); r != nil {
|
||||
return fmt.Errorf("role %q already exists", role.Name)
|
||||
return util.NewI18nError(
|
||||
fmt.Errorf("%w: role %q already exists", ErrDuplicatedKey, role.Name),
|
||||
util.I18nErrorDuplicatedName,
|
||||
)
|
||||
}
|
||||
id, err := bucket.NextSequence()
|
||||
if err != nil {
|
||||
|
|
|
@ -148,6 +148,11 @@ const (
|
|||
DumpScopeConfigs = "configs"
|
||||
)
|
||||
|
||||
const (
|
||||
fieldUsername = 1
|
||||
fieldName = 2
|
||||
)
|
||||
|
||||
var (
|
||||
// SupportedProviders defines the supported data providers
|
||||
SupportedProviders = []string{SQLiteDataProviderName, PGSQLDataProviderName, MySQLDataProviderName,
|
||||
|
@ -176,13 +181,17 @@ var (
|
|||
ErrInvalidCredentials = errors.New("invalid credentials")
|
||||
// ErrLoginNotAllowedFromIP defines the error to return if login is denied from the current IP
|
||||
ErrLoginNotAllowedFromIP = errors.New("login is not allowed from this IP")
|
||||
isAdminCreated atomic.Bool
|
||||
validTLSUsernames = []string{string(sdk.TLSUsernameNone), string(sdk.TLSUsernameCN)}
|
||||
config Config
|
||||
provider Provider
|
||||
sqlPlaceholders []string
|
||||
internalHashPwdPrefixes = []string{argonPwdPrefix, bcryptPwdPrefix}
|
||||
hashPwdPrefixes = []string{argonPwdPrefix, bcryptPwdPrefix, pbkdf2SHA1Prefix, pbkdf2SHA256Prefix,
|
||||
// ErrDuplicatedKey occurs when there is a unique key constraint violation
|
||||
ErrDuplicatedKey = errors.New("duplicated key not allowed")
|
||||
// ErrForeignKeyViolated occurs when there is a foreign key constraint violation
|
||||
ErrForeignKeyViolated = errors.New("violates foreign key constraint")
|
||||
isAdminCreated atomic.Bool
|
||||
validTLSUsernames = []string{string(sdk.TLSUsernameNone), string(sdk.TLSUsernameCN)}
|
||||
config Config
|
||||
provider Provider
|
||||
sqlPlaceholders []string
|
||||
internalHashPwdPrefixes = []string{argonPwdPrefix, bcryptPwdPrefix}
|
||||
hashPwdPrefixes = []string{argonPwdPrefix, bcryptPwdPrefix, pbkdf2SHA1Prefix, pbkdf2SHA256Prefix,
|
||||
pbkdf2SHA512Prefix, pbkdf2SHA256B64SaltPrefix, md5cryptPwdPrefix, md5cryptApr1PwdPrefix, md5DigestPwdPrefix,
|
||||
sha256DigestPwdPrefix, sha512DigestPwdPrefix, sha256cryptPwdPrefix, sha512cryptPwdPrefix, yescryptPwdPrefix}
|
||||
pbkdfPwdPrefixes = []string{pbkdf2SHA1Prefix, pbkdf2SHA256Prefix, pbkdf2SHA512Prefix, pbkdf2SHA256B64SaltPrefix}
|
||||
|
|
|
@ -332,7 +332,10 @@ func (p *MemoryProvider) addUser(user *User) error {
|
|||
|
||||
_, err = p.userExistsInternal(user.Username)
|
||||
if err == nil {
|
||||
return fmt.Errorf("username %q already exists", user.Username)
|
||||
return util.NewI18nError(
|
||||
fmt.Errorf("%w: username %v already exists", ErrDuplicatedKey, user.Username),
|
||||
util.I18nErrorDuplicatedUsername,
|
||||
)
|
||||
}
|
||||
user.ID = p.getNextID()
|
||||
user.LastQuotaUpdate = 0
|
||||
|
@ -730,7 +733,10 @@ func (p *MemoryProvider) addAdmin(admin *Admin) error {
|
|||
}
|
||||
_, err = p.adminExistsInternal(admin.Username)
|
||||
if err == nil {
|
||||
return fmt.Errorf("admin %q already exists", admin.Username)
|
||||
return util.NewI18nError(
|
||||
fmt.Errorf("%w: admin %q already exists", ErrDuplicatedKey, admin.Username),
|
||||
util.I18nErrorDuplicatedUsername,
|
||||
)
|
||||
}
|
||||
admin.ID = p.getNextAdminID()
|
||||
admin.CreatedAt = util.GetTimeAsMsSinceEpoch(time.Now())
|
||||
|
@ -1041,7 +1047,10 @@ func (p *MemoryProvider) addGroup(group *Group) error {
|
|||
|
||||
_, err := p.groupExistsInternal(group.Name)
|
||||
if err == nil {
|
||||
return fmt.Errorf("group %q already exists", group.Name)
|
||||
return util.NewI18nError(
|
||||
fmt.Errorf("%w: group %q already exists", ErrDuplicatedKey, group.Name),
|
||||
util.I18nErrorDuplicatedUsername,
|
||||
)
|
||||
}
|
||||
group.ID = p.getNextGroupID()
|
||||
group.CreatedAt = util.GetTimeAsMsSinceEpoch(time.Now())
|
||||
|
@ -1512,7 +1521,10 @@ func (p *MemoryProvider) addFolder(folder *vfs.BaseVirtualFolder) error {
|
|||
|
||||
_, err = p.folderExistsInternal(folder.Name)
|
||||
if err == nil {
|
||||
return fmt.Errorf("folder %q already exists", folder.Name)
|
||||
return util.NewI18nError(
|
||||
fmt.Errorf("%w: folder %q already exists", ErrDuplicatedKey, folder.Name),
|
||||
util.I18nErrorDuplicatedUsername,
|
||||
)
|
||||
}
|
||||
folder.ID = p.getNextFolderID()
|
||||
folder.Users = nil
|
||||
|
@ -2172,7 +2184,10 @@ func (p *MemoryProvider) addEventAction(action *BaseEventAction) error {
|
|||
}
|
||||
_, err = p.actionExistsInternal(action.Name)
|
||||
if err == nil {
|
||||
return fmt.Errorf("event action %q already exists", action.Name)
|
||||
return util.NewI18nError(
|
||||
fmt.Errorf("%w: event action %q already exists", ErrDuplicatedKey, action.Name),
|
||||
util.I18nErrorDuplicatedName,
|
||||
)
|
||||
}
|
||||
action.ID = p.getNextActionID()
|
||||
action.Rules = nil
|
||||
|
@ -2348,7 +2363,10 @@ func (p *MemoryProvider) addEventRule(rule *EventRule) error {
|
|||
}
|
||||
_, err := p.ruleExistsInternal(rule.Name)
|
||||
if err == nil {
|
||||
return fmt.Errorf("event rule %q already exists", rule.Name)
|
||||
return util.NewI18nError(
|
||||
fmt.Errorf("%w: event rule %q already exists", ErrDuplicatedKey, rule.Name),
|
||||
util.I18nErrorDuplicatedName,
|
||||
)
|
||||
}
|
||||
rule.ID = p.getNextRuleID()
|
||||
rule.CreatedAt = util.GetTimeAsMsSinceEpoch(time.Now())
|
||||
|
@ -2499,7 +2517,10 @@ func (p *MemoryProvider) addRole(role *Role) error {
|
|||
|
||||
_, err := p.roleExistsInternal(role.Name)
|
||||
if err == nil {
|
||||
return fmt.Errorf("role %q already exists", role.Name)
|
||||
return util.NewI18nError(
|
||||
fmt.Errorf("%w: role %q already exists", ErrDuplicatedKey, role.Name),
|
||||
util.I18nErrorDuplicatedName,
|
||||
)
|
||||
}
|
||||
role.ID = p.getNextRoleID()
|
||||
role.CreatedAt = util.GetTimeAsMsSinceEpoch(time.Now())
|
||||
|
|
|
@ -32,6 +32,7 @@ import (
|
|||
"github.com/go-sql-driver/mysql"
|
||||
|
||||
"github.com/drakkan/sftpgo/v2/internal/logger"
|
||||
"github.com/drakkan/sftpgo/v2/internal/util"
|
||||
"github.com/drakkan/sftpgo/v2/internal/version"
|
||||
"github.com/drakkan/sftpgo/v2/internal/vfs"
|
||||
)
|
||||
|
@ -341,7 +342,7 @@ func (p *MySQLProvider) userExists(username, role string) (User, error) {
|
|||
}
|
||||
|
||||
func (p *MySQLProvider) addUser(user *User) error {
|
||||
return sqlCommonAddUser(user, p.dbHandle)
|
||||
return p.normalizeError(sqlCommonAddUser(user, p.dbHandle), fieldUsername)
|
||||
}
|
||||
|
||||
func (p *MySQLProvider) updateUser(user *User) error {
|
||||
|
@ -387,7 +388,7 @@ func (p *MySQLProvider) getFolderByName(name string) (vfs.BaseVirtualFolder, err
|
|||
}
|
||||
|
||||
func (p *MySQLProvider) addFolder(folder *vfs.BaseVirtualFolder) error {
|
||||
return sqlCommonAddFolder(folder, p.dbHandle)
|
||||
return p.normalizeError(sqlCommonAddFolder(folder, p.dbHandle), fieldName)
|
||||
}
|
||||
|
||||
func (p *MySQLProvider) updateFolder(folder *vfs.BaseVirtualFolder) error {
|
||||
|
@ -423,7 +424,7 @@ func (p *MySQLProvider) groupExists(name string) (Group, error) {
|
|||
}
|
||||
|
||||
func (p *MySQLProvider) addGroup(group *Group) error {
|
||||
return sqlCommonAddGroup(group, p.dbHandle)
|
||||
return p.normalizeError(sqlCommonAddGroup(group, p.dbHandle), fieldName)
|
||||
}
|
||||
|
||||
func (p *MySQLProvider) updateGroup(group *Group) error {
|
||||
|
@ -443,7 +444,7 @@ func (p *MySQLProvider) adminExists(username string) (Admin, error) {
|
|||
}
|
||||
|
||||
func (p *MySQLProvider) addAdmin(admin *Admin) error {
|
||||
return sqlCommonAddAdmin(admin, p.dbHandle)
|
||||
return p.normalizeError(sqlCommonAddAdmin(admin, p.dbHandle), fieldUsername)
|
||||
}
|
||||
|
||||
func (p *MySQLProvider) updateAdmin(admin *Admin) error {
|
||||
|
@ -603,7 +604,7 @@ func (p *MySQLProvider) eventActionExists(name string) (BaseEventAction, error)
|
|||
}
|
||||
|
||||
func (p *MySQLProvider) addEventAction(action *BaseEventAction) error {
|
||||
return sqlCommonAddEventAction(action, p.dbHandle)
|
||||
return p.normalizeError(sqlCommonAddEventAction(action, p.dbHandle), fieldName)
|
||||
}
|
||||
|
||||
func (p *MySQLProvider) updateEventAction(action *BaseEventAction) error {
|
||||
|
@ -631,7 +632,7 @@ func (p *MySQLProvider) eventRuleExists(name string) (EventRule, error) {
|
|||
}
|
||||
|
||||
func (p *MySQLProvider) addEventRule(rule *EventRule) error {
|
||||
return sqlCommonAddEventRule(rule, p.dbHandle)
|
||||
return p.normalizeError(sqlCommonAddEventRule(rule, p.dbHandle), fieldName)
|
||||
}
|
||||
|
||||
func (p *MySQLProvider) updateEventRule(rule *EventRule) error {
|
||||
|
@ -683,7 +684,7 @@ func (p *MySQLProvider) roleExists(name string) (Role, error) {
|
|||
}
|
||||
|
||||
func (p *MySQLProvider) addRole(role *Role) error {
|
||||
return sqlCommonAddRole(role, p.dbHandle)
|
||||
return p.normalizeError(sqlCommonAddRole(role, p.dbHandle), fieldName)
|
||||
}
|
||||
|
||||
func (p *MySQLProvider) updateRole(role *Role) error {
|
||||
|
@ -824,3 +825,26 @@ func (p *MySQLProvider) resetDatabase() error {
|
|||
sql := sqlReplaceAll(mysqlResetSQL)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(p.dbHandle, strings.Split(sql, ";"), 0, false)
|
||||
}
|
||||
|
||||
func (p *MySQLProvider) normalizeError(err error, fieldType int) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
var mysqlErr *mysql.MySQLError
|
||||
if errors.As(err, &mysqlErr) {
|
||||
switch mysqlErr.Number {
|
||||
case 1062:
|
||||
message := util.I18nErrorDuplicatedName
|
||||
if fieldType == fieldUsername {
|
||||
message = util.I18nErrorDuplicatedUsername
|
||||
}
|
||||
return util.NewI18nError(
|
||||
fmt.Errorf("%w: %s", ErrDuplicatedKey, err.Error()),
|
||||
message,
|
||||
)
|
||||
case 1452:
|
||||
return fmt.Errorf("%w: %s", ErrForeignKeyViolated, err.Error())
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -29,9 +29,11 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
"github.com/jackc/pgx/v5/stdlib"
|
||||
|
||||
"github.com/drakkan/sftpgo/v2/internal/logger"
|
||||
"github.com/drakkan/sftpgo/v2/internal/util"
|
||||
"github.com/drakkan/sftpgo/v2/internal/version"
|
||||
"github.com/drakkan/sftpgo/v2/internal/vfs"
|
||||
)
|
||||
|
@ -353,7 +355,7 @@ func (p *PGSQLProvider) userExists(username, role string) (User, error) {
|
|||
}
|
||||
|
||||
func (p *PGSQLProvider) addUser(user *User) error {
|
||||
return sqlCommonAddUser(user, p.dbHandle)
|
||||
return p.normalizeError(sqlCommonAddUser(user, p.dbHandle), fieldUsername)
|
||||
}
|
||||
|
||||
func (p *PGSQLProvider) updateUser(user *User) error {
|
||||
|
@ -399,7 +401,7 @@ func (p *PGSQLProvider) getFolderByName(name string) (vfs.BaseVirtualFolder, err
|
|||
}
|
||||
|
||||
func (p *PGSQLProvider) addFolder(folder *vfs.BaseVirtualFolder) error {
|
||||
return sqlCommonAddFolder(folder, p.dbHandle)
|
||||
return p.normalizeError(sqlCommonAddFolder(folder, p.dbHandle), fieldName)
|
||||
}
|
||||
|
||||
func (p *PGSQLProvider) updateFolder(folder *vfs.BaseVirtualFolder) error {
|
||||
|
@ -435,7 +437,7 @@ func (p *PGSQLProvider) groupExists(name string) (Group, error) {
|
|||
}
|
||||
|
||||
func (p *PGSQLProvider) addGroup(group *Group) error {
|
||||
return sqlCommonAddGroup(group, p.dbHandle)
|
||||
return p.normalizeError(sqlCommonAddGroup(group, p.dbHandle), fieldName)
|
||||
}
|
||||
|
||||
func (p *PGSQLProvider) updateGroup(group *Group) error {
|
||||
|
@ -455,7 +457,7 @@ func (p *PGSQLProvider) adminExists(username string) (Admin, error) {
|
|||
}
|
||||
|
||||
func (p *PGSQLProvider) addAdmin(admin *Admin) error {
|
||||
return sqlCommonAddAdmin(admin, p.dbHandle)
|
||||
return p.normalizeError(sqlCommonAddAdmin(admin, p.dbHandle), fieldUsername)
|
||||
}
|
||||
|
||||
func (p *PGSQLProvider) updateAdmin(admin *Admin) error {
|
||||
|
@ -615,7 +617,7 @@ func (p *PGSQLProvider) eventActionExists(name string) (BaseEventAction, error)
|
|||
}
|
||||
|
||||
func (p *PGSQLProvider) addEventAction(action *BaseEventAction) error {
|
||||
return sqlCommonAddEventAction(action, p.dbHandle)
|
||||
return p.normalizeError(sqlCommonAddEventAction(action, p.dbHandle), fieldName)
|
||||
}
|
||||
|
||||
func (p *PGSQLProvider) updateEventAction(action *BaseEventAction) error {
|
||||
|
@ -643,7 +645,7 @@ func (p *PGSQLProvider) eventRuleExists(name string) (EventRule, error) {
|
|||
}
|
||||
|
||||
func (p *PGSQLProvider) addEventRule(rule *EventRule) error {
|
||||
return sqlCommonAddEventRule(rule, p.dbHandle)
|
||||
return p.normalizeError(sqlCommonAddEventRule(rule, p.dbHandle), fieldName)
|
||||
}
|
||||
|
||||
func (p *PGSQLProvider) updateEventRule(rule *EventRule) error {
|
||||
|
@ -695,7 +697,7 @@ func (p *PGSQLProvider) roleExists(name string) (Role, error) {
|
|||
}
|
||||
|
||||
func (p *PGSQLProvider) addRole(role *Role) error {
|
||||
return sqlCommonAddRole(role, p.dbHandle)
|
||||
return p.normalizeError(sqlCommonAddRole(role, p.dbHandle), fieldName)
|
||||
}
|
||||
|
||||
func (p *PGSQLProvider) updateRole(role *Role) error {
|
||||
|
@ -842,3 +844,26 @@ func (p *PGSQLProvider) resetDatabase() error {
|
|||
sql := sqlReplaceAll(pgsqlResetSQL)
|
||||
return sqlCommonExecSQLAndUpdateDBVersion(p.dbHandle, []string{sql}, 0, false)
|
||||
}
|
||||
|
||||
func (p *PGSQLProvider) normalizeError(err error, fieldType int) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
var pgsqlErr *pgconn.PgError
|
||||
if errors.As(err, &pgsqlErr) {
|
||||
switch pgsqlErr.Code {
|
||||
case "23505":
|
||||
message := util.I18nErrorDuplicatedName
|
||||
if fieldType == fieldUsername {
|
||||
message = util.I18nErrorDuplicatedUsername
|
||||
}
|
||||
return util.NewI18nError(
|
||||
fmt.Errorf("%w: %s", ErrDuplicatedKey, err.Error()),
|
||||
message,
|
||||
)
|
||||
case "23503":
|
||||
return fmt.Errorf("%w: %s", ErrForeignKeyViolated, err.Error())
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -26,8 +26,7 @@ import (
|
|||
"path/filepath"
|
||||
"time"
|
||||
|
||||
// we import go-sqlite3 here to be able to disable SQLite support using a build tag
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/mattn/go-sqlite3"
|
||||
|
||||
"github.com/drakkan/sftpgo/v2/internal/logger"
|
||||
"github.com/drakkan/sftpgo/v2/internal/util"
|
||||
|
@ -264,7 +263,7 @@ func (p *SQLiteProvider) userExists(username, role string) (User, error) {
|
|||
}
|
||||
|
||||
func (p *SQLiteProvider) addUser(user *User) error {
|
||||
return sqlCommonAddUser(user, p.dbHandle)
|
||||
return p.normalizeError(sqlCommonAddUser(user, p.dbHandle), fieldUsername)
|
||||
}
|
||||
|
||||
func (p *SQLiteProvider) updateUser(user *User) error {
|
||||
|
@ -310,7 +309,7 @@ func (p *SQLiteProvider) getFolderByName(name string) (vfs.BaseVirtualFolder, er
|
|||
}
|
||||
|
||||
func (p *SQLiteProvider) addFolder(folder *vfs.BaseVirtualFolder) error {
|
||||
return sqlCommonAddFolder(folder, p.dbHandle)
|
||||
return p.normalizeError(sqlCommonAddFolder(folder, p.dbHandle), fieldName)
|
||||
}
|
||||
|
||||
func (p *SQLiteProvider) updateFolder(folder *vfs.BaseVirtualFolder) error {
|
||||
|
@ -346,7 +345,7 @@ func (p *SQLiteProvider) groupExists(name string) (Group, error) {
|
|||
}
|
||||
|
||||
func (p *SQLiteProvider) addGroup(group *Group) error {
|
||||
return sqlCommonAddGroup(group, p.dbHandle)
|
||||
return p.normalizeError(sqlCommonAddGroup(group, p.dbHandle), fieldName)
|
||||
}
|
||||
|
||||
func (p *SQLiteProvider) updateGroup(group *Group) error {
|
||||
|
@ -366,7 +365,7 @@ func (p *SQLiteProvider) adminExists(username string) (Admin, error) {
|
|||
}
|
||||
|
||||
func (p *SQLiteProvider) addAdmin(admin *Admin) error {
|
||||
return sqlCommonAddAdmin(admin, p.dbHandle)
|
||||
return p.normalizeError(sqlCommonAddAdmin(admin, p.dbHandle), fieldUsername)
|
||||
}
|
||||
|
||||
func (p *SQLiteProvider) updateAdmin(admin *Admin) error {
|
||||
|
@ -526,7 +525,7 @@ func (p *SQLiteProvider) eventActionExists(name string) (BaseEventAction, error)
|
|||
}
|
||||
|
||||
func (p *SQLiteProvider) addEventAction(action *BaseEventAction) error {
|
||||
return sqlCommonAddEventAction(action, p.dbHandle)
|
||||
return p.normalizeError(sqlCommonAddEventAction(action, p.dbHandle), fieldName)
|
||||
}
|
||||
|
||||
func (p *SQLiteProvider) updateEventAction(action *BaseEventAction) error {
|
||||
|
@ -554,7 +553,7 @@ func (p *SQLiteProvider) eventRuleExists(name string) (EventRule, error) {
|
|||
}
|
||||
|
||||
func (p *SQLiteProvider) addEventRule(rule *EventRule) error {
|
||||
return sqlCommonAddEventRule(rule, p.dbHandle)
|
||||
return p.normalizeError(sqlCommonAddEventRule(rule, p.dbHandle), fieldName)
|
||||
}
|
||||
|
||||
func (p *SQLiteProvider) updateEventRule(rule *EventRule) error {
|
||||
|
@ -606,7 +605,7 @@ func (p *SQLiteProvider) roleExists(name string) (Role, error) {
|
|||
}
|
||||
|
||||
func (p *SQLiteProvider) addRole(role *Role) error {
|
||||
return sqlCommonAddRole(role, p.dbHandle)
|
||||
return p.normalizeError(sqlCommonAddRole(role, p.dbHandle), fieldName)
|
||||
}
|
||||
|
||||
func (p *SQLiteProvider) updateRole(role *Role) error {
|
||||
|
@ -747,6 +746,28 @@ func (p *SQLiteProvider) resetDatabase() error {
|
|||
return sqlCommonExecSQLAndUpdateDBVersion(p.dbHandle, []string{sql}, 0, false)
|
||||
}
|
||||
|
||||
func (p *SQLiteProvider) normalizeError(err error, fieldType int) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if e, ok := err.(sqlite3.Error); ok {
|
||||
switch e.ExtendedCode {
|
||||
case 1555, 2067:
|
||||
message := util.I18nErrorDuplicatedName
|
||||
if fieldType == fieldUsername {
|
||||
message = util.I18nErrorDuplicatedUsername
|
||||
}
|
||||
return util.NewI18nError(
|
||||
fmt.Errorf("%w: %s", ErrDuplicatedKey, err.Error()),
|
||||
message,
|
||||
)
|
||||
case 787:
|
||||
return fmt.Errorf("%w: %s", ErrForeignKeyViolated, err.Error())
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
/*func setPragmaFK(dbHandle *sql.DB, value string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), longSQLQueryTimeout)
|
||||
defer cancel()
|
||||
|
|
|
@ -105,6 +105,9 @@ func getRespStatus(err error) int {
|
|||
if errors.Is(err, plugin.ErrNoSearcher) || errors.Is(err, dataprovider.ErrNotImplemented) {
|
||||
return http.StatusNotImplemented
|
||||
}
|
||||
if errors.Is(err, dataprovider.ErrDuplicatedKey) || errors.Is(err, dataprovider.ErrForeignKeyViolated) {
|
||||
return http.StatusConflict
|
||||
}
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
|
||||
|
|
|
@ -600,6 +600,8 @@ func TestBasicUserHandling(t *testing.T) {
|
|||
u.Email = "user@user.com"
|
||||
user, resp, err := httpdtest.AddUser(u, http.StatusCreated)
|
||||
assert.NoError(t, err, string(resp))
|
||||
_, resp, err = httpdtest.AddUser(u, http.StatusConflict)
|
||||
assert.NoError(t, err, string(resp))
|
||||
lastPwdChange := user.LastPasswordChange
|
||||
assert.Greater(t, lastPwdChange, int64(0))
|
||||
user.MaxSessions = 10
|
||||
|
|
|
@ -189,6 +189,8 @@ const (
|
|||
I18nAddFolderTitle = "title.add_folder"
|
||||
I18nUpdateFolderTitle = "title.update_folder"
|
||||
I18nTemplateFolderTitle = "title.template_folder"
|
||||
I18nErrorDuplicatedUsername = "general.duplicated_username"
|
||||
I18nErrorDuplicatedName = "general.duplicated_name"
|
||||
)
|
||||
|
||||
// NewI18nError returns a I18nError wrappring the provided error
|
||||
|
|
|
@ -211,7 +211,9 @@
|
|||
"mandatory_encryption": "Mandatory encryption",
|
||||
"name_invalid": "The specified username is not valid, the following characters are allowed: a-zA-Z0-9-_.~",
|
||||
"associations": "Associations",
|
||||
"template_placeholders": "The following placeholders are supported"
|
||||
"template_placeholders": "The following placeholders are supported",
|
||||
"duplicated_username": "The specified username already exists",
|
||||
"duplicated_name": "The specified name already exists"
|
||||
},
|
||||
"fs": {
|
||||
"view_file": "View file \"{{- path}}\"",
|
||||
|
|
|
@ -211,7 +211,9 @@
|
|||
"mandatory_encryption": "Crittografia obbligatoria",
|
||||
"name_invalid": "Il nome specificato non è valido, sono consentiti i seguenti caratteri: a-zA-Z0-9-_.~",
|
||||
"associations": "Associazioni",
|
||||
"template_placeholders": "Sono supportati i seguenti segnaposto"
|
||||
"template_placeholders": "Sono supportati i seguenti segnaposto",
|
||||
"duplicated_username": "Il nome utente specificato esiste già",
|
||||
"duplicated_name": "Il nome specificato esiste già"
|
||||
},
|
||||
"fs": {
|
||||
"view_file": "Visualizza file \"{{- path}}\"",
|
||||
|
|
Loading…
Reference in a new issue