mirror of
https://github.com/drakkan/sftpgo.git
synced 2024-11-25 00:50:31 +00:00
REST API: remove merging of fields on updates
we use PUT verb not PATCH. We keep merging only to allow to preserve hidden/encrypted fields. This is a backward incompatible change, but is necessary to avoid unexpected issues. You have to pass complete objects on updates. Fixes #1088 Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
parent
e17975ed7d
commit
0841c7d7bd
12 changed files with 173 additions and 231 deletions
14
go.mod
14
go.mod
|
@ -9,13 +9,13 @@ require (
|
|||
github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962
|
||||
github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387
|
||||
github.com/aws/aws-sdk-go-v2 v1.17.3
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.6
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.6
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.7
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.7
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.21
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.45
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.46
|
||||
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.13.26
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.29.6
|
||||
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.16.10
|
||||
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.16.11
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.17.7
|
||||
github.com/cockroachdb/cockroach-go/v2 v2.2.19
|
||||
github.com/coreos/go-oidc/v3 v3.4.0
|
||||
|
@ -92,7 +92,7 @@ require (
|
|||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.22 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.21 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.21 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.27 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.28 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.11 // indirect
|
||||
github.com/aws/smithy-go v1.13.5 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
|
@ -144,7 +144,7 @@ require (
|
|||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.39.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/prometheus/procfs v0.9.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
|
@ -171,5 +171,5 @@ require (
|
|||
replace (
|
||||
github.com/fclairamb/ftpserverlib => github.com/drakkan/ftpserverlib v0.0.0-20221203115213-ba73c775a9fd
|
||||
github.com/jlaffaye/ftp => github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9
|
||||
golang.org/x/crypto => github.com/drakkan/crypto v0.0.0-20221220153730-5f47589cce28
|
||||
golang.org/x/crypto => github.com/drakkan/crypto v0.0.0-20221223081523-be6917ff6f72
|
||||
)
|
||||
|
|
28
go.sum
28
go.sum
|
@ -233,17 +233,17 @@ github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3/go.mod h1:gNsR5CaXK
|
|||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.15.15/go.mod h1:A1Lzyy/o21I5/s2FbyX5AevQfSVXpvvIDCoVFD0BC4E=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.6 h1:iSuEAeervBWMHA7Aaq5hCNfwuN2m7x2VuQCnEbbQg68=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.6/go.mod h1:qyjgnyqpKnNGT+C62zMsrZ/Mn2OodYqwIH0DpXiW8f8=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.7 h1:V94lTcix6jouwmAsgQMAEBozVAGJMFhVj+6/++xfe3E=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.7/go.mod h1:OZYsyHFL5PB9UpyS78NElgKs11qI/B5KJau2XOJDXHA=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.12.10/go.mod h1:g5eIM5XRs/OzIIK81QMBl+dAuDyoLN0VYaLP+tBqEOk=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.6 h1:BXOMvv3O82/4JLggIi67WKlTO56f0rliCKBT4CKyf0o=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.6/go.mod h1:VbnUvhw31DUu6aiubViixQwWCBNO/st84dhPeOkmdls=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.7 h1:qUUcNS5Z1092XBFT66IJM7mYkMwgZ8fcC8YDIbEwXck=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.7/go.mod h1:AdCcbZXHQCjJh6NaH3pFaw8LUeBFn5+88BZGMVGuBT8=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.9/go.mod h1:KDCCm4ONIdHtUloDcFvK2+vshZvx4Zmj7UMDfusuz5s=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.21 h1:j9wi1kQ8b+e0FBVHxCqCGo4kxDU175hoDHcWAi0sauU=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.21/go.mod h1:ugwW57Z5Z48bpvUyZuaPy4Kv+vEfJWnIrky7RmkBvJg=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.21/go.mod h1:iIYPrQ2rYfZiB/iADYlhj9HHZ9TTi6PqKQPAqygohbE=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.45 h1:ckFtXy51PT613d/KLKPxFiwRqgGIxDhVbNLof6x/XLo=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.45/go.mod h1:xar61xizdVU4pQygvQrNdZY1VCLNcOIvm87KzdZmWrE=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.46 h1:OCX1pQ4pcqhsDV7B92HzdLWjHWOQsILvjLinpaUWhcc=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.46/go.mod h1:MxCBOcyNXGJRvfpPiH+L6n/BF9zbowthGSUZdDvQF/c=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.15/go.mod h1:pWrr2OoHlT7M/Pd2y4HV3gJyPb3qj5qMmnPkKSNPYK4=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27 h1:I3cakv2Uy1vNmmhRQmFptYDxOvBnwCdNwyw63N0RaRU=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27/go.mod h1:a1/UpzeyBBerajpnP5nGZa9mGzsBn5cOKxm6NWQsvoI=
|
||||
|
@ -275,14 +275,14 @@ github.com/aws/aws-sdk-go-v2/service/s3 v1.27.2/go.mod h1:u+566cosFI+d+motIz3USX
|
|||
github.com/aws/aws-sdk-go-v2/service/s3 v1.29.6 h1:W8pLcSn6Uy0eXgDBUUl8M8Kxv7JCoP68ZKTD04OXLEA=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.29.6/go.mod h1:L2l2/q76teehcW7YEsgsDjqdsDTERJeX3nOMIFlgGUE=
|
||||
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.15.14/go.mod h1:xakbH8KMsQQKqzX87uyyzTHshc/0/Df8bsTneTS5pFU=
|
||||
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.16.10 h1:6obimjQAiRlEUZT7a2Q1ikH7ck4cPO3phGz4wqI5f2w=
|
||||
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.16.10/go.mod h1:jAeo/PdIJZuDSwsvxJS94G4d6h8tStj7WXVuKwLHWU8=
|
||||
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.16.11 h1:77V7vnw/NC4DORHVgA97+Ky2p1ri0+ZVYXh6ordUZU0=
|
||||
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.16.11/go.mod h1:jAeo/PdIJZuDSwsvxJS94G4d6h8tStj7WXVuKwLHWU8=
|
||||
github.com/aws/aws-sdk-go-v2/service/sns v1.17.10/go.mod h1:uITsRNVMeCB3MkWpXxXw0eDz8pW4TYLzj+eyQtbhSxM=
|
||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.19.1/go.mod h1:A94o564Gj+Yn+7QO1eLFeI7UVv3riy/YBFOfICVqFvU=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssm v1.27.6/go.mod h1:fiFzQgj4xNOg4/wqmAiPvzgDMXPD+cUEplX/CYn+0j0=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.13/go.mod h1:d7ptRksDDgvXaUvxyHZ9SYh+iMDymm94JbVcgvSYSzU=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.27 h1:Nmvn0DJKg00TBmoBweK253Kdsuy4V5Rs68yL/H15uBQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.27/go.mod h1:wo/B7uUm/7zw/dWhBJ4FXuw1sySU5lyIhVg1Bu2yL9A=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.28 h1:gItLq3zBYyRDPmqAClgzTH8PBjDQGeyptYGHIwtYYNA=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.28/go.mod h1:wo/B7uUm/7zw/dWhBJ4FXuw1sySU5lyIhVg1Bu2yL9A=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.11 h1:KCacyVSs/wlcPGx37hcbT3IGYO8P8Jx+TgSDhAXtQMY=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.11/go.mod h1:TZSH7xLO7+phDtViY/KUp9WGCJMQkLJ/VpgkTFd5gh8=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.16.10/go.mod h1:cftkHYN6tCDNfkSasAmclSfl4l7cySoay8vz7p/ce0E=
|
||||
|
@ -538,8 +538,8 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD
|
|||
github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
|
||||
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
github.com/drakkan/crypto v0.0.0-20221220153730-5f47589cce28 h1:QTEjJpZpyqRFlN4Yh9GIumPHDJ9LYWka9aWRPz1RiOk=
|
||||
github.com/drakkan/crypto v0.0.0-20221220153730-5f47589cce28/go.mod h1:cy6DFZ6nHFw1bTHZksT/gYKmdxPdzr7Rw7xcJFSayo4=
|
||||
github.com/drakkan/crypto v0.0.0-20221223081523-be6917ff6f72 h1:Ivant8yrd81A5y3tQOS7vqwL9QaOdlGonHNOfRR3rsQ=
|
||||
github.com/drakkan/crypto v0.0.0-20221223081523-be6917ff6f72/go.mod h1:cy6DFZ6nHFw1bTHZksT/gYKmdxPdzr7Rw7xcJFSayo4=
|
||||
github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9 h1:LPH1dEblAOO/LoG7yHPMtBLXhQmjaga91/DDjWk9jWA=
|
||||
github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9/go.mod h1:2lmrmq866uF2tnje75wQHzmPXhmSWUt7Gyx2vgK1RCU=
|
||||
github.com/drakkan/ftpserverlib v0.0.0-20221203115213-ba73c775a9fd h1:wu/ys+33GwD9PyRO8QDCUpI2WBZtwFiDk8QkFPW8rhQ=
|
||||
|
@ -1409,8 +1409,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
|
|||
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
|
||||
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
|
||||
github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
|
||||
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
|
||||
github.com/prometheus/prometheus v0.35.0/go.mod h1:7HaLx5kEPKJ0GDgbODG0fZgXbQ8K/XjZNJXQmbmgQlY=
|
||||
github.com/prometheus/prometheus v0.37.0/go.mod h1:egARUgz+K93zwqsVIAneFlLZefyGOON44WyAp4Xqbbk=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
|
|
|
@ -116,13 +116,8 @@ func updateAdmin(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
adminID := admin.ID
|
||||
username = admin.Username
|
||||
totpConfig := admin.Filters.TOTPConfig
|
||||
recoveryCodes := admin.Filters.RecoveryCodes
|
||||
admin.Filters.TOTPConfig = dataprovider.AdminTOTPConfig{}
|
||||
admin.Filters.RecoveryCodes = nil
|
||||
err = render.DecodeJSON(r.Body, &admin)
|
||||
var updatedAdmin dataprovider.Admin
|
||||
err = render.DecodeJSON(r.Body, &updatedAdmin)
|
||||
if err != nil {
|
||||
sendAPIResponse(w, r, err, "", http.StatusBadRequest)
|
||||
return
|
||||
|
@ -139,24 +134,28 @@ func updateAdmin(w http.ResponseWriter, r *http.Request) {
|
|||
http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if claims.isCriticalPermRemoved(admin.Permissions) {
|
||||
if claims.isCriticalPermRemoved(updatedAdmin.Permissions) {
|
||||
sendAPIResponse(w, r, errors.New("you cannot remove these permissions to yourself"), "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if admin.Status == 0 {
|
||||
if updatedAdmin.Status == 0 {
|
||||
sendAPIResponse(w, r, errors.New("you cannot disable yourself"), "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if admin.Role != claims.Role {
|
||||
if updatedAdmin.Role != claims.Role {
|
||||
sendAPIResponse(w, r, errors.New("you cannot add/change your role"), "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
admin.ID = adminID
|
||||
admin.Username = username
|
||||
admin.Filters.TOTPConfig = totpConfig
|
||||
admin.Filters.RecoveryCodes = recoveryCodes
|
||||
if err := dataprovider.UpdateAdmin(&admin, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role); err != nil {
|
||||
updatedAdmin.ID = admin.ID
|
||||
updatedAdmin.Username = admin.Username
|
||||
if updatedAdmin.Password == "" {
|
||||
updatedAdmin.Password = admin.Password
|
||||
}
|
||||
updatedAdmin.Filters.TOTPConfig = admin.Filters.TOTPConfig
|
||||
updatedAdmin.Filters.RecoveryCodes = admin.Filters.RecoveryCodes
|
||||
err = dataprovider.UpdateAdmin(&updatedAdmin, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role)
|
||||
if err != nil {
|
||||
sendAPIResponse(w, r, err, "", getRespStatus(err))
|
||||
return
|
||||
}
|
||||
|
|
|
@ -96,32 +96,30 @@ func updateEventAction(w http.ResponseWriter, r *http.Request) {
|
|||
sendAPIResponse(w, r, err, "", getRespStatus(err))
|
||||
return
|
||||
}
|
||||
actionID := action.ID
|
||||
name = action.Name
|
||||
currentHTTPPassword := action.Options.HTTPConfig.Password
|
||||
action.Options = dataprovider.BaseEventActionOptions{}
|
||||
|
||||
err = render.DecodeJSON(r.Body, &action)
|
||||
var updatedAction dataprovider.BaseEventAction
|
||||
err = render.DecodeJSON(r.Body, &updatedAction)
|
||||
if err != nil {
|
||||
sendAPIResponse(w, r, err, "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
action.ID = actionID
|
||||
action.Name = name
|
||||
action.Options.SetEmptySecretsIfNil()
|
||||
switch action.Type {
|
||||
updatedAction.ID = action.ID
|
||||
updatedAction.Name = action.Name
|
||||
updatedAction.Options.SetEmptySecretsIfNil()
|
||||
|
||||
switch updatedAction.Type {
|
||||
case dataprovider.ActionTypeHTTP:
|
||||
if action.Options.HTTPConfig.Password.IsNotPlainAndNotEmpty() {
|
||||
action.Options.HTTPConfig.Password = currentHTTPPassword
|
||||
if updatedAction.Options.HTTPConfig.Password.IsNotPlainAndNotEmpty() {
|
||||
updatedAction.Options.HTTPConfig.Password = action.Options.HTTPConfig.Password
|
||||
}
|
||||
}
|
||||
|
||||
err = dataprovider.UpdateEventAction(&action, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role)
|
||||
err = dataprovider.UpdateEventAction(&updatedAction, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role)
|
||||
if err != nil {
|
||||
sendAPIResponse(w, r, err, "", getRespStatus(err))
|
||||
return
|
||||
}
|
||||
sendAPIResponse(w, r, nil, "Event target updated", http.StatusOK)
|
||||
sendAPIResponse(w, r, nil, "Event action updated", http.StatusOK)
|
||||
}
|
||||
|
||||
func deleteEventAction(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -206,25 +204,22 @@ func updateEventRule(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
name := getURLParam(r, "name")
|
||||
rule, err := dataprovider.EventRuleExists(name)
|
||||
rule, err := dataprovider.EventRuleExists(getURLParam(r, "name"))
|
||||
if err != nil {
|
||||
sendAPIResponse(w, r, err, "", getRespStatus(err))
|
||||
return
|
||||
}
|
||||
ruleID := rule.ID
|
||||
name = rule.Name
|
||||
rule.Actions = nil
|
||||
|
||||
err = render.DecodeJSON(r.Body, &rule)
|
||||
var updatedRule dataprovider.EventRule
|
||||
err = render.DecodeJSON(r.Body, &updatedRule)
|
||||
if err != nil {
|
||||
sendAPIResponse(w, r, err, "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
rule.ID = ruleID
|
||||
rule.Name = name
|
||||
updatedRule.ID = rule.ID
|
||||
updatedRule.Name = rule.Name
|
||||
|
||||
err = dataprovider.UpdateEventRule(&rule, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role)
|
||||
err = dataprovider.UpdateEventRule(&updatedRule, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role)
|
||||
if err != nil {
|
||||
sendAPIResponse(w, r, err, "", getRespStatus(err))
|
||||
return
|
||||
|
|
|
@ -76,39 +76,23 @@ func updateFolder(w http.ResponseWriter, r *http.Request) {
|
|||
sendAPIResponse(w, r, err, "", getRespStatus(err))
|
||||
return
|
||||
}
|
||||
users := folder.Users
|
||||
groups := folder.Groups
|
||||
folderID := folder.ID
|
||||
name = folder.Name
|
||||
currentS3AccessSecret := folder.FsConfig.S3Config.AccessSecret
|
||||
currentAzAccountKey := folder.FsConfig.AzBlobConfig.AccountKey
|
||||
currentAzSASUrl := folder.FsConfig.AzBlobConfig.SASURL
|
||||
currentGCSCredentials := folder.FsConfig.GCSConfig.Credentials
|
||||
currentCryptoPassphrase := folder.FsConfig.CryptConfig.Passphrase
|
||||
currentSFTPPassword := folder.FsConfig.SFTPConfig.Password
|
||||
currentSFTPKey := folder.FsConfig.SFTPConfig.PrivateKey
|
||||
currentSFTPKeyPassphrase := folder.FsConfig.SFTPConfig.KeyPassphrase
|
||||
currentHTTPPassword := folder.FsConfig.HTTPConfig.Password
|
||||
currentHTTPAPIKey := folder.FsConfig.HTTPConfig.APIKey
|
||||
|
||||
folder.FsConfig.S3Config = vfs.S3FsConfig{}
|
||||
folder.FsConfig.AzBlobConfig = vfs.AzBlobFsConfig{}
|
||||
folder.FsConfig.GCSConfig = vfs.GCSFsConfig{}
|
||||
folder.FsConfig.CryptConfig = vfs.CryptFsConfig{}
|
||||
folder.FsConfig.SFTPConfig = vfs.SFTPFsConfig{}
|
||||
folder.FsConfig.HTTPConfig = vfs.HTTPFsConfig{}
|
||||
err = render.DecodeJSON(r.Body, &folder)
|
||||
var updatedFolder vfs.BaseVirtualFolder
|
||||
err = render.DecodeJSON(r.Body, &updatedFolder)
|
||||
if err != nil {
|
||||
sendAPIResponse(w, r, err, "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
folder.ID = folderID
|
||||
folder.Name = name
|
||||
folder.FsConfig.SetEmptySecretsIfNil()
|
||||
updateEncryptedSecrets(&folder.FsConfig, currentS3AccessSecret, currentAzAccountKey, currentAzSASUrl, currentGCSCredentials,
|
||||
currentCryptoPassphrase, currentSFTPPassword, currentSFTPKey, currentSFTPKeyPassphrase, currentHTTPPassword,
|
||||
currentHTTPAPIKey)
|
||||
err = dataprovider.UpdateFolder(&folder, users, groups, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role)
|
||||
updatedFolder.ID = folder.ID
|
||||
updatedFolder.Name = folder.Name
|
||||
updatedFolder.FsConfig.SetEmptySecretsIfNil()
|
||||
updateEncryptedSecrets(&updatedFolder.FsConfig, folder.FsConfig.S3Config.AccessSecret, folder.FsConfig.AzBlobConfig.AccountKey,
|
||||
folder.FsConfig.AzBlobConfig.SASURL, folder.FsConfig.GCSConfig.Credentials, folder.FsConfig.CryptConfig.Passphrase,
|
||||
folder.FsConfig.SFTPConfig.Password, folder.FsConfig.SFTPConfig.PrivateKey, folder.FsConfig.SFTPConfig.KeyPassphrase,
|
||||
folder.FsConfig.HTTPConfig.Password, folder.FsConfig.HTTPConfig.APIKey)
|
||||
|
||||
err = dataprovider.UpdateFolder(&updatedFolder, folder.Users, folder.Groups, claims.Username,
|
||||
util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role)
|
||||
if err != nil {
|
||||
sendAPIResponse(w, r, err, "", getRespStatus(err))
|
||||
return
|
||||
|
|
|
@ -22,7 +22,6 @@ import (
|
|||
|
||||
"github.com/drakkan/sftpgo/v2/internal/dataprovider"
|
||||
"github.com/drakkan/sftpgo/v2/internal/util"
|
||||
"github.com/drakkan/sftpgo/v2/internal/vfs"
|
||||
)
|
||||
|
||||
func getGroups(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -76,9 +75,7 @@ func updateGroup(w http.ResponseWriter, r *http.Request) {
|
|||
sendAPIResponse(w, r, err, "", getRespStatus(err))
|
||||
return
|
||||
}
|
||||
users := group.Users
|
||||
groupID := group.ID
|
||||
name = group.Name
|
||||
|
||||
currentS3AccessSecret := group.UserSettings.FsConfig.S3Config.AccessSecret
|
||||
currentAzAccountKey := group.UserSettings.FsConfig.AzBlobConfig.AccountKey
|
||||
currentAzSASUrl := group.UserSettings.FsConfig.AzBlobConfig.SASURL
|
||||
|
@ -90,24 +87,20 @@ func updateGroup(w http.ResponseWriter, r *http.Request) {
|
|||
currentHTTPPassword := group.UserSettings.FsConfig.HTTPConfig.Password
|
||||
currentHTTPAPIKey := group.UserSettings.FsConfig.HTTPConfig.APIKey
|
||||
|
||||
group.UserSettings.FsConfig.S3Config = vfs.S3FsConfig{}
|
||||
group.UserSettings.FsConfig.AzBlobConfig = vfs.AzBlobFsConfig{}
|
||||
group.UserSettings.FsConfig.GCSConfig = vfs.GCSFsConfig{}
|
||||
group.UserSettings.FsConfig.CryptConfig = vfs.CryptFsConfig{}
|
||||
group.UserSettings.FsConfig.SFTPConfig = vfs.SFTPFsConfig{}
|
||||
group.UserSettings.FsConfig.HTTPConfig = vfs.HTTPFsConfig{}
|
||||
err = render.DecodeJSON(r.Body, &group)
|
||||
var updatedGroup dataprovider.Group
|
||||
err = render.DecodeJSON(r.Body, &updatedGroup)
|
||||
if err != nil {
|
||||
sendAPIResponse(w, r, err, "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
group.ID = groupID
|
||||
group.Name = name
|
||||
group.UserSettings.FsConfig.SetEmptySecretsIfNil()
|
||||
updateEncryptedSecrets(&group.UserSettings.FsConfig, currentS3AccessSecret, currentAzAccountKey, currentAzSASUrl,
|
||||
updatedGroup.ID = group.ID
|
||||
updatedGroup.Name = group.Name
|
||||
updatedGroup.UserSettings.FsConfig.SetEmptySecretsIfNil()
|
||||
updateEncryptedSecrets(&updatedGroup.UserSettings.FsConfig, currentS3AccessSecret, currentAzAccountKey, currentAzSASUrl,
|
||||
currentGCSCredentials, currentCryptoPassphrase, currentSFTPPassword, currentSFTPKey, currentSFTPKeyPassphrase,
|
||||
currentHTTPPassword, currentHTTPAPIKey)
|
||||
err = dataprovider.UpdateGroup(&group, users, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role)
|
||||
err = dataprovider.UpdateGroup(&updatedGroup, group.Users, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr),
|
||||
claims.Role)
|
||||
if err != nil {
|
||||
sendAPIResponse(w, r, err, "", getRespStatus(err))
|
||||
return
|
||||
|
|
|
@ -98,14 +98,17 @@ func updateAPIKey(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
err = render.DecodeJSON(r.Body, &apiKey)
|
||||
var updatedAPIKey dataprovider.APIKey
|
||||
err = render.DecodeJSON(r.Body, &updatedAPIKey)
|
||||
if err != nil {
|
||||
sendAPIResponse(w, r, err, "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
apiKey.KeyID = keyID
|
||||
if err := dataprovider.UpdateAPIKey(&apiKey, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role); err != nil {
|
||||
updatedAPIKey.KeyID = keyID
|
||||
updatedAPIKey.Key = apiKey.Key
|
||||
err = dataprovider.UpdateAPIKey(&updatedAPIKey, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role)
|
||||
if err != nil {
|
||||
sendAPIResponse(w, r, err, "", getRespStatus(err))
|
||||
return
|
||||
}
|
||||
|
|
|
@ -75,16 +75,17 @@ func updateRole(w http.ResponseWriter, r *http.Request) {
|
|||
sendAPIResponse(w, r, err, "", getRespStatus(err))
|
||||
return
|
||||
}
|
||||
roleID := role.ID
|
||||
name = role.Name
|
||||
err = render.DecodeJSON(r.Body, &role)
|
||||
|
||||
var updatedRole dataprovider.Role
|
||||
err = render.DecodeJSON(r.Body, &updatedRole)
|
||||
if err != nil {
|
||||
sendAPIResponse(w, r, err, "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
role.ID = roleID
|
||||
role.Name = name
|
||||
err = dataprovider.UpdateRole(&role, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role)
|
||||
|
||||
updatedRole.ID = role.ID
|
||||
updatedRole.Name = role.Name
|
||||
err = dataprovider.UpdateRole(&updatedRole, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role)
|
||||
if err != nil {
|
||||
sendAPIResponse(w, r, err, "", getRespStatus(err))
|
||||
return
|
||||
|
|
|
@ -131,26 +131,27 @@ func updateShare(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
oldPassword := share.Password
|
||||
err = render.DecodeJSON(r.Body, &share)
|
||||
var updatedShare dataprovider.Share
|
||||
err = render.DecodeJSON(r.Body, &updatedShare)
|
||||
if err != nil {
|
||||
sendAPIResponse(w, r, err, "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
share.ShareID = shareID
|
||||
share.Username = claims.Username
|
||||
if share.Password == redactedSecret {
|
||||
share.Password = oldPassword
|
||||
updatedShare.ShareID = shareID
|
||||
updatedShare.Username = claims.Username
|
||||
if updatedShare.Password == redactedSecret {
|
||||
updatedShare.Password = share.Password
|
||||
}
|
||||
if share.Password == "" {
|
||||
if updatedShare.Password == "" {
|
||||
if util.Contains(claims.Permissions, sdk.WebClientShareNoPasswordDisabled) {
|
||||
sendAPIResponse(w, r, nil, "You are not authorized to share files/folders without a password",
|
||||
http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
}
|
||||
if err := dataprovider.UpdateShare(&share, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role); err != nil {
|
||||
err = dataprovider.UpdateShare(&updatedShare, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role)
|
||||
if err != nil {
|
||||
sendAPIResponse(w, r, err, "", getRespStatus(err))
|
||||
return
|
||||
}
|
||||
|
|
|
@ -163,55 +163,28 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
|
|||
sendAPIResponse(w, r, err, "", getRespStatus(err))
|
||||
return
|
||||
}
|
||||
userID := user.ID
|
||||
username = user.Username
|
||||
lastPwdChange := user.LastPasswordChange
|
||||
totpConfig := user.Filters.TOTPConfig
|
||||
recoveryCodes := user.Filters.RecoveryCodes
|
||||
currentPermissions := user.Permissions
|
||||
currentS3AccessSecret := user.FsConfig.S3Config.AccessSecret
|
||||
currentAzAccountKey := user.FsConfig.AzBlobConfig.AccountKey
|
||||
currentAzSASUrl := user.FsConfig.AzBlobConfig.SASURL
|
||||
currentGCSCredentials := user.FsConfig.GCSConfig.Credentials
|
||||
currentCryptoPassphrase := user.FsConfig.CryptConfig.Passphrase
|
||||
currentSFTPPassword := user.FsConfig.SFTPConfig.Password
|
||||
currentSFTPKey := user.FsConfig.SFTPConfig.PrivateKey
|
||||
currentSFTPKeyPassphrase := user.FsConfig.SFTPConfig.KeyPassphrase
|
||||
currentHTTPPassword := user.FsConfig.HTTPConfig.Password
|
||||
currentHTTPAPIKey := user.FsConfig.HTTPConfig.APIKey
|
||||
|
||||
user.Permissions = make(map[string][]string)
|
||||
user.FsConfig.S3Config = vfs.S3FsConfig{}
|
||||
user.FsConfig.AzBlobConfig = vfs.AzBlobFsConfig{}
|
||||
user.FsConfig.GCSConfig = vfs.GCSFsConfig{}
|
||||
user.FsConfig.CryptConfig = vfs.CryptFsConfig{}
|
||||
user.FsConfig.SFTPConfig = vfs.SFTPFsConfig{}
|
||||
user.FsConfig.HTTPConfig = vfs.HTTPFsConfig{}
|
||||
user.Filters.TOTPConfig = dataprovider.UserTOTPConfig{}
|
||||
user.Filters.RecoveryCodes = nil
|
||||
user.VirtualFolders = nil
|
||||
err = render.DecodeJSON(r.Body, &user)
|
||||
var updatedUser dataprovider.User
|
||||
updatedUser.Password = user.Password
|
||||
err = render.DecodeJSON(r.Body, &updatedUser)
|
||||
if err != nil {
|
||||
sendAPIResponse(w, r, err, "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
user.ID = userID
|
||||
user.Username = username
|
||||
user.Filters.TOTPConfig = totpConfig
|
||||
user.Filters.RecoveryCodes = recoveryCodes
|
||||
user.LastPasswordChange = lastPwdChange
|
||||
user.SetEmptySecretsIfNil()
|
||||
// we use new Permissions if passed otherwise the old ones
|
||||
if len(user.Permissions) == 0 {
|
||||
user.Permissions = currentPermissions
|
||||
}
|
||||
updateEncryptedSecrets(&user.FsConfig, currentS3AccessSecret, currentAzAccountKey, currentAzSASUrl,
|
||||
currentGCSCredentials, currentCryptoPassphrase, currentSFTPPassword, currentSFTPKey, currentSFTPKeyPassphrase,
|
||||
currentHTTPPassword, currentHTTPAPIKey)
|
||||
updatedUser.ID = user.ID
|
||||
updatedUser.Username = user.Username
|
||||
updatedUser.Filters.RecoveryCodes = user.Filters.RecoveryCodes
|
||||
updatedUser.Filters.TOTPConfig = user.Filters.TOTPConfig
|
||||
updatedUser.LastPasswordChange = user.LastPasswordChange
|
||||
updatedUser.SetEmptySecretsIfNil()
|
||||
updateEncryptedSecrets(&updatedUser.FsConfig, user.FsConfig.S3Config.AccessSecret, user.FsConfig.AzBlobConfig.AccountKey,
|
||||
user.FsConfig.AzBlobConfig.SASURL, user.FsConfig.GCSConfig.Credentials, user.FsConfig.CryptConfig.Passphrase,
|
||||
user.FsConfig.SFTPConfig.Password, user.FsConfig.SFTPConfig.PrivateKey, user.FsConfig.SFTPConfig.KeyPassphrase,
|
||||
user.FsConfig.HTTPConfig.Password, user.FsConfig.HTTPConfig.APIKey)
|
||||
if claims.Role != "" {
|
||||
user.Role = claims.Role
|
||||
updatedUser.Role = claims.Role
|
||||
}
|
||||
err = dataprovider.UpdateUser(&user, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role)
|
||||
err = dataprovider.UpdateUser(&updatedUser, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role)
|
||||
if err != nil {
|
||||
sendAPIResponse(w, r, err, "", getRespStatus(err))
|
||||
return
|
||||
|
|
|
@ -668,8 +668,8 @@ func TestRoleRelations(t *testing.T) {
|
|||
admin, _, err := httpdtest.AddAdmin(a, http.StatusCreated)
|
||||
assert.NoError(t, err)
|
||||
admin.Role = "invalid role"
|
||||
_, _, err = httpdtest.UpdateAdmin(admin, http.StatusInternalServerError)
|
||||
assert.NoError(t, err)
|
||||
_, resp, err = httpdtest.UpdateAdmin(admin, http.StatusInternalServerError)
|
||||
assert.NoError(t, err, string(resp))
|
||||
admin, _, err = httpdtest.GetAdminByUsername(admin.Username, http.StatusOK)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, role.Name, admin.Role)
|
||||
|
@ -813,21 +813,38 @@ func TestBasicGroupHandling(t *testing.T) {
|
|||
group.UserSettings.FsConfig.SFTPConfig.Endpoint = sftpServerAddr
|
||||
group.UserSettings.FsConfig.SFTPConfig.Username = defaultUsername
|
||||
group.UserSettings.FsConfig.SFTPConfig.Password = kms.NewPlainSecret(defaultPassword)
|
||||
group.UserSettings.Permissions = map[string][]string{
|
||||
"/": {dataprovider.PermAny},
|
||||
}
|
||||
group.UserSettings.Filters.AllowedIP = []string{"10.0.0.0/8"}
|
||||
group, _, err = httpdtest.UpdateGroup(group, http.StatusOK)
|
||||
assert.NoError(t, err)
|
||||
groupGet, _, err = httpdtest.GetGroupByName(group.Name, http.StatusOK)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, groupGet.UserSettings.Permissions, 1)
|
||||
assert.Len(t, groupGet.UserSettings.Filters.AllowedIP, 1)
|
||||
|
||||
// update again and check that the password was preserved
|
||||
dbGroup, err := dataprovider.GroupExists(group.Name)
|
||||
assert.NoError(t, err)
|
||||
group.UserSettings.FsConfig.SFTPConfig.Password = kms.NewSecret(
|
||||
dbGroup.UserSettings.FsConfig.SFTPConfig.Password.GetStatus(),
|
||||
dbGroup.UserSettings.FsConfig.SFTPConfig.Password.GetPayload(), "", "")
|
||||
group.UserSettings.Permissions = nil
|
||||
group.UserSettings.Filters.AllowedIP = nil
|
||||
group, _, err = httpdtest.UpdateGroup(group, http.StatusOK)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, group.UserSettings.Permissions, 0)
|
||||
assert.Len(t, group.UserSettings.Filters.AllowedIP, 0)
|
||||
dbGroup, err = dataprovider.GroupExists(group.Name)
|
||||
assert.NoError(t, err)
|
||||
err = dbGroup.UserSettings.FsConfig.SFTPConfig.Password.Decrypt()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, defaultPassword, dbGroup.UserSettings.FsConfig.SFTPConfig.Password.GetPayload())
|
||||
// check the group permissions
|
||||
groupGet, _, err = httpdtest.GetGroupByName(group.Name, http.StatusOK)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, groupGet.UserSettings.Permissions, 0)
|
||||
|
||||
group.UserSettings.HomeDir = "relative path"
|
||||
_, _, err = httpdtest.UpdateGroup(group, http.StatusBadRequest)
|
||||
|
@ -4191,7 +4208,11 @@ func TestUpdateUserEmptyPassword(t *testing.T) {
|
|||
assert.NotEmpty(t, dbUser.Password)
|
||||
assert.True(t, dbUser.IsPasswordHashed())
|
||||
// now update the user and set an empty password
|
||||
customUser := make(map[string]any)
|
||||
data, err := json.Marshal(dbUser)
|
||||
assert.NoError(t, err)
|
||||
var customUser map[string]any
|
||||
err = json.Unmarshal(data, &customUser)
|
||||
assert.NoError(t, err)
|
||||
customUser["password"] = ""
|
||||
asJSON, err := json.Marshal(customUser)
|
||||
assert.NoError(t, err)
|
||||
|
@ -4208,6 +4229,30 @@ func TestUpdateUserEmptyPassword(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestUpdateUserNoPassword(t *testing.T) {
|
||||
u := getTestUser()
|
||||
u.PublicKeys = []string{testPubKey}
|
||||
user, _, err := httpdtest.AddUser(u, http.StatusCreated)
|
||||
assert.NoError(t, err)
|
||||
// the password is not empty
|
||||
dbUser, err := dataprovider.UserExists(u.Username, "")
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, dbUser.Password)
|
||||
assert.True(t, dbUser.IsPasswordHashed())
|
||||
// now update the user and remove the password field, old password should be preserved
|
||||
user.Password = "" // password has the omitempty tag
|
||||
_, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
|
||||
assert.NoError(t, err)
|
||||
// the password is preserved
|
||||
dbUser, err = dataprovider.UserExists(u.Username, "")
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, dbUser.Password)
|
||||
assert.True(t, dbUser.IsPasswordHashed())
|
||||
|
||||
_, err = httpdtest.RemoveUser(user, http.StatusOK)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestUpdateUser(t *testing.T) {
|
||||
u := getTestUser()
|
||||
u.UsedQuotaFiles = 1
|
||||
|
@ -5947,10 +5992,11 @@ func TestNamingRules(t *testing.T) {
|
|||
assert.Equal(t, "文件夹ab", folder.Name)
|
||||
folder.Name = f.Name
|
||||
folder.Description = folder.Name
|
||||
folder, resp, err = httpdtest.UpdateFolder(folder, http.StatusOK)
|
||||
_, resp, err = httpdtest.UpdateFolder(folder, http.StatusOK)
|
||||
assert.NoError(t, err, string(resp))
|
||||
folder, resp, err = httpdtest.GetFolderByName(f.Name, http.StatusOK)
|
||||
assert.NoError(t, err, string(resp))
|
||||
assert.Equal(t, "文件夹AB", folder.Description)
|
||||
_, err = httpdtest.RemoveFolder(f, http.StatusOK)
|
||||
assert.NoError(t, err)
|
||||
token, err := getJWTWebClientTokenFromTestServer(u.Username, defaultPassword)
|
||||
|
@ -9620,7 +9666,10 @@ func TestWebAPIChangeUserProfileMock(t *testing.T) {
|
|||
assert.Equal(t, email, profileReq["email"].(string))
|
||||
assert.Equal(t, description, profileReq["description"].(string))
|
||||
assert.True(t, profileReq["allow_api_key_auth"].(bool))
|
||||
assert.Len(t, profileReq["public_keys"].([]any), 2)
|
||||
val, ok := profileReq["public_keys"].([]any)
|
||||
if assert.True(t, ok, profileReq) {
|
||||
assert.Len(t, val, 2)
|
||||
}
|
||||
// set an invalid email
|
||||
profileReq = make(map[string]any)
|
||||
profileReq["email"] = "notavalidemail"
|
||||
|
@ -9644,6 +9693,8 @@ func TestWebAPIChangeUserProfileMock(t *testing.T) {
|
|||
checkResponseCode(t, http.StatusBadRequest, rr)
|
||||
assert.Contains(t, rr.Body.String(), "Validation error: could not parse key")
|
||||
|
||||
user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
|
||||
assert.NoError(t, err)
|
||||
user.Filters.WebClient = []string{sdk.WebClientAPIKeyAuthChangeDisabled, sdk.WebClientPubKeyChangeDisabled}
|
||||
user.Email = email
|
||||
user.Description = description
|
||||
|
@ -9678,8 +9729,13 @@ func TestWebAPIChangeUserProfileMock(t *testing.T) {
|
|||
assert.Equal(t, email, profileReq["email"].(string))
|
||||
assert.Equal(t, description+"_mod", profileReq["description"].(string))
|
||||
assert.True(t, profileReq["allow_api_key_auth"].(bool))
|
||||
assert.Len(t, profileReq["public_keys"].([]any), 2)
|
||||
val, ok = profileReq["public_keys"].([]any)
|
||||
if assert.True(t, ok, profileReq) {
|
||||
assert.Len(t, val, 2)
|
||||
}
|
||||
|
||||
user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
|
||||
assert.NoError(t, err)
|
||||
user.Filters.WebClient = []string{sdk.WebClientAPIKeyAuthChangeDisabled, sdk.WebClientInfoChangeDisabled}
|
||||
user.Description = description + "_mod"
|
||||
_, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
|
||||
|
@ -10299,47 +10355,6 @@ func TestUserHandlingWithAPIKey(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestUpdateUserMock(t *testing.T) {
|
||||
token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
|
||||
assert.NoError(t, err)
|
||||
user := getTestUser()
|
||||
userAsJSON := getUserAsJSON(t, user)
|
||||
req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
|
||||
setBearerForReq(req, token)
|
||||
rr := executeRequest(req)
|
||||
checkResponseCode(t, http.StatusCreated, rr)
|
||||
err = render.DecodeJSON(rr.Body, &user)
|
||||
assert.NoError(t, err)
|
||||
// permissions should not change if empty or nil
|
||||
permissions := user.Permissions
|
||||
user.Permissions = make(map[string][]string)
|
||||
userAsJSON = getUserAsJSON(t, user)
|
||||
req, _ = http.NewRequest(http.MethodPut, userPath+"/"+user.Username, bytes.NewBuffer(userAsJSON))
|
||||
setBearerForReq(req, token)
|
||||
rr = executeRequest(req)
|
||||
checkResponseCode(t, http.StatusOK, rr)
|
||||
req, _ = http.NewRequest(http.MethodGet, userPath+"/"+user.Username, nil)
|
||||
setBearerForReq(req, token)
|
||||
rr = executeRequest(req)
|
||||
checkResponseCode(t, http.StatusOK, rr)
|
||||
var updatedUser dataprovider.User
|
||||
err = render.DecodeJSON(rr.Body, &updatedUser)
|
||||
assert.NoError(t, err)
|
||||
for dir, perms := range permissions {
|
||||
if actualPerms, ok := updatedUser.Permissions[dir]; ok {
|
||||
for _, v := range actualPerms {
|
||||
assert.True(t, util.Contains(perms, v))
|
||||
}
|
||||
} else {
|
||||
assert.Fail(t, "Permissions directories mismatch")
|
||||
}
|
||||
}
|
||||
req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil)
|
||||
setBearerForReq(req, token)
|
||||
rr = executeRequest(req)
|
||||
checkResponseCode(t, http.StatusOK, rr)
|
||||
}
|
||||
|
||||
func TestUpdateUserQuotaUsageMock(t *testing.T) {
|
||||
token, err := getJWTAPITokenFromTestServer(defaultTokenAuthUser, defaultTokenAuthPass)
|
||||
assert.NoError(t, err)
|
||||
|
|
|
@ -2668,29 +2668,7 @@ func TestLoginAfterUserUpdateEmptyPwd(t *testing.T) {
|
|||
user, _, err := httpdtest.AddUser(getTestUser(usePubKey), http.StatusCreated)
|
||||
assert.NoError(t, err)
|
||||
user.Password = ""
|
||||
user.PublicKeys = []string{}
|
||||
// password and public key should remain unchanged
|
||||
_, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
|
||||
assert.NoError(t, err)
|
||||
conn, client, err := getSftpClient(user, usePubKey)
|
||||
if assert.NoError(t, err) {
|
||||
defer conn.Close()
|
||||
defer client.Close()
|
||||
assert.NoError(t, checkBasicSFTP(client))
|
||||
}
|
||||
_, err = httpdtest.RemoveUser(user, http.StatusOK)
|
||||
assert.NoError(t, err)
|
||||
err = os.RemoveAll(user.GetHomeDir())
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestLoginAfterUserUpdateEmptyPubKey(t *testing.T) {
|
||||
usePubKey := true
|
||||
user, _, err := httpdtest.AddUser(getTestUser(usePubKey), http.StatusCreated)
|
||||
assert.NoError(t, err)
|
||||
user.Password = ""
|
||||
user.PublicKeys = []string{}
|
||||
// password and public key should remain unchanged
|
||||
// password should remain unchanged
|
||||
_, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
|
||||
assert.NoError(t, err)
|
||||
conn, client, err := getSftpClient(user, usePubKey)
|
||||
|
|
Loading…
Reference in a new issue