diff --git a/go.mod b/go.mod index 82f6c50f..02ca9f30 100644 --- a/go.mod +++ b/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.5 + github.com/aws/aws-sdk-go-v2/config v1.26.6 github.com/aws/aws-sdk-go-v2/credentials v1.16.16 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.13 + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.14 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 @@ -32,7 +32,7 @@ require ( github.com/go-sql-driver/mysql v1.7.1 github.com/golang/mock v1.6.0 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 - github.com/google/uuid v1.5.0 + github.com/google/uuid v1.6.0 github.com/hashicorp/go-hclog v1.6.2 github.com/hashicorp/go-plugin v1.6.0 github.com/hashicorp/go-retryablehttp v0.7.5 @@ -88,7 +88,7 @@ require ( github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.10 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.10 // indirect @@ -171,10 +171,10 @@ 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-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/genproto v0.0.0-20240123012728-ef4313101c80 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect + google.golang.org/grpc v1.61.0 // indirect google.golang.org/protobuf v1.32.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index f5099d80..280a7618 100644 --- a/go.sum +++ b/go.sum @@ -37,20 +37,20 @@ 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.5 h1:lodGSevz7d+kkFJodfauThRxK9mdJbyutUxGq1NNhvw= -github.com/aws/aws-sdk-go-v2/config v1.26.5/go.mod h1:DxHrz6diQJOc9EwDslVRh84VjjrE17g+pVZXUeSxaDU= +github.com/aws/aws-sdk-go-v2/config v1.26.6 h1:Z/7w9bUqlRI0FFQpetVuFYEsjzE3h7fpU6HuGmfPL/o= +github.com/aws/aws-sdk-go-v2/config v1.26.6/go.mod h1:uKU6cnDmYCvJ+pxO9S4cWDb2yWWIH5hra+32hVh1MI4= github.com/aws/aws-sdk-go-v2/credentials v1.16.16 h1:8q6Rliyv0aUFAVtzaldUEcS+T5gbadPbWdV1WcAddK8= github.com/aws/aws-sdk-go-v2/credentials v1.16.16/go.mod h1:UHVZrdUsv63hPXFo1H7c5fEneoVo9UXiz36QG1GEPi0= 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.13 h1:8Nt4LBUEKV0FxLBO2BmRzDKax3hp2LRMKySMBwL4vMc= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.13/go.mod h1:t5QEDu/FBJJM4kslbQlTSpYtnhoWDNmHSsgQojIxE0o= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.14 h1:ogP1WgyvN/qxPJkgtFMD7G2eKb5p/61Jomx+nIHXUQ4= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.14/go.mod h1:nYd/WmIrXlBHW/5QwrZP81/Gz08wKi87nV6EI1kmqx4= 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= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10/go.mod h1:6UV4SZkVvmODfXKql4LCbaZUpF7HO2BX38FgBf9ZOLw= -github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 h1:GrSw8s0Gs/5zZ0SX+gX4zQjRnRsMJDJ2sLur1gRBhEM= -github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 h1:n3GDfwqF2tzEkXlv5cuy4iy7LpKDtqDMcNLfZDu9rls= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.10 h1:5oE2WzJE56/mVveuDZPJESKlg/00AaS2pY2QZcnxg4M= github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.10/go.mod h1:FHbKWQtRBYUz4vO5WBWjzMD2by126ny5y/1EoaWoLfI= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw= @@ -91,8 +91,8 @@ github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY= +github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/cockroach-go/v2 v2.3.6 h1:Wlv9TzkrG9V7i6u8dEtmXPrBzvfFp+CgJNs696rAajM= github.com/cockroachdb/cockroach-go/v2 v2.3.6/go.mod h1:1wNJ45eSXW9AnOc3skntW9ZUZz6gxrQK3cOj3rK+BC8= github.com/coreos/go-oidc/v3 v3.9.0 h1:0J/ogVOd4y8P0f0xUh8l9t07xRP/d8tccvjHl2dcsSo= @@ -208,8 +208,8 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaU github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8= github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= @@ -531,19 +531,19 @@ 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-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/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ= +google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= +google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 h1:Lj5rbfG876hIAYFjqiJnPHfhXbv+nzTWfm04Fg/XSVU= +google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= 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= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= -google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= +google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= +google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/internal/dataprovider/bolt.go b/internal/dataprovider/bolt.go index 775d0ccd..ac731977 100644 --- a/internal/dataprovider/bolt.go +++ b/internal/dataprovider/bolt.go @@ -2827,7 +2827,10 @@ func (p *BoltProvider) addIPListEntry(entry *IPListEntry) error { return err } if e := bucket.Get([]byte(entry.getKey())); e != nil { - return fmt.Errorf("entry %q already exists", entry.IPOrNet) + return util.NewI18nError( + fmt.Errorf("entry %q already exists", entry.IPOrNet), + util.I18nErrorDuplicatedIPNet, + ) } entry.CreatedAt = util.GetTimeAsMsSinceEpoch(time.Now()) entry.UpdatedAt = util.GetTimeAsMsSinceEpoch(time.Now()) diff --git a/internal/dataprovider/dataprovider.go b/internal/dataprovider/dataprovider.go index a4230d79..a5cfafcc 100644 --- a/internal/dataprovider/dataprovider.go +++ b/internal/dataprovider/dataprovider.go @@ -151,6 +151,7 @@ const ( const ( fieldUsername = 1 fieldName = 2 + fieldIPNet = 3 ) var ( diff --git a/internal/dataprovider/iplist.go b/internal/dataprovider/iplist.go index 0558b0cf..16c68b1b 100644 --- a/internal/dataprovider/iplist.go +++ b/internal/dataprovider/iplist.go @@ -214,7 +214,7 @@ func (e *IPListEntry) validate() error { // parse as IP parsed, err := netip.ParseAddr(e.IPOrNet) if err != nil { - return util.NewValidationError(fmt.Sprintf("invalid IP %q", e.IPOrNet)) + return util.NewI18nError(util.NewValidationError(fmt.Sprintf("invalid IP %q", e.IPOrNet)), util.I18nErrorIpInvalid) } if parsed.Is4() { e.IPOrNet += "/32" @@ -226,7 +226,7 @@ func (e *IPListEntry) validate() error { } prefix, err := netip.ParsePrefix(e.IPOrNet) if err != nil { - return util.NewValidationError(fmt.Sprintf("invalid network %q: %v", e.IPOrNet, err)) + return util.NewI18nError(util.NewValidationError(fmt.Sprintf("invalid network %q: %v", e.IPOrNet, err)), util.I18nErrorNetInvalid) } prefix = prefix.Masked() if prefix.Addr().Is4In6() { @@ -235,7 +235,7 @@ func (e *IPListEntry) validate() error { // TODO: to remove when the in memory ranger switch to netip _, _, err = net.ParseCIDR(e.IPOrNet) if err != nil { - return util.NewValidationError(fmt.Sprintf("invalid network: %v", err)) + return util.NewI18nError(util.NewValidationError(fmt.Sprintf("invalid network: %v", err)), util.I18nErrorNetInvalid) } if prefix.Addr().Is4() || prefix.Addr().Is4In6() { e.IPType = ipTypeV4 diff --git a/internal/dataprovider/memory.go b/internal/dataprovider/memory.go index eb9674d1..17986b70 100644 --- a/internal/dataprovider/memory.go +++ b/internal/dataprovider/memory.go @@ -2672,7 +2672,10 @@ func (p *MemoryProvider) addIPListEntry(entry *IPListEntry) error { } _, err := p.ipListEntryExistsInternal(entry) if err == nil { - return fmt.Errorf("entry %q already exists", entry.IPOrNet) + return util.NewI18nError( + fmt.Errorf("entry %q already exists", entry.IPOrNet), + util.I18nErrorDuplicatedIPNet, + ) } entry.CreatedAt = util.GetTimeAsMsSinceEpoch(time.Now()) entry.UpdatedAt = util.GetTimeAsMsSinceEpoch(time.Now()) diff --git a/internal/dataprovider/mysql.go b/internal/dataprovider/mysql.go index f7e85cbb..342d0de0 100644 --- a/internal/dataprovider/mysql.go +++ b/internal/dataprovider/mysql.go @@ -708,7 +708,7 @@ func (p *MySQLProvider) ipListEntryExists(ipOrNet string, listType IPListType) ( } func (p *MySQLProvider) addIPListEntry(entry *IPListEntry) error { - return sqlCommonAddIPListEntry(entry, p.dbHandle) + return p.normalizeError(sqlCommonAddIPListEntry(entry, p.dbHandle), fieldIPNet) } func (p *MySQLProvider) updateIPListEntry(entry *IPListEntry) error { @@ -834,9 +834,14 @@ func (p *MySQLProvider) normalizeError(err error, fieldType int) error { if errors.As(err, &mysqlErr) { switch mysqlErr.Number { case 1062: - message := util.I18nErrorDuplicatedName - if fieldType == fieldUsername { + var message string + switch fieldType { + case fieldUsername: message = util.I18nErrorDuplicatedUsername + case fieldIPNet: + message = util.I18nErrorDuplicatedIPNet + default: + message = util.I18nErrorDuplicatedName } return util.NewI18nError( fmt.Errorf("%w: %s", ErrDuplicatedKey, err.Error()), diff --git a/internal/dataprovider/pgsql.go b/internal/dataprovider/pgsql.go index 83b60558..7e6e5853 100644 --- a/internal/dataprovider/pgsql.go +++ b/internal/dataprovider/pgsql.go @@ -721,7 +721,7 @@ func (p *PGSQLProvider) ipListEntryExists(ipOrNet string, listType IPListType) ( } func (p *PGSQLProvider) addIPListEntry(entry *IPListEntry) error { - return sqlCommonAddIPListEntry(entry, p.dbHandle) + return p.normalizeError(sqlCommonAddIPListEntry(entry, p.dbHandle), fieldIPNet) } func (p *PGSQLProvider) updateIPListEntry(entry *IPListEntry) error { @@ -853,9 +853,14 @@ func (p *PGSQLProvider) normalizeError(err error, fieldType int) error { if errors.As(err, &pgsqlErr) { switch pgsqlErr.Code { case "23505": - message := util.I18nErrorDuplicatedName - if fieldType == fieldUsername { + var message string + switch fieldType { + case fieldUsername: message = util.I18nErrorDuplicatedUsername + case fieldIPNet: + message = util.I18nErrorDuplicatedIPNet + default: + message = util.I18nErrorDuplicatedName } return util.NewI18nError( fmt.Errorf("%w: %s", ErrDuplicatedKey, err.Error()), diff --git a/internal/dataprovider/sqlite.go b/internal/dataprovider/sqlite.go index e80c3bc4..991dc9f0 100644 --- a/internal/dataprovider/sqlite.go +++ b/internal/dataprovider/sqlite.go @@ -629,7 +629,7 @@ func (p *SQLiteProvider) ipListEntryExists(ipOrNet string, listType IPListType) } func (p *SQLiteProvider) addIPListEntry(entry *IPListEntry) error { - return sqlCommonAddIPListEntry(entry, p.dbHandle) + return p.normalizeError(sqlCommonAddIPListEntry(entry, p.dbHandle), fieldIPNet) } func (p *SQLiteProvider) updateIPListEntry(entry *IPListEntry) error { @@ -753,9 +753,14 @@ func (p *SQLiteProvider) normalizeError(err error, fieldType int) error { if e, ok := err.(sqlite3.Error); ok { switch e.ExtendedCode { case 1555, 2067: - message := util.I18nErrorDuplicatedName - if fieldType == fieldUsername { + var message string + switch fieldType { + case fieldUsername: message = util.I18nErrorDuplicatedUsername + case fieldIPNet: + message = util.I18nErrorDuplicatedIPNet + default: + message = util.I18nErrorDuplicatedName } return util.NewI18nError( fmt.Errorf("%w: %s", ErrDuplicatedKey, err.Error()), diff --git a/internal/httpd/webadmin.go b/internal/httpd/webadmin.go index 2f16c4a8..8d442c35 100644 --- a/internal/httpd/webadmin.go +++ b/internal/httpd/webadmin.go @@ -102,11 +102,8 @@ const ( pageEventRulesTitle = "Event rules" pageEventActionsTitle = "Event actions" pageMaintenanceTitle = "Maintenance" - pageDefenderTitle = "Auto Blocklist" - pageIPListsTitle = "IP Lists" pageEventsTitle = "Logs" pageConfigsTitle = "Configurations" - pageSetupTitle = "Create first admin user" defaultQueryLimit = 1000 inversePatternType = "inverse" ) @@ -259,7 +256,7 @@ type ipListsPage struct { type ipListPage struct { basePage Entry *dataprovider.IPListEntry - Error string + Error *util.I18nError Mode genericPageMode } @@ -460,17 +457,17 @@ func loadAdminTemplates(templatesPath string) { filepath.Join(templatesPath, templateAdminDir, templateMaintenance), } defenderPaths := []string{ - filepath.Join(templatesPath, templateCommonDir, templateCommonCSS), + filepath.Join(templatesPath, templateCommonDir, templateCommonBase), filepath.Join(templatesPath, templateAdminDir, templateBase), filepath.Join(templatesPath, templateAdminDir, templateDefender), } ipListsPaths := []string{ - filepath.Join(templatesPath, templateCommonDir, templateCommonCSS), + filepath.Join(templatesPath, templateCommonDir, templateCommonBase), filepath.Join(templatesPath, templateAdminDir, templateBase), filepath.Join(templatesPath, templateAdminDir, templateIPLists), } ipListPaths := []string{ - filepath.Join(templatesPath, templateCommonDir, templateCommonCSS), + filepath.Join(templatesPath, templateCommonDir, templateCommonBase), filepath.Join(templatesPath, templateAdminDir, templateBase), filepath.Join(templatesPath, templateAdminDir, templateIPList), } @@ -997,20 +994,20 @@ func (s *httpdServer) renderUserPage(w http.ResponseWriter, r *http.Request, use } func (s *httpdServer) renderIPListPage(w http.ResponseWriter, r *http.Request, entry dataprovider.IPListEntry, - mode genericPageMode, error string, + mode genericPageMode, err error, ) { var title, currentURL string switch mode { case genericPageModeAdd: - title = "Add a new IP List entry" + title = util.I18nAddIPListTitle currentURL = fmt.Sprintf("%s/%d", webIPListPath, entry.Type) case genericPageModeUpdate: - title = "Update IP List entry" + title = util.I18nUpdateIPListTitle currentURL = fmt.Sprintf("%s/%d/%s", webIPListPath, entry.Type, url.PathEscape(entry.IPOrNet)) } data := ipListPage{ basePage: s.getBasePageData(title, currentURL, r), - Error: error, + Error: getI18nError(err), Entry: &entry, Mode: mode, } @@ -2955,7 +2952,7 @@ func (s *httpdServer) handleWebUpdateAdminPost(w http.ResponseWriter, r *http.Re func (s *httpdServer) handleWebDefenderPage(w http.ResponseWriter, r *http.Request) { r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize) data := defenderHostsPage{ - basePage: s.getBasePageData(pageDefenderTitle, webDefenderPath, r), + basePage: s.getBasePageData(util.I18nDefenderTitle, webDefenderPath, r), DefenderHostsURL: webDefenderHostsPath, } @@ -3986,7 +3983,7 @@ func (s *httpdServer) handleWebIPListsPage(w http.ResponseWriter, r *http.Reques r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize) rtlStatus, rtlProtocols := common.Config.GetRateLimitersStatus() data := ipListsPage{ - basePage: s.getBasePageData(pageIPListsTitle, webIPListsPath, r), + basePage: s.getBasePageData(util.I18nIPListsTitle, webIPListsPath, r), RateLimitersStatus: rtlStatus, RateLimitersProtocols: strings.Join(rtlProtocols, ", "), IsAllowListEnabled: common.Config.IsAllowListEnabled(), @@ -4002,7 +3999,7 @@ func (s *httpdServer) handleWebAddIPListEntryGet(w http.ResponseWriter, r *http. s.renderBadRequestPage(w, r, err) return } - s.renderIPListPage(w, r, dataprovider.IPListEntry{Type: listType}, genericPageModeAdd, "") + s.renderIPListPage(w, r, dataprovider.IPListEntry{Type: listType}, genericPageModeAdd, nil) } func (s *httpdServer) handleWebAddIPListEntryPost(w http.ResponseWriter, r *http.Request) { @@ -4014,7 +4011,7 @@ func (s *httpdServer) handleWebAddIPListEntryPost(w http.ResponseWriter, r *http } entry, err := getIPListEntryFromPostFields(r, listType) if err != nil { - s.renderIPListPage(w, r, entry, genericPageModeAdd, err.Error()) + s.renderIPListPage(w, r, entry, genericPageModeAdd, err) return } entry.Type = listType @@ -4030,7 +4027,7 @@ func (s *httpdServer) handleWebAddIPListEntryPost(w http.ResponseWriter, r *http } err = dataprovider.AddIPListEntry(&entry, claims.Username, ipAddr, claims.Role) if err != nil { - s.renderIPListPage(w, r, entry, genericPageModeAdd, err.Error()) + s.renderIPListPage(w, r, entry, genericPageModeAdd, err) return } http.Redirect(w, r, webIPListsPath, http.StatusSeeOther) @@ -4045,7 +4042,7 @@ func (s *httpdServer) handleWebUpdateIPListEntryGet(w http.ResponseWriter, r *ht } entry, err := dataprovider.IPListEntryExists(ipOrNet, listType) if err == nil { - s.renderIPListPage(w, r, entry, genericPageModeUpdate, "") + s.renderIPListPage(w, r, entry, genericPageModeUpdate, nil) } else if errors.Is(err, util.ErrNotFound) { s.renderNotFoundPage(w, r, err) } else { @@ -4075,7 +4072,7 @@ func (s *httpdServer) handleWebUpdateIPListEntryPost(w http.ResponseWriter, r *h } updatedEntry, err := getIPListEntryFromPostFields(r, listType) if err != nil { - s.renderIPListPage(w, r, entry, genericPageModeUpdate, err.Error()) + s.renderIPListPage(w, r, entry, genericPageModeUpdate, err) return } ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr) @@ -4087,7 +4084,7 @@ func (s *httpdServer) handleWebUpdateIPListEntryPost(w http.ResponseWriter, r *h updatedEntry.IPOrNet = ipOrNet err = dataprovider.UpdateIPListEntry(&updatedEntry, claims.Username, ipAddr, claims.Role) if err != nil { - s.renderIPListPage(w, r, entry, genericPageModeUpdate, err.Error()) + s.renderIPListPage(w, r, entry, genericPageModeUpdate, err) return } http.Redirect(w, r, webIPListsPath, http.StatusSeeOther) diff --git a/internal/util/i18n.go b/internal/util/i18n.go index 1c602f15..e3dbf1c3 100644 --- a/internal/util/i18n.go +++ b/internal/util/i18n.go @@ -63,6 +63,10 @@ const ( I18nSessionsTitle = "title.connections" I18nRolesTitle = "title.roles" I18nAdminsTitle = "title.admins" + I18nIPListsTitle = "title.ip_lists" + I18nAddIPListTitle = "title.add_ip_list" + I18nUpdateIPListTitle = "title.update_ip_list" + I18nDefenderTitle = "title.defender" I18nErrorSetupInstallCode = "setup.install_code_mismatch" I18nInvalidAuth = "general.invalid_auth_request" I18nError429Message = "general.error429" @@ -204,6 +208,7 @@ const ( I18nTemplateFolderTitle = "title.template_folder" I18nErrorDuplicatedUsername = "general.duplicated_username" I18nErrorDuplicatedName = "general.duplicated_name" + I18nErrorDuplicatedIPNet = "ip_list.duplicated" I18nErrorRoleAdminPerms = "admin.role_permissions" I18nBackupOK = "general.backup_ok" I18nErrorFolderTemplate = "virtual_folders.template_no_folder" @@ -218,6 +223,8 @@ const ( I18nErrorAdminSelfPerms = "admin.self_permissions" I18nErrorAdminSelfDisable = "admin.self_disable" I18nErrorAdminSelfRole = "admin.self_role" + I18nErrorIpInvalid = "ip_list.ip_invalid" + I18nErrorNetInvalid = "ip_list.net_invalid" ) // NewI18nError returns a I18nError wrappring the provided error diff --git a/static/locales/en/translation.json b/static/locales/en/translation.json index 6528ef1c..b580d0ae 100644 --- a/static/locales/en/translation.json +++ b/static/locales/en/translation.json @@ -58,7 +58,9 @@ "add_role": "Add role", "update_role": "Update role", "add_admin": "Add admin", - "update_admin": "Update admin" + "update_admin": "Update admin", + "add_ip_list": "Add IP list entry", + "update_ip_list": "Update IP list entry" }, "setup": { "desc": "To start using SFTPGo you need to create an administrator user", @@ -229,7 +231,10 @@ "members": "Members", "members_summary": "Users: {{users}}. Admins: {{admins}}", "status": "Status", - "last_login": "Last login" + "last_login": "Last login", + "previous": "Previous", + "next": "Next", + "type": "Type" }, "fs": { "view_file": "View file \"{{- path}}\"", @@ -710,5 +715,31 @@ }, "role": { "view_manage": "View and manage roles" + }, + "ip_list": { + "view_manage": "View and manage IP lists", + "defender_list": "Defender", + "allow_list": "Allow list", + "ratelimiters_safe_list": "Rate limiters safe list", + "ip_net": "IP/Network", + "protocols": "Protocols", + "mode": "Mode", + "any": "Any", + "allow": "Allow", + "deny": "Deny", + "ip_net_help": "IP address or network in CIDR format, example: \"192.168.1.1 or 10.8.0.100/32 or 2001:db8:1234::/48\"", + "ip_invalid": "Invalid IP address", + "net_invalid": "Invalid network", + "duplicated": "The specified IP/network already exists", + "search": "IP/Network or initial part", + "defender_disabled": "Defender disabled in your configuration", + "allow_list_disabled": "Allow list disabled in your configuration", + "ratelimiters_disabled": "Rate limiters disabled in your configuration" + }, + "defender": { + "view_manage": "View and manage auto blocklist", + "ip": "IP address", + "ban_time": "Blocked until", + "score": "Score" } } \ No newline at end of file diff --git a/static/locales/it/translation.json b/static/locales/it/translation.json index cda3c547..e51b1925 100644 --- a/static/locales/it/translation.json +++ b/static/locales/it/translation.json @@ -58,7 +58,9 @@ "add_role": "Aggiungi ruolo", "update_role": "Aggiorna ruolo", "add_admin": "Aggiungi amministratore", - "update_admin": "Aggiorna amministratore" + "update_admin": "Aggiorna amministratore", + "add_ip_list": "Aggiungi elemento a lista IP", + "update_ip_list": "Aggiorna elemento lista IP" }, "setup": { "desc": "Per iniziare a utilizzare SFTPGo devi creare un utente amministratore", @@ -229,7 +231,10 @@ "members": "Membri", "members_summary": "Utenti: {{users}}. Amministratori: {{admins}}", "status": "Stato", - "last_login": "Ultimo accesso" + "last_login": "Ultimo accesso", + "previous": "Precedente", + "next": "Successivo", + "type": "Tipo" }, "fs": { "view_file": "Visualizza file \"{{- path}}\"", @@ -710,5 +715,31 @@ }, "role": { "view_manage": "Visualizza e gestisci ruoli" + }, + "ip_list": { + "view_manage": "Visualizza e gestisci liste IP", + "defender_list": "Defender", + "allow_list": "Lista IP consentiti", + "ratelimiters_safe_list": "Lista IP esclusi dai rate limiters", + "ip_net": "IP/Rete", + "protocols": "Protocolli", + "mode": "Modalità ", + "any": "Qualunque", + "allow": "Permesso", + "deny": "Non permesso", + "ip_net_help": "Indirizzo IP o rete in formato CIDR, ad esempio: \"192.168.1.1 o 10.8.0.100/32 o 2001:db8:1234::/48\"", + "ip_invalid": "Indirizzo IP non valido", + "net_invalid": "Rete non valida", + "duplicated": "L'IP/Rete specificato esiste già ", + "search": "IP/Rete o parte iniziale", + "defender_disabled": "Defender disabilitato in configurazione", + "allow_list_disabled": "Lista IP consentiti disabilitata in configurazione", + "ratelimiters_disabled": "Rate limiters disabilitati in configurazione" + }, + "defender": { + "view_manage": "Visualizza e gestisci la blocklist automatica", + "ip": "Indirizzo IP", + "ban_time": "Bloccato fino a", + "score": "Punteggio" } } \ No newline at end of file diff --git a/templates/webadmin/connections.html b/templates/webadmin/connections.html index a1c0d806..ff9ac14e 100644 --- a/templates/webadmin/connections.html +++ b/templates/webadmin/connections.html @@ -70,7 +70,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com). -
ID | -IP | -Ban time | -Score | +
---|---|---|---|
IP | +Blocked until | +Score | +