diff --git a/docs/custom-actions.md b/docs/custom-actions.md index 6450cf8f..4f8fb083 100644 --- a/docs/custom-actions.md +++ b/docs/custom-actions.md @@ -49,6 +49,7 @@ If the `hook` defines a path to an external program, then this program can read - `SFTPGO_ACTION_IP`, the action was executed from this IP address - `SFTPGO_ACTION_SESSION_ID`, string. Unique protocol session identifier. For stateless protocols such as HTTP the session id will change for each request - `SFTPGO_ACTION_OPEN_FLAGS`, integer. File open flags, can be non-zero for `pre-upload` action. If `SFTPGO_ACTION_FILE_SIZE` is greater than zero and `SFTPGO_ACTION_OPEN_FLAGS&512 == 0` the target file will not be truncated +- `SFTPGO_ACTION_ROLE`, string. Role of the user who executed the action - `SFTPGO_ACTION_TIMESTAMP`, int64. Event timestamp as nanoseconds since epoch Global environment variables are cleared, for security reasons, when the script is called. You can set additional environment variables in the "command" configuration section. @@ -72,6 +73,7 @@ If the `hook` defines an HTTP URL then this URL will be invoked as HTTP POST. Th - `ip`, string. The action was executed from this IP address - `session_id`, string. Unique protocol session identifier. For stateless protocols such as HTTP the session id will change for each request - `open_flags`, integer. File open flags, can be non-zero for `pre-upload` action. If `file_size` is greater than zero and `file_size&512 == 0` the target file will not be truncated +- `role`, string. Included if the user who executed the action has a role - `timestamp`, int64. Event timestamp as nanoseconds since epoch The HTTP hook will use the global configuration for HTTP clients and will respect the retry configurations. @@ -102,15 +104,16 @@ If the `hook` defines a path to an external program, then this program can read - `SFTPGO_PROVIDER_ACTION`, supported values are `add`, `update`, `delete` - `SFTPGO_PROVIDER_OBJECT_TYPE`, affected object type - `SFTPGO_PROVIDER_OBJECT_NAME`, unique identifier for the affected object, for example username or key id -- `SFTPGO_PROVIDER_USERNAME`, the username that executed the action. There are two special usernames: `__self__` identifies a user/admin that updates itself and `__system__` identifies an action that does not have an explicit executor associated with it, for example users/admins can be added/updated by loading them from initial data +- `SFTPGO_PROVIDER_USERNAME`, the admin username that executed the action. There are two special usernames: `__self__` identifies a user/admin that updates itself and `__system__` identifies an action that does not have an explicit executor associated with it, for example users/admins can be added/updated by loading them from initial data - `SFTPGO_PROVIDER_IP`, the action was executed from this IP address +- `SFTPGO_PROVIDER_ROLE`, the action was executed by an admin with this role - `SFTPGO_PROVIDER_TIMESTAMP`, event timestamp as nanoseconds since epoch - `SFTPGO_PROVIDER_OBJECT`, object serialized as JSON with sensitive fields removed Global environment variables are cleared, for security reasons, when the script is called. You can set additional environment variables in the "command" configuration section. The program must finish within 15 seconds. -If the `hook` defines an HTTP URL then this URL will be invoked as HTTP POST. The action, username, ip, object_type and object_name and timestamp are added to the query string, for example `?action=update&username=admin&ip=127.0.0.1&object_type=user&object_name=user1×tamp=1633860803249`, and the full object is sent serialized as JSON inside the POST body with sensitive fields removed. +If the `hook` defines an HTTP URL then this URL will be invoked as HTTP POST. The action, username, ip, object_type and object_name and timestamp and role are added to the query string, for example `?action=update&username=admin&ip=127.0.0.1&object_type=user&object_name=user1×tamp=1633860803249`, and the full object is sent serialized as JSON inside the POST body with sensitive fields removed. The role is added only if not empty. The HTTP hook will use the global configuration for HTTP clients and will respect the retry configurations. diff --git a/docs/eventmanager.md b/docs/eventmanager.md index a0c4f152..1ac971db 100644 --- a/docs/eventmanager.md +++ b/docs/eventmanager.md @@ -39,6 +39,7 @@ The following placeholders are supported: - `{{FileSize}}`. File size. - `{{Protocol}}`. Used protocol, for example `SFTP`, `FTP`. - `{{IP}}`. Client IP address. +- `{{Role}}`. User or admin role. - `{{Timestamp}}`. Event timestamp as nanoseconds since epoch. - `{{ObjectData}}`. Provider object data serialized as JSON with sensitive fields removed. - `{{RetentionReports}}`. Data retention reports as zip compressed CSV files. Supported as email attachment, file path for multipart HTTP request and as single parameter for HTTP requests body. Data retention reports contain details on the number of files deleted and the total size deleted for each folder. diff --git a/go.mod b/go.mod index 6943fccd..2955be52 100644 --- a/go.mod +++ b/go.mod @@ -3,20 +3,20 @@ module github.com/drakkan/sftpgo/v2 go 1.19 require ( - cloud.google.com/go/storage v1.28.0 + cloud.google.com/go/storage v1.28.1 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.2.0 github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1 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.1 - github.com/aws/aws-sdk-go-v2/config v1.18.3 - github.com/aws/aws-sdk-go-v2/credentials v1.13.3 - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19 - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.42 - github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.13.24 - github.com/aws/aws-sdk-go-v2/service/s3 v1.29.4 - github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.16.8 - github.com/aws/aws-sdk-go-v2/service/sts v1.17.5 + github.com/aws/aws-sdk-go-v2 v1.17.2 + github.com/aws/aws-sdk-go-v2/config v1.18.4 + github.com/aws/aws-sdk-go-v2/credentials v1.13.4 + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.20 + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.43 + github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.13.25 + github.com/aws/aws-sdk-go-v2/service/s3 v1.29.5 + github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.16.9 + github.com/aws/aws-sdk-go-v2/service/sts v1.17.6 github.com/cockroachdb/cockroach-go/v2 v2.2.19 github.com/coreos/go-oidc/v3 v3.4.0 github.com/drakkan/webdav v0.0.0-20221101181759-17ed21f9337b @@ -27,7 +27,7 @@ require ( github.com/go-chi/chi/v5 v5.0.8-0.20221018120124-e5529d9db4d3 github.com/go-chi/jwtauth/v5 v5.1.0 github.com/go-chi/render v1.0.2 - github.com/go-sql-driver/mysql v1.6.0 + github.com/go-sql-driver/mysql v1.7.0 github.com/golang/mock v1.6.0 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/google/uuid v1.3.0 @@ -51,8 +51,8 @@ require ( github.com/rs/cors v1.8.3-0.20220619195839-da52b0701de5 github.com/rs/xid v1.4.0 github.com/rs/zerolog v1.28.0 - github.com/sftpgo/sdk v0.1.3-0.20221116180328-3fc64e926700 - github.com/shirou/gopsutil/v3 v3.22.10 + github.com/sftpgo/sdk v0.1.3-0.20221203095324-2feef3600930 + github.com/shirou/gopsutil/v3 v3.22.11 github.com/spf13/afero v1.9.3 github.com/spf13/cobra v1.6.1 github.com/spf13/viper v1.14.0 @@ -77,23 +77,23 @@ require ( require ( cloud.google.com/go v0.107.0 // indirect - cloud.google.com/go/compute v1.12.1 // indirect - cloud.google.com/go/compute/metadata v0.2.1 // indirect + cloud.google.com/go/compute v1.13.0 // indirect + cloud.google.com/go/compute/metadata v0.2.2 // indirect cloud.google.com/go/iam v0.7.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.1 // indirect github.com/ajg/form v1.5.1 // indirect - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.16 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.10 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.20 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.19 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.11.25 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 // indirect - github.com/aws/smithy-go v1.13.4 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.26 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.20 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.27 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.17 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.21 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.20 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.20 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.11.26 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.9 // indirect + github.com/aws/smithy-go v1.13.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/boombuler/barcode v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.2.0 // indirect @@ -115,7 +115,7 @@ require ( github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/yamux v0.1.1 // indirect - github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect @@ -158,7 +158,7 @@ require ( golang.org/x/tools v0.3.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 // indirect + google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd // indirect google.golang.org/grpc v1.51.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index af5a3778..caa14b26 100644 --- a/go.sum +++ b/go.sum @@ -50,10 +50,10 @@ cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6m cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= -cloud.google.com/go/compute v1.12.1 h1:gKVJMEyqV5c/UnpzjjQbo3Rjvvqpr9B1DFSbJC4OXr0= -cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute/metadata v0.2.1 h1:efOwf5ymceDhK6PKMnnrTHP4pppY5L22mle96M1yP48= -cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= +cloud.google.com/go/compute v1.13.0 h1:AYrLkB8NPdDRslNp4Jxmzrhdr03fUAIDbiGFjLWowoU= +cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= +cloud.google.com/go/compute/metadata v0.2.2 h1:aWKAjYaBaOSrpKl57+jnS/3fJRQnxL7TvR/u1VVbt6k= +cloud.google.com/go/compute/metadata v0.2.2/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= @@ -82,8 +82,8 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= cloud.google.com/go/storage v1.24.0/go.mod h1:3xrJEFMXBsQLgxwThyjuD3aYlroL0TMRec1ypGUQ0KE= -cloud.google.com/go/storage v1.28.0 h1:DLrIZ6xkeZX6K70fU/boWx5INJumt6f+nwwWSHXzzGY= -cloud.google.com/go/storage v1.28.0/go.mod h1:qlgZML35PXA3zoEnIkiPLY4/TOkUleufRlu6qmcf7sI= +cloud.google.com/go/storage v1.28.1 h1:F5QDG5ChchaAVQhINh24U99OWHURqrW8OmQcGKXcbgI= +cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= cloud.google.com/go/trace v1.0.0/go.mod h1:4iErSByzxkyHWzzlAj63/Gmjz0NH1ASqhJguHpGcr6A= cloud.google.com/go/trace v1.2.0/go.mod h1:Wc8y/uYyOhPy12KEnXG9XGrvfMz5F5SrYecQlbW1rwM= code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c/go.mod h1:QD9Lzhd/ux6eNQVUDVRJX/RKTigpewimNYBi7ivZKY8= @@ -227,70 +227,70 @@ github.com/aws/aws-sdk-go v1.44.45/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4 github.com/aws/aws-sdk-go v1.44.68/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/aws/aws-sdk-go-v2 v1.16.8/go.mod h1:6CpKuLXg2w7If3ABZCl/qZ6rEgwtjZTn4eAf4RcEyuw= -github.com/aws/aws-sdk-go-v2 v1.17.1 h1:02c72fDJr87N8RAC2s3Qu0YuvMRZKNZJ9F+lAehCazk= -github.com/aws/aws-sdk-go-v2 v1.17.1/go.mod h1:JLnGeGONAyi2lWXI1p0PCIOIy333JMVK1U7Hf0aRFLw= +github.com/aws/aws-sdk-go-v2 v1.17.2 h1:r0yRZInwiPBNpQ4aDy/Ssh3ROWsGtKDwar2JS8Lm+N8= +github.com/aws/aws-sdk-go-v2 v1.17.2/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3/go.mod h1:gNsR5CaXKmQSSzrmGxmwmct/r+ZBfbxorAuXYsj/M5Y= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9 h1:RKci2D7tMwpvGpDNZnGQw9wk6v7o/xSwFcUAuNPoB8k= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9/go.mod h1:vCmV1q1VK8eoQJ5+aYE7PkK1K6v41qJ5pJdK3ggCDvg= +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.3 h1:3kfBKcX3votFX84dm00U8RGA1sCCh3eRMOGzg5dCWfU= -github.com/aws/aws-sdk-go-v2/config v1.18.3/go.mod h1:BYdrbeCse3ZnOD5+2/VE/nATOK8fEUpBtmPMdKSyhMU= +github.com/aws/aws-sdk-go-v2/config v1.18.4 h1:VZKhr3uAADXHStS/Gf9xSYVmmaluTUfkc0dcbPiDsKE= +github.com/aws/aws-sdk-go-v2/config v1.18.4/go.mod h1:EZxMPLSdGAZ3eAmkqXfYbRppZJTzFTkv8VyEzJhKko4= 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.3 h1:ur+FHdp4NbVIv/49bUjBW+FE7e57HOo03ELodttmagk= -github.com/aws/aws-sdk-go-v2/credentials v1.13.3/go.mod h1:/rOMmqYBcFfNbRPU0iN9IgGqD5+V2yp3iWNmIlz0wI4= +github.com/aws/aws-sdk-go-v2/credentials v1.13.4 h1:nEbHIyJy7mCvQ/kzGG7VWHSBpRB4H6sJy3bWierWUtg= +github.com/aws/aws-sdk-go-v2/credentials v1.13.4/go.mod h1:/Cj5w9LRsNTLSwexsohwDME32OzJ6U81Zs33zr2ZWOM= 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.19 h1:E3PXZSI3F2bzyj6XxUXdTIfvp425HHhwKsFvmzBwHgs= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19/go.mod h1:VihW95zQpeKQWVPGkwT+2+WJNQV8UXFfMTWdU6VErL8= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.20 h1:tpNOglTZ8kg9T38NpcGBxudqfUAwUzyUnLQ4XSd0CHE= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.20/go.mod h1:d9xFpWd3qYwdIXM0fvu7deD08vvdRXyc/ueV+0SqaWE= 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.42 h1:bxgBYvvBh+W1RnNYP4ROXEB8N+HSSucDszfE7Rb+kfU= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.42/go.mod h1:LHOsygMiW/14CkFxdXxvzKyMh3jbk/QfZVaDtCbLkl8= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.43 h1:+bkAMTd5OGyHu2nwNOangjEsP65fR0uhMbZJA52sZ64= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.43/go.mod h1:sS2tu0VEspKuY5eM1vQgy7P/hpZX8F62o6qsghZExWc= 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.25 h1:nBO/RFxeq/IS5G9Of+ZrgucRciie2qpLy++3UGZ+q2E= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25/go.mod h1:Zb29PYkf42vVYQY6pvSyJCJcFHlPIiY+YKdPtwnvMkY= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.26 h1:5WU31cY7m0tG+AiaXuXGoMzo2GBQ1IixtWa8Yywsgco= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.26/go.mod h1:2E0LdbJW6lbeU4uxjum99GZzI0ZjDpAb0CoSCM0oeEY= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.9/go.mod h1:08tUpeSGN33QKSO7fwxXczNfiwCpbj+GxK6XKwqWVv0= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19 h1:oRHDrwCTVT8ZXi4sr9Ld+EXk7N/KGssOr2ygNeojEhw= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19/go.mod h1:6Q0546uHDp421okhmmGfbxzq2hBqbXFNpi4k+Q1JnQA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.20 h1:WW0qSzDWoiWU2FS5DbKpxGilFVlCEJPwx4YtjdfI0Jw= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.20/go.mod h1:/+6lSiby8TBFpTVXZgKiN/rCfkYXEGvhlM4zCgPpt7w= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.16/go.mod h1:CYmI+7x03jjJih8kBEEFKRQc40UjUokT0k7GbvrhhTc= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26 h1:Mza+vlnZr+fPKFKRq/lKGVvM6B/8ZZmNdEopOwSQLms= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26/go.mod h1:Y2OJ+P+MC1u1VKnavT+PshiEuGPyh/7DqxoDNij4/bg= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.27 h1:N2eKFw2S+JWRCtTt0IhIX7uoGGQciD4p6ba+SJv4WEU= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.27/go.mod h1:RdwFVc7PBYWY33fa2+8T1mSqQ7ZEK4ILpM0wfioDC3w= github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.6/go.mod h1:O7Oc4peGZDEKlddivslfYFvAbgzvl/GH3J8j3JIGBXc= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.16 h1:2EXB7dtGwRYIN3XQ9qwIW504DVbKIw3r89xQnonGdsQ= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.16/go.mod h1:XH+3h395e3WVdd6T2Z3mPxuI+x/HVtdqVOREkTiyubs= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.17 h1:5tXbMJ7Jq0iG65oiMg6tCLsHkSaO2xLXa2EmZ29vaTA= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.17/go.mod h1:twV0fKMQuqLY4klyFH56aXNq3AFiA5LO0/frTczEOFE= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.3/go.mod h1:gkb2qADY+OHaGLKNTYxMaQNacfeyQpZ4csDTQMeFmcw= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.10 h1:dpiPHgmFstgkLG07KaYAewvuptq5kvo52xn7tVSrtrQ= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.10/go.mod h1:9cBNUHI2aW4ho0A5T87O294iPDuuUOSIEDjnd1Lq/z0= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.10/go.mod h1:Qks+dxK3O+Z2deAhNo6cJ8ls1bam3tUGUAcgxQP1c70= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.20 h1:KSvtm1+fPXE0swe9GPjc6msyrdTT0LB/BP8eLugL1FI= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.20/go.mod h1:Mp4XI/CkWGD79AQxZ5lIFlgvC0A+gl+4BmyG1F+SfNc= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.21 h1:77b1GfaSuIok5yB/3HYbG+ypWvOJDQ2rVdq943D17R4= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.21/go.mod h1:sPOz31BVdqeeurKEuUpLNSve4tdCNPluE+070HNcEHI= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.9/go.mod h1:yQowTpvdZkFVuHrLBXmczat4W+WJKg/PafBZnGBLga0= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19 h1:GE25AWCdNUPh9AOJzI9KIJnja7IwUc1WyUqz/JTyJ/I= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19/go.mod h1:02CP6iuYP+IVnBX5HULVdSAku/85eHB2Y9EsFhrkEwU= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.20 h1:jlgyHbkZQAgAc7VIxJDmtouH8eNjOk2REVAQfVhdaiQ= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.20/go.mod h1:Xs52xaLBqDEKRcAfX/hgjmD3YQ7c/W+BEyfamlO/W2E= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.9/go.mod h1:Rc5+wn2k8gFSi3V1Ch4mhxOzjMh+bYSXVFfVaqowQOY= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.19 h1:piDBAaWkaxkkVV3xJJbTehXCZRXYs49kvpi/LG6LR2o= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.19/go.mod h1:BmQWRVkLTmyNzYPFAZgon53qKLWBNSvonugD1MrSWUs= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.20 h1:4K6dbmR0mlp3o4Bo78PnpvzHtYAqEeVMguvEenpMGsI= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.20/go.mod h1:1XpDcReIEOHsjwNToDKhIAO3qwLo1BnfbtSqWJa8j7g= github.com/aws/aws-sdk-go-v2/service/kms v1.18.1/go.mod h1:4PZMUkc9rXHWGVB5J9vKaZy3D7Nai79ORworQ3ASMiM= -github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.13.24 h1:DYr+X4xrRzcthq2OLJzsiS/uSJhZ/HHxXG0yUgGZceU= -github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.13.24/go.mod h1:mRGY+k3s1yt7yQA3AfzJhnr68OCs1xDfQfIABFUk+ek= +github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.13.25 h1:rCfUDMT9KO++W4TkIJr3BO0h749xkRX4RpHdydSFfHw= +github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.13.25/go.mod h1:xCXhZdPR0p6uaNhggLVGREnJaUIc2CNOJydWnZ2R7OQ= github.com/aws/aws-sdk-go-v2/service/s3 v1.27.2/go.mod h1:u+566cosFI+d+motIz3USXEh6sN8Nq4GrNXSg2RXVMo= -github.com/aws/aws-sdk-go-v2/service/s3 v1.29.4 h1:QgmmWifaYZZcpaw3y1+ccRlgH6jAvLm4K/MBGUc7cNM= -github.com/aws/aws-sdk-go-v2/service/s3 v1.29.4/go.mod h1:/NHbqPRiwxSPVOB2Xr+StDEH+GWV/64WwnUjv4KYzV0= +github.com/aws/aws-sdk-go-v2/service/s3 v1.29.5 h1:nRSEQj1JergKTVc8RGkhZvOEGgcvo4fWpDPwGDeg2ok= +github.com/aws/aws-sdk-go-v2/service/s3 v1.29.5/go.mod h1:wcaJTmjKFDW0s+Se55HBNIds6ghdAGoDDw+SGUdrfAk= 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.8 h1:Zw48FHykP40fKMxPmagkuzklpEuDPLhvUjKP8Ygrds0= -github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.16.8/go.mod h1:k6CPuxyzO247nYEM1baEwHH1kRtosRCvgahAepaaShw= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.16.9 h1:ogcakjF/mrZOo9oJVWmRbG838C04oWGXI8T8IY4xcfM= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.16.9/go.mod h1:S7AsUoaHONHV2iGM5QXQOonnaV05cK9fty2dXRdouws= 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.25 h1:GFZitO48N/7EsFDt8fMa5iYdmWqkUDDB3Eje6z3kbG0= -github.com/aws/aws-sdk-go-v2/service/sso v1.11.25/go.mod h1:IARHuzTXmj1C0KS35vboR0FeJ89OkEy1M9mWbK2ifCI= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 h1:jcw6kKZrtNfBPJkaHrscDOZoe5gvi9wjudnxvozYFJo= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8/go.mod h1:er2JHN+kBY6FcMfcBBKNGCT3CarImmdFzishsqBmSRI= +github.com/aws/aws-sdk-go-v2/service/sso v1.11.26 h1:ActQgdTNQej/RuUJjB9uxYVLDOvRGtUreXF8L3c8wyg= +github.com/aws/aws-sdk-go-v2/service/sso v1.11.26/go.mod h1:uB9tV79ULEZUXc6Ob18A46KSQ0JDlrplPni9XW6Ot60= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.9 h1:wihKuqYUlA2T/Rx+yu2s6NDAns8B9DgnRooB1PVhY+Q= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.9/go.mod h1:2E/3D/mB8/r2J7nK42daoKP/ooCwbf0q1PznNc+DZTU= github.com/aws/aws-sdk-go-v2/service/sts v1.16.10/go.mod h1:cftkHYN6tCDNfkSasAmclSfl4l7cySoay8vz7p/ce0E= -github.com/aws/aws-sdk-go-v2/service/sts v1.17.5 h1:60SJ4lhvn///8ygCzYy2l53bFW/Q15bVfyjyAWo6zuw= -github.com/aws/aws-sdk-go-v2/service/sts v1.17.5/go.mod h1:bXcN3koeVYiJcdDU89n3kCYILob7Y34AeLopUbZgLT4= +github.com/aws/aws-sdk-go-v2/service/sts v1.17.6 h1:VQFOLQVL3BrKM/NLO/7FiS4vcp5bqK0mGMyk09xLoAY= +github.com/aws/aws-sdk-go-v2/service/sts v1.17.6/go.mod h1:Az3OXXYGyfNwQNsK/31L4R75qFYnO641RZGAoV3uH1c= github.com/aws/smithy-go v1.12.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= -github.com/aws/smithy-go v1.13.4 h1:/RN2z1txIJWeXeOkzX+Hk/4Uuvv7dWtCjbmVJcrskyk= -github.com/aws/smithy-go v1.13.4/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= +github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -676,8 +676,9 @@ github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GO github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= @@ -966,8 +967,9 @@ github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ= github.com/ionos-cloud/sdk-go/v6 v6.1.0/go.mod h1:Ox3W0iiEz0GHnfY9e5LmAxwklsxguuNFEUSu0gVRTME= @@ -1446,10 +1448,10 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/secsy/goftp v0.0.0-20200609142545-aa2de14babf4 h1:PT+ElG/UUFMfqy5HrxJxNzj3QBOf7dZwupeVC+mG1Lo= -github.com/sftpgo/sdk v0.1.3-0.20221116180328-3fc64e926700 h1:hfUjwmNPMqE9o5oIBxDQZE0FJ8IqlJwVVhATQYwe2Ao= -github.com/sftpgo/sdk v0.1.3-0.20221116180328-3fc64e926700/go.mod h1:Giy5vj7Gmju0nGlmBNd28DwPo0G0o1nr9XkE+vu3i+o= -github.com/shirou/gopsutil/v3 v3.22.10 h1:4KMHdfBRYXGF9skjDWiL4RA2N+E8dRdodU/bOZpPoVg= -github.com/shirou/gopsutil/v3 v3.22.10/go.mod h1:QNza6r4YQoydyCfo6rH0blGfKahgibh4dQmV5xdFkQk= +github.com/sftpgo/sdk v0.1.3-0.20221203095324-2feef3600930 h1:znJ52fQBSAQhacaQvZAfkpTioqpcutDREM/H8NttKzU= +github.com/sftpgo/sdk v0.1.3-0.20221203095324-2feef3600930/go.mod h1:S2S/Q9fgUpXmL11YoCCt0hyCkEwH1LzQM/6QVsbUCFg= +github.com/shirou/gopsutil/v3 v3.22.11 h1:kxsPKS+Eeo+VnEQ2XCaGJepeP6KY53QoRTETx3+1ndM= +github.com/shirou/gopsutil/v3 v3.22.11/go.mod h1:xl0EeL4vXJ+hQMAGN8B9VFpxukEMA0XdevQOe5MZ1oY= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= @@ -1536,10 +1538,8 @@ github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= github.com/tedsuo/ifrit v0.0.0-20180802180643-bea94bb476cc/go.mod h1:eyZnKCc955uh98WQvzOm0dgAeLnf2O0Rz0LPoC5ze+0= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM= github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= -github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms= github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -2294,8 +2294,8 @@ google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljW google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20220802133213-ce4fa296bf78/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= -google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 h1:a2S6M0+660BgMNl++4JPlcAO/CjkqYItDEZwkoDQK7c= -google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd h1:OjndDrsik+Gt+e6fs45z9AxiewiKyLKYpA45W5Kpkks= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= diff --git a/internal/cmd/startsubsys.go b/internal/cmd/startsubsys.go index f04ad692..5bf759c0 100644 --- a/internal/cmd/startsubsys.go +++ b/internal/cmd/startsubsys.go @@ -142,7 +142,7 @@ Command-line flags should be specified in the Subsystem declaration. if user.HomeDir != filepath.Clean(homedir) && !preserveHomeDir { // update the user user.HomeDir = filepath.Clean(homedir) - err = dataprovider.UpdateUser(&user, dataprovider.ActionExecutorSystem, "") + err = dataprovider.UpdateUser(&user, dataprovider.ActionExecutorSystem, "", "") if err != nil { logger.Error(logSender, connectionID, "unable to update user %#v: %v", username, err) os.Exit(1) @@ -159,7 +159,7 @@ Command-line flags should be specified in the Subsystem declaration. user.Password = connectionID user.Permissions = make(map[string][]string) user.Permissions["/"] = []string{dataprovider.PermAny} - err = dataprovider.AddUser(&user, dataprovider.ActionExecutorSystem, "") + err = dataprovider.AddUser(&user, dataprovider.ActionExecutorSystem, "", "") if err != nil { logger.Error(logSender, connectionID, "unable to add user %#v: %v", username, err) os.Exit(1) diff --git a/internal/common/actions.go b/internal/common/actions.go index 1729fd09..cb38eab7 100644 --- a/internal/common/actions.go +++ b/internal/common/actions.go @@ -139,6 +139,7 @@ func ExecuteActionNotification(conn *BaseConnection, operation, filePath, virtua FileSize: notification.FileSize, Protocol: notification.Protocol, IP: notification.IP, + Role: notification.Role, Timestamp: notification.Timestamp, Object: nil, } @@ -214,6 +215,7 @@ func newActionNotification( IP: ip, SessionID: sessionID, OpenFlags: openFlags, + Role: user.Role, Timestamp: time.Now().UnixNano(), } } @@ -311,6 +313,7 @@ func notificationAsEnvVars(event *notifier.FsEvent) []string { fmt.Sprintf("SFTPGO_ACTION_SESSION_ID=%s", event.SessionID), fmt.Sprintf("SFTPGO_ACTION_OPEN_FLAGS=%d", event.OpenFlags), fmt.Sprintf("SFTPGO_ACTION_TIMESTAMP=%d", event.Timestamp), + fmt.Sprintf("SFTPGO_ACTION_ROLE=%s", event.Role), } } diff --git a/internal/common/common_test.go b/internal/common/common_test.go index d5a5c156..bf73a632 100644 --- a/internal/common/common_test.go +++ b/internal/common/common_test.go @@ -1380,7 +1380,7 @@ func TestUpdateTransferTimestamps(t *testing.T) { }, }, } - err := dataprovider.AddUser(user, "", "") + err := dataprovider.AddUser(user, "", "", "") assert.NoError(t, err) assert.Equal(t, int64(0), user.FirstUpload) assert.Equal(t, int64(0), user.FirstDownload) diff --git a/internal/common/eventmanager.go b/internal/common/eventmanager.go index 0f9a7827..9368ddd3 100644 --- a/internal/common/eventmanager.go +++ b/internal/common/eventmanager.go @@ -69,7 +69,7 @@ func init() { concurrencyGuard: make(chan struct{}, 200), } dataprovider.SetEventRulesCallbacks(eventManager.loadRules, eventManager.RemoveRule, - func(operation, executor, ip, objectType, objectName string, object plugin.Renderer) { + func(operation, executor, ip, objectType, objectName, role string, object plugin.Renderer) { eventManager.handleProviderEvent(EventParams{ Name: executor, ObjectName: objectName, @@ -77,6 +77,7 @@ func init() { Status: 1, ObjectType: objectType, IP: ip, + Role: role, Timestamp: time.Now().UnixNano(), Object: object, }) @@ -439,6 +440,7 @@ type EventParams struct { FileSize int64 Protocol string IP string + Role string Timestamp int64 Object plugin.Renderer sender string @@ -610,6 +612,7 @@ func (p *EventParams) getStringReplacements(addObjectData bool) []string { "{{FileSize}}", fmt.Sprintf("%d", p.FileSize), "{{Protocol}}", p.Protocol, "{{IP}}", p.IP, + "{{Role}}", p.Role, "{{Timestamp}}", fmt.Sprintf("%d", p.Timestamp), "{{StatusString}}", p.getStatusString(), } diff --git a/internal/common/eventmanager_test.go b/internal/common/eventmanager_test.go index 431cf7c7..f67e6c6e 100644 --- a/internal/common/eventmanager_test.go +++ b/internal/common/eventmanager_test.go @@ -210,7 +210,7 @@ func TestEventManager(t *testing.T) { }, }, } - err := dataprovider.AddEventAction(action, "", "") + err := dataprovider.AddEventAction(action, "", "", "") assert.NoError(t, err) rule := &dataprovider.EventRule{ Name: "rule", @@ -228,7 +228,7 @@ func TestEventManager(t *testing.T) { }, } - err = dataprovider.AddEventRule(rule, "", "") + err = dataprovider.AddEventRule(rule, "", "", "") assert.NoError(t, err) eventManager.RLock() @@ -242,7 +242,7 @@ func TestEventManager(t *testing.T) { rule.Conditions = dataprovider.EventConditions{ ProviderEvents: []string{"add"}, } - err = dataprovider.UpdateEventRule(rule, "", "") + err = dataprovider.UpdateEventRule(rule, "", "", "") assert.NoError(t, err) eventManager.RLock() @@ -280,7 +280,7 @@ func TestEventManager(t *testing.T) { }, 2*time.Second, 100*time.Millisecond) rule.DeletedAt = 0 - err = dataprovider.AddEventRule(rule, "", "") + err = dataprovider.AddEventRule(rule, "", "", "") assert.NoError(t, err) eventManager.RLock() @@ -290,7 +290,7 @@ func TestEventManager(t *testing.T) { assert.Len(t, eventManager.schedulesMapping, 1) eventManager.RUnlock() - err = dataprovider.DeleteEventRule(rule.Name, "", "") + err = dataprovider.DeleteEventRule(rule.Name, "", "", "") assert.NoError(t, err) eventManager.RLock() @@ -300,7 +300,7 @@ func TestEventManager(t *testing.T) { assert.Len(t, eventManager.schedulesMapping, 0) eventManager.RUnlock() - err = dataprovider.DeleteEventAction(action.Name, "", "") + err = dataprovider.DeleteEventAction(action.Name, "", "", "") assert.NoError(t, err) stopEventScheduler() } @@ -616,9 +616,9 @@ func TestEventRuleActions(t *testing.T) { }, }, } - err = dataprovider.AddUser(&user1, "", "") + err = dataprovider.AddUser(&user1, "", "", "") assert.NoError(t, err) - err = dataprovider.AddUser(&user2, "", "") + err = dataprovider.AddUser(&user2, "", "", "") assert.NoError(t, err) action = dataprovider.BaseEventAction{ @@ -963,9 +963,9 @@ func TestEventRuleActions(t *testing.T) { Name: foldername2, MappedPath: filepath.Join(os.TempDir(), foldername2), } - err = dataprovider.AddFolder(&folder1, "", "") + err = dataprovider.AddFolder(&folder1, "", "", "") assert.NoError(t, err) - err = dataprovider.AddFolder(&folder2, "", "") + err = dataprovider.AddFolder(&folder2, "", "", "") assert.NoError(t, err) action = dataprovider.BaseEventAction{ Type: dataprovider.ActionTypeFolderQuotaReset, @@ -1025,9 +1025,9 @@ func TestEventRuleActions(t *testing.T) { err = os.RemoveAll(folder1.MappedPath) assert.NoError(t, err) - err = dataprovider.DeleteFolder(foldername1, "", "") + err = dataprovider.DeleteFolder(foldername1, "", "", "") assert.NoError(t, err) - err = dataprovider.DeleteFolder(foldername2, "", "") + err = dataprovider.DeleteFolder(foldername2, "", "", "") assert.NoError(t, err) } @@ -1042,7 +1042,7 @@ func TestEventRuleActionsNoGroupMatching(t *testing.T) { HomeDir: filepath.Join(os.TempDir(), username), }, } - err := dataprovider.AddUser(&user, "", "") + err := dataprovider.AddUser(&user, "", "", "") assert.NoError(t, err) conditions := dataprovider.ConditionOptions{ @@ -1102,7 +1102,7 @@ func TestGetFileContent(t *testing.T) { HomeDir: filepath.Join(os.TempDir(), username), }, } - err := dataprovider.AddUser(&user, "", "") + err := dataprovider.AddUser(&user, "", "", "") assert.NoError(t, err) err = os.MkdirAll(user.GetHomeDir(), os.ModePerm) assert.NoError(t, err) @@ -1141,7 +1141,7 @@ func TestGetFileContent(t *testing.T) { // change the filesystem provider user.FsConfig.Provider = sdk.CryptedFilesystemProvider user.FsConfig.CryptConfig.Passphrase = kms.NewPlainSecret("pwd") - err = dataprovider.UpdateUser(&user, "", "") + err = dataprovider.UpdateUser(&user, "", "", "") assert.NoError(t, err) // the file is not encrypted so reading the encryption header will fail _, err = getMailAttachments(user, []string{"/file.txt"}, replacer) @@ -1191,7 +1191,7 @@ func TestFilesystemActionErrors(t *testing.T) { conn := NewBaseConnection("", protocolEventAction, "", "", user) err = executeDeleteFileFsAction(conn, "", nil) assert.Error(t, err) - err = dataprovider.AddUser(&user, "", "") + err = dataprovider.AddUser(&user, "", "", "") assert.NoError(t, err) // check root fs fails err = executeDeleteFsActionForUser(nil, testReplacer, user) @@ -1234,7 +1234,7 @@ func TestFilesystemActionErrors(t *testing.T) { user.Permissions["/"] = []string{dataprovider.PermUpload} err = dataprovider.DeleteUser(username, "", "", "") assert.NoError(t, err) - err = dataprovider.AddUser(&user, "", "") + err = dataprovider.AddUser(&user, "", "", "") assert.NoError(t, err) err = executeRenameFsActionForUser([]dataprovider.KeyValue{ { @@ -1373,7 +1373,7 @@ func TestQuotaActionsWithQuotaTrackDisabled(t *testing.T) { Provider: sdk.LocalFilesystemProvider, }, } - err = dataprovider.AddUser(&user, "", "") + err = dataprovider.AddUser(&user, "", "", "") assert.NoError(t, err) err = os.MkdirAll(user.GetHomeDir(), os.ModePerm) @@ -1408,7 +1408,7 @@ func TestQuotaActionsWithQuotaTrackDisabled(t *testing.T) { Name: foldername, MappedPath: filepath.Join(os.TempDir(), foldername), } - err = dataprovider.AddFolder(&folder, "", "") + err = dataprovider.AddFolder(&folder, "", "", "") assert.NoError(t, err) err = os.MkdirAll(folder.MappedPath, os.ModePerm) assert.NoError(t, err) @@ -1425,7 +1425,7 @@ func TestQuotaActionsWithQuotaTrackDisabled(t *testing.T) { err = os.RemoveAll(folder.MappedPath) assert.NoError(t, err) - err = dataprovider.DeleteFolder(foldername, "", "") + err = dataprovider.DeleteFolder(foldername, "", "", "") assert.NoError(t, err) err = dataprovider.Close() @@ -1444,7 +1444,7 @@ func TestScheduledActions(t *testing.T) { Name: "action", Type: dataprovider.ActionTypeBackup, } - err = dataprovider.AddEventAction(action, "", "") + err = dataprovider.AddEventAction(action, "", "", "") assert.NoError(t, err) rule := &dataprovider.EventRule{ Name: "rule", @@ -1475,7 +1475,7 @@ func TestScheduledActions(t *testing.T) { job.Run() // rule not found assert.NoDirExists(t, backupsPath) - err = dataprovider.AddEventRule(rule, "", "") + err = dataprovider.AddEventRule(rule, "", "", "") assert.NoError(t, err) job.Run() @@ -1490,13 +1490,13 @@ func TestScheduledActions(t *testing.T) { Attachments: []string{"/file1.txt"}, }, } - err = dataprovider.UpdateEventAction(action, "", "") + err = dataprovider.UpdateEventAction(action, "", "", "") assert.NoError(t, err) job.Run() // action is not compatible with a scheduled rule - err = dataprovider.DeleteEventRule(rule.Name, "", "") + err = dataprovider.DeleteEventRule(rule.Name, "", "", "") assert.NoError(t, err) - err = dataprovider.DeleteEventAction(action.Name, "", "") + err = dataprovider.DeleteEventAction(action.Name, "", "", "") assert.NoError(t, err) err = os.RemoveAll(backupsPath) assert.NoError(t, err) diff --git a/internal/common/protocol_test.go b/internal/common/protocol_test.go index 6a30b8f0..d98b0988 100644 --- a/internal/common/protocol_test.go +++ b/internal/common/protocol_test.go @@ -3295,7 +3295,7 @@ func TestDelayedQuotaUpdater(t *testing.T) { Name: "folder", MappedPath: filepath.Join(os.TempDir(), "p"), } - err = dataprovider.AddFolder(&folder, "", "") + err = dataprovider.AddFolder(&folder, "", "", "") assert.NoError(t, err) err = dataprovider.UpdateVirtualFolderQuota(&folder, 10, 6000, false) @@ -3322,7 +3322,7 @@ func TestDelayedQuotaUpdater(t *testing.T) { assert.Equal(t, 10, folderGet.UsedQuotaFiles) assert.Equal(t, int64(6000), folderGet.UsedQuotaSize) - err = dataprovider.DeleteFolder(folder.Name, "", "") + err = dataprovider.DeleteFolder(folder.Name, "", "", "") assert.NoError(t, err) err = dataprovider.Close() @@ -5669,13 +5669,13 @@ func TestEventRuleIPBlocked(t *testing.T) { assert.True(t, util.Contains(email.To, "test4@example.com")) assert.Contains(t, email.Data, `Subject: New "IP Blocked"`) - err = dataprovider.DeleteEventRule(rule1.Name, "", "") + err = dataprovider.DeleteEventRule(rule1.Name, "", "", "") assert.NoError(t, err) - err = dataprovider.DeleteEventRule(rule2.Name, "", "") + err = dataprovider.DeleteEventRule(rule2.Name, "", "", "") assert.NoError(t, err) - err = dataprovider.DeleteEventAction(action1.Name, "", "") + err = dataprovider.DeleteEventAction(action1.Name, "", "", "") assert.NoError(t, err) - err = dataprovider.DeleteEventAction(action2.Name, "", "") + err = dataprovider.DeleteEventAction(action2.Name, "", "", "") assert.NoError(t, err) err = dataprovider.DeleteUser(user.Username, "", "", "") assert.NoError(t, err) @@ -6125,7 +6125,7 @@ func TestBuiltinKeyboardInteractiveAuthentication(t *testing.T) { Secret: kms.NewPlainSecret(secret), Protocols: []string{common.ProtocolSSH}, } - err = dataprovider.UpdateUser(&user, "", "") + err = dataprovider.UpdateUser(&user, "", "", "") assert.NoError(t, err) passcode, err := generateTOTPPasscode(secret, otp.AlgorithmSHA1) assert.NoError(t, err) diff --git a/internal/common/transferschecker_test.go b/internal/common/transferschecker_test.go index 1311f7c2..b615538b 100644 --- a/internal/common/transferschecker_test.go +++ b/internal/common/transferschecker_test.go @@ -76,12 +76,12 @@ func TestTransfersCheckerDiskQuota(t *testing.T) { }, }, } - err := dataprovider.AddGroup(&group, "", "") + err := dataprovider.AddGroup(&group, "", "", "") assert.NoError(t, err) group, err = dataprovider.GroupExists(groupName) assert.NoError(t, err) assert.Equal(t, int64(120), group.UserSettings.QuotaSize) - err = dataprovider.AddUser(&user, "", "") + err = dataprovider.AddUser(&user, "", "", "") assert.NoError(t, err) user, err = dataprovider.GetUserWithGroupSettings(username, "") assert.NoError(t, err) @@ -154,7 +154,7 @@ func TestTransfersCheckerDiskQuota(t *testing.T) { assert.True(t, conn3.IsQuotaExceededError(transfer3.GetAbortError())) // update the user quota size group.UserSettings.QuotaSize = 1000 - err = dataprovider.UpdateGroup(&group, []string{username}, "", "") + err = dataprovider.UpdateGroup(&group, []string{username}, "", "", "") assert.NoError(t, err) transfer1.errAbort = nil transfer2.errAbort = nil @@ -164,7 +164,7 @@ func TestTransfersCheckerDiskQuota(t *testing.T) { assert.Nil(t, transfer3.errAbort) group.UserSettings.QuotaSize = 0 - err = dataprovider.UpdateGroup(&group, []string{username}, "", "") + err = dataprovider.UpdateGroup(&group, []string{username}, "", "", "") assert.NoError(t, err) Connections.checkTransfers() assert.Nil(t, transfer1.errAbort) @@ -251,11 +251,11 @@ func TestTransfersCheckerDiskQuota(t *testing.T) { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) - err = dataprovider.DeleteFolder(folderName, "", "") + err = dataprovider.DeleteFolder(folderName, "", "", "") assert.NoError(t, err) err = os.RemoveAll(filepath.Join(os.TempDir(), folderName)) assert.NoError(t, err) - err = dataprovider.DeleteGroup(groupName, "", "") + err = dataprovider.DeleteGroup(groupName, "", "", "") assert.NoError(t, err) } @@ -273,7 +273,7 @@ func TestTransferCheckerTransferQuota(t *testing.T) { }, }, } - err := dataprovider.AddUser(&user, "", "") + err := dataprovider.AddUser(&user, "", "", "") assert.NoError(t, err) connID1 := xid.New().String() @@ -634,7 +634,7 @@ func TestGetUsersForQuotaCheck(t *testing.T) { }, }, } - err = dataprovider.AddUser(&user, "", "") + err = dataprovider.AddUser(&user, "", "", "") assert.NoError(t, err) err = dataprovider.UpdateVirtualFolderQuota(&vfs.BaseVirtualFolder{Name: fmt.Sprintf("f%v", i)}, 1, 50, false) assert.NoError(t, err) @@ -673,7 +673,7 @@ func TestGetUsersForQuotaCheck(t *testing.T) { for i := 0; i < 40; i++ { err = dataprovider.DeleteUser(fmt.Sprintf("user%v", i), "", "", "") assert.NoError(t, err) - err = dataprovider.DeleteFolder(fmt.Sprintf("f%v", i), "", "") + err = dataprovider.DeleteFolder(fmt.Sprintf("f%v", i), "", "", "") assert.NoError(t, err) } diff --git a/internal/dataprovider/actions.go b/internal/dataprovider/actions.go index 2acf63d3..78e0efa5 100644 --- a/internal/dataprovider/actions.go +++ b/internal/dataprovider/actions.go @@ -58,7 +58,7 @@ var ( reservedUsers = []string{ActionExecutorSelf, ActionExecutorSystem} ) -func executeAction(operation, executor, ip, objectType, objectName string, object plugin.Renderer) { +func executeAction(operation, executor, ip, objectType, objectName, role string, object plugin.Renderer) { if plugin.Handler.HasNotifiers() { plugin.Handler.NotifyProviderEvent(¬ifier.ProviderEvent{ Action: operation, @@ -66,11 +66,12 @@ func executeAction(operation, executor, ip, objectType, objectName string, objec ObjectType: objectType, ObjectName: objectName, IP: ip, + Role: role, Timestamp: time.Now().UnixNano(), }, object) } if fnHandleRuleForProviderEvent != nil { - fnHandleRuleForProviderEvent(operation, executor, ip, objectType, objectName, object) + fnHandleRuleForProviderEvent(operation, executor, ip, objectType, objectName, role, object) } if config.Actions.Hook == "" { return @@ -105,6 +106,9 @@ func executeAction(operation, executor, ip, objectType, objectName string, objec q.Add("ip", ip) q.Add("object_type", objectType) q.Add("object_name", objectName) + if role != "" { + q.Add("role", role) + } q.Add("timestamp", fmt.Sprintf("%d", time.Now().UnixNano())) url.RawQuery = q.Encode() startTime := time.Now() @@ -114,15 +118,15 @@ func executeAction(operation, executor, ip, objectType, objectName string, objec respCode = resp.StatusCode resp.Body.Close() } - providerLog(logger.LevelDebug, "notified operation %#v to URL: %v status code: %v, elapsed: %v err: %v", + providerLog(logger.LevelDebug, "notified operation %q to URL: %s status code: %d, elapsed: %s err: %v", operation, url.Redacted(), respCode, time.Since(startTime), err) - } else { - executeNotificationCommand(operation, executor, ip, objectType, objectName, dataAsJSON) //nolint:errcheck // the error is used in test cases only + return } + executeNotificationCommand(operation, executor, ip, objectType, objectName, role, dataAsJSON) //nolint:errcheck // the error is used in test cases only }() } -func executeNotificationCommand(operation, executor, ip, objectType, objectName string, objectAsJSON []byte) error { +func executeNotificationCommand(operation, executor, ip, objectType, objectName, role string, objectAsJSON []byte) error { if !filepath.IsAbs(config.Actions.Hook) { err := fmt.Errorf("invalid notification command %#v", config.Actions.Hook) logger.Warn(logSender, "", "unable to execute notification command: %v", err) @@ -140,6 +144,7 @@ func executeNotificationCommand(operation, executor, ip, objectType, objectName fmt.Sprintf("SFTPGO_PROVIDER_OBJECT_NAME=%s", objectName), fmt.Sprintf("SFTPGO_PROVIDER_USERNAME=%s", executor), fmt.Sprintf("SFTPGO_PROVIDER_IP=%s", ip), + fmt.Sprintf("SFTPGO_PROVIDER_ROLE=%s", role), fmt.Sprintf("SFTPGO_PROVIDER_TIMESTAMP=%d", util.GetTimeAsMsSinceEpoch(time.Now())), fmt.Sprintf("SFTPGO_PROVIDER_OBJECT=%s", string(objectAsJSON))) diff --git a/internal/dataprovider/admin.go b/internal/dataprovider/admin.go index d4640c42..4eb4ba49 100644 --- a/internal/dataprovider/admin.go +++ b/internal/dataprovider/admin.go @@ -75,7 +75,7 @@ var ( PermAdminManageAPIKeys, PermAdminQuotaScans, PermAdminManageSystem, PermAdminManageDefender, PermAdminViewDefender, PermAdminRetentionChecks, PermAdminMetadataChecks, PermAdminViewEvents} forbiddenPermsForRoleAdmins = []string{PermAdminAny, PermAdminManageAdmins, PermAdminManageSystem, - PermAdminManageEventRules, PermAdminManageRoles, PermAdminViewEvents} + PermAdminManageEventRules, PermAdminManageRoles} ) // AdminTOTPConfig defines the time-based one time password configuration diff --git a/internal/dataprovider/dataprovider.go b/internal/dataprovider/dataprovider.go index 86950af2..c36269ee 100644 --- a/internal/dataprovider/dataprovider.go +++ b/internal/dataprovider/dataprovider.go @@ -233,7 +233,7 @@ type FnReloadRules func() type FnRemoveRule func(name string) // FnHandleRuleForProviderEvent define the callback to handle event rules for provider events -type FnHandleRuleForProviderEvent func(operation, executor, ip, objectType, objectName string, object plugin.Renderer) +type FnHandleRuleForProviderEvent func(operation, executor, ip, objectType, objectName, role string, object plugin.Renderer) // SetEventRulesCallbacks sets the event rules callbacks func SetEventRulesCallbacks(reload FnReloadRules, remove FnRemoveRule, handle FnHandleRuleForProviderEvent) { @@ -1504,32 +1504,32 @@ func GetUsedVirtualFolderQuota(name string) (int, int64, error) { } // AddShare adds a new share -func AddShare(share *Share, executor, ipAddress string) error { +func AddShare(share *Share, executor, ipAddress, role string) error { err := provider.addShare(share) if err == nil { - executeAction(operationAdd, executor, ipAddress, actionObjectShare, share.ShareID, share) + executeAction(operationAdd, executor, ipAddress, actionObjectShare, share.ShareID, role, share) } return err } // UpdateShare updates an existing share -func UpdateShare(share *Share, executor, ipAddress string) error { +func UpdateShare(share *Share, executor, ipAddress, role string) error { err := provider.updateShare(share) if err == nil { - executeAction(operationUpdate, executor, ipAddress, actionObjectShare, share.ShareID, share) + executeAction(operationUpdate, executor, ipAddress, actionObjectShare, share.ShareID, role, share) } return err } // DeleteShare deletes an existing share -func DeleteShare(shareID string, executor, ipAddress string) error { +func DeleteShare(shareID string, executor, ipAddress, role string) error { share, err := provider.shareExists(shareID, executor) if err != nil { return err } err = provider.deleteShare(share) if err == nil { - executeAction(operationDelete, executor, ipAddress, actionObjectShare, shareID, &share) + executeAction(operationDelete, executor, ipAddress, actionObjectShare, shareID, role, &share) } return err } @@ -1543,26 +1543,26 @@ func ShareExists(shareID, username string) (Share, error) { } // AddRole adds a new role -func AddRole(role *Role, executor, ipAddress string) error { +func AddRole(role *Role, executor, ipAddress, executorRole string) error { role.Name = config.convertName(role.Name) err := provider.addRole(role) if err == nil { - executeAction(operationAdd, executor, ipAddress, actionObjectRole, role.Name, role) + executeAction(operationAdd, executor, ipAddress, actionObjectRole, role.Name, executorRole, role) } return err } // UpdateRole updates an existing Role -func UpdateRole(role *Role, executor, ipAddress string) error { +func UpdateRole(role *Role, executor, ipAddress, executorRole string) error { err := provider.updateRole(role) if err == nil { - executeAction(operationUpdate, executor, ipAddress, actionObjectRole, role.Name, role) + executeAction(operationUpdate, executor, ipAddress, actionObjectRole, role.Name, executorRole, role) } return err } // DeleteRole deletes an existing Role -func DeleteRole(name string, executor, ipAddress string) error { +func DeleteRole(name string, executor, ipAddress, executorRole string) error { name = config.convertName(name) role, err := provider.roleExists(name) if err != nil { @@ -1574,13 +1574,13 @@ func DeleteRole(name string, executor, ipAddress string) error { } err = provider.deleteRole(role) if err == nil { - executeAction(operationDelete, executor, ipAddress, actionObjectRole, role.Name, &role) + executeAction(operationDelete, executor, ipAddress, actionObjectRole, role.Name, executorRole, &role) for _, user := range role.Users { provider.setUpdatedAt(user) u, err := provider.userExists(user, "") if err == nil { webDAVUsersCache.swap(&u) - executeAction(operationUpdate, executor, ipAddress, actionObjectUser, u.Username, &u) + executeAction(operationUpdate, executor, ipAddress, actionObjectUser, u.Username, u.Role, &u) } } } @@ -1594,17 +1594,17 @@ func RoleExists(name string) (Role, error) { } // AddGroup adds a new group -func AddGroup(group *Group, executor, ipAddress string) error { +func AddGroup(group *Group, executor, ipAddress, role string) error { group.Name = config.convertName(group.Name) err := provider.addGroup(group) if err == nil { - executeAction(operationAdd, executor, ipAddress, actionObjectGroup, group.Name, group) + executeAction(operationAdd, executor, ipAddress, actionObjectGroup, group.Name, role, group) } return err } // UpdateGroup updates an existing Group -func UpdateGroup(group *Group, users []string, executor, ipAddress string) error { +func UpdateGroup(group *Group, users []string, executor, ipAddress, role string) error { err := provider.updateGroup(group) if err == nil { for _, user := range users { @@ -1612,18 +1612,17 @@ func UpdateGroup(group *Group, users []string, executor, ipAddress string) error u, err := provider.userExists(user, "") if err == nil { webDAVUsersCache.swap(&u) - executeAction(operationUpdate, executor, ipAddress, actionObjectUser, u.Username, &u) } else { RemoveCachedWebDAVUser(user) } } - executeAction(operationUpdate, executor, ipAddress, actionObjectGroup, group.Name, group) + executeAction(operationUpdate, executor, ipAddress, actionObjectGroup, group.Name, role, group) } return err } // DeleteGroup deletes an existing Group -func DeleteGroup(name string, executor, ipAddress string) error { +func DeleteGroup(name string, executor, ipAddress, role string) error { name = config.convertName(name) group, err := provider.groupExists(name) if err != nil { @@ -1639,11 +1638,11 @@ func DeleteGroup(name string, executor, ipAddress string) error { provider.setUpdatedAt(user) u, err := provider.userExists(user, "") if err == nil { - executeAction(operationUpdate, executor, ipAddress, actionObjectUser, u.Username, &u) + executeAction(operationUpdate, executor, ipAddress, actionObjectUser, u.Username, u.Role, &u) } RemoveCachedWebDAVUser(user) } - executeAction(operationDelete, executor, ipAddress, actionObjectGroup, group.Name, &group) + executeAction(operationDelete, executor, ipAddress, actionObjectGroup, group.Name, role, &group) } return err } @@ -1655,32 +1654,32 @@ func GroupExists(name string) (Group, error) { } // AddAPIKey adds a new API key -func AddAPIKey(apiKey *APIKey, executor, ipAddress string) error { +func AddAPIKey(apiKey *APIKey, executor, ipAddress, role string) error { err := provider.addAPIKey(apiKey) if err == nil { - executeAction(operationAdd, executor, ipAddress, actionObjectAPIKey, apiKey.KeyID, apiKey) + executeAction(operationAdd, executor, ipAddress, actionObjectAPIKey, apiKey.KeyID, role, apiKey) } return err } // UpdateAPIKey updates an existing API key -func UpdateAPIKey(apiKey *APIKey, executor, ipAddress string) error { +func UpdateAPIKey(apiKey *APIKey, executor, ipAddress, role string) error { err := provider.updateAPIKey(apiKey) if err == nil { - executeAction(operationUpdate, executor, ipAddress, actionObjectAPIKey, apiKey.KeyID, apiKey) + executeAction(operationUpdate, executor, ipAddress, actionObjectAPIKey, apiKey.KeyID, role, apiKey) } return err } // DeleteAPIKey deletes an existing API key -func DeleteAPIKey(keyID string, executor, ipAddress string) error { +func DeleteAPIKey(keyID string, executor, ipAddress, role string) error { apiKey, err := provider.apiKeyExists(keyID) if err != nil { return err } err = provider.deleteAPIKey(apiKey) if err == nil { - executeAction(operationDelete, executor, ipAddress, actionObjectAPIKey, apiKey.KeyID, &apiKey) + executeAction(operationDelete, executor, ipAddress, actionObjectAPIKey, apiKey.KeyID, role, &apiKey) } return err } @@ -1705,29 +1704,29 @@ func EventActionExists(name string) (BaseEventAction, error) { } // AddEventAction adds a new event action -func AddEventAction(action *BaseEventAction, executor, ipAddress string) error { +func AddEventAction(action *BaseEventAction, executor, ipAddress, role string) error { action.Name = config.convertName(action.Name) err := provider.addEventAction(action) if err == nil { - executeAction(operationAdd, executor, ipAddress, actionObjectEventAction, action.Name, action) + executeAction(operationAdd, executor, ipAddress, actionObjectEventAction, action.Name, role, action) } return err } // UpdateEventAction updates an existing event action -func UpdateEventAction(action *BaseEventAction, executor, ipAddress string) error { +func UpdateEventAction(action *BaseEventAction, executor, ipAddress, role string) error { err := provider.updateEventAction(action) if err == nil { if fnReloadRules != nil { fnReloadRules() } - executeAction(operationUpdate, executor, ipAddress, actionObjectEventAction, action.Name, action) + executeAction(operationUpdate, executor, ipAddress, actionObjectEventAction, action.Name, role, action) } return err } // DeleteEventAction deletes an existing event action -func DeleteEventAction(name string, executor, ipAddress string) error { +func DeleteEventAction(name string, executor, ipAddress, role string) error { name = config.convertName(name) action, err := provider.eventActionExists(name) if err != nil { @@ -1739,7 +1738,7 @@ func DeleteEventAction(name string, executor, ipAddress string) error { } err = provider.deleteEventAction(action) if err == nil { - executeAction(operationDelete, executor, ipAddress, actionObjectEventAction, action.Name, &action) + executeAction(operationDelete, executor, ipAddress, actionObjectEventAction, action.Name, role, &action) } return err } @@ -1761,32 +1760,32 @@ func EventRuleExists(name string) (EventRule, error) { } // AddEventRule adds a new event rule -func AddEventRule(rule *EventRule, executor, ipAddress string) error { +func AddEventRule(rule *EventRule, executor, ipAddress, role string) error { rule.Name = config.convertName(rule.Name) err := provider.addEventRule(rule) if err == nil { if fnReloadRules != nil { fnReloadRules() } - executeAction(operationAdd, executor, ipAddress, actionObjectEventRule, rule.Name, rule) + executeAction(operationAdd, executor, ipAddress, actionObjectEventRule, rule.Name, role, rule) } return err } // UpdateEventRule updates an existing event rule -func UpdateEventRule(rule *EventRule, executor, ipAddress string) error { +func UpdateEventRule(rule *EventRule, executor, ipAddress, role string) error { err := provider.updateEventRule(rule) if err == nil { if fnReloadRules != nil { fnReloadRules() } - executeAction(operationUpdate, executor, ipAddress, actionObjectEventRule, rule.Name, rule) + executeAction(operationUpdate, executor, ipAddress, actionObjectEventRule, rule.Name, role, rule) } return err } // DeleteEventRule deletes an existing event rule -func DeleteEventRule(name string, executor, ipAddress string) error { +func DeleteEventRule(name string, executor, ipAddress, role string) error { name = config.convertName(name) rule, err := provider.eventRuleExists(name) if err != nil { @@ -1797,7 +1796,7 @@ func DeleteEventRule(name string, executor, ipAddress string) error { if fnRemoveRule != nil { fnRemoveRule(rule.Name) } - executeAction(operationDelete, executor, ipAddress, actionObjectEventRule, rule.Name, &rule) + executeAction(operationDelete, executor, ipAddress, actionObjectEventRule, rule.Name, role, &rule) } return err } @@ -1857,7 +1856,7 @@ func HasAdmin() bool { } // AddAdmin adds a new SFTPGo admin -func AddAdmin(admin *Admin, executor, ipAddress string) error { +func AddAdmin(admin *Admin, executor, ipAddress, role string) error { admin.Filters.RecoveryCodes = nil admin.Filters.TOTPConfig = AdminTOTPConfig{ Enabled: false, @@ -1866,22 +1865,22 @@ func AddAdmin(admin *Admin, executor, ipAddress string) error { err := provider.addAdmin(admin) if err == nil { isAdminCreated.Store(true) - executeAction(operationAdd, executor, ipAddress, actionObjectAdmin, admin.Username, admin) + executeAction(operationAdd, executor, ipAddress, actionObjectAdmin, admin.Username, role, admin) } return err } // UpdateAdmin updates an existing SFTPGo admin -func UpdateAdmin(admin *Admin, executor, ipAddress string) error { +func UpdateAdmin(admin *Admin, executor, ipAddress, role string) error { err := provider.updateAdmin(admin) if err == nil { - executeAction(operationUpdate, executor, ipAddress, actionObjectAdmin, admin.Username, admin) + executeAction(operationUpdate, executor, ipAddress, actionObjectAdmin, admin.Username, role, admin) } return err } // DeleteAdmin deletes an existing SFTPGo admin -func DeleteAdmin(username, executor, ipAddress string) error { +func DeleteAdmin(username, executor, ipAddress, role string) error { username = config.convertName(username) admin, err := provider.adminExists(username) if err != nil { @@ -1889,7 +1888,7 @@ func DeleteAdmin(username, executor, ipAddress string) error { } err = provider.deleteAdmin(admin) if err == nil { - executeAction(operationDelete, executor, ipAddress, actionObjectAdmin, admin.Username, &admin) + executeAction(operationDelete, executor, ipAddress, actionObjectAdmin, admin.Username, role, &admin) } return err } @@ -1932,17 +1931,17 @@ func GetUserVariants(username, role string) (User, User, error) { } // AddUser adds a new SFTPGo user. -func AddUser(user *User, executor, ipAddress string) error { +func AddUser(user *User, executor, ipAddress, role string) error { user.Username = config.convertName(user.Username) err := provider.addUser(user) if err == nil { - executeAction(operationAdd, executor, ipAddress, actionObjectUser, user.Username, user) + executeAction(operationAdd, executor, ipAddress, actionObjectUser, user.Username, role, user) } return err } // UpdateUserPassword updates the user password -func UpdateUserPassword(username, plainPwd, executor, ipAddress string) error { +func UpdateUserPassword(username, plainPwd, executor, ipAddress, role string) error { hashedPwd, err := hashPlainPassword(plainPwd) if err != nil { return util.NewGenericError(fmt.Sprintf("unable to set the new password: %v", err)) @@ -1952,12 +1951,12 @@ func UpdateUserPassword(username, plainPwd, executor, ipAddress string) error { return util.NewGenericError(fmt.Sprintf("unable to set the new password: %v", err)) } cachedPasswords.Remove(username) - executeAction(operationUpdate, executor, ipAddress, actionObjectUser, username, &User{}) + executeAction(operationUpdate, executor, ipAddress, actionObjectUser, username, role, &User{}) return nil } // UpdateUser updates an existing SFTPGo user. -func UpdateUser(user *User, executor, ipAddress string) error { +func UpdateUser(user *User, executor, ipAddress, role string) error { if user.groupSettingsApplied { return errors.New("cannot save a user with group settings applied") } @@ -1965,7 +1964,7 @@ func UpdateUser(user *User, executor, ipAddress string) error { if err == nil { webDAVUsersCache.swap(user) cachedPasswords.Remove(user.Username) - executeAction(operationUpdate, executor, ipAddress, actionObjectUser, user.Username, user) + executeAction(operationUpdate, executor, ipAddress, actionObjectUser, user.Username, role, user) } return err } @@ -1982,7 +1981,7 @@ func DeleteUser(username, executor, ipAddress, role string) error { RemoveCachedWebDAVUser(user.Username) delayedQuotaUpdater.resetUserQuota(user.Username) cachedPasswords.Remove(username) - executeAction(operationDelete, executor, ipAddress, actionObjectUser, user.Username, &user) + executeAction(operationDelete, executor, ipAddress, actionObjectUser, user.Username, role, &user) } return err } @@ -2106,20 +2105,20 @@ func GetUsersForQuotaCheck(toFetch map[string]bool) ([]User, error) { } // AddFolder adds a new virtual folder. -func AddFolder(folder *vfs.BaseVirtualFolder, executor, ipAddress string) error { +func AddFolder(folder *vfs.BaseVirtualFolder, executor, ipAddress, role string) error { folder.Name = config.convertName(folder.Name) err := provider.addFolder(folder) if err == nil { - executeAction(operationAdd, executor, ipAddress, actionObjectFolder, folder.Name, &wrappedFolder{Folder: *folder}) + executeAction(operationAdd, executor, ipAddress, actionObjectFolder, folder.Name, role, &wrappedFolder{Folder: *folder}) } return err } // UpdateFolder updates the specified virtual folder -func UpdateFolder(folder *vfs.BaseVirtualFolder, users []string, groups []string, executor, ipAddress string) error { +func UpdateFolder(folder *vfs.BaseVirtualFolder, users []string, groups []string, executor, ipAddress, role string) error { err := provider.updateFolder(folder) if err == nil { - executeAction(operationUpdate, executor, ipAddress, actionObjectFolder, folder.Name, &wrappedFolder{Folder: *folder}) + executeAction(operationUpdate, executor, ipAddress, actionObjectFolder, folder.Name, role, &wrappedFolder{Folder: *folder}) usersInGroups, errGrp := provider.getUsersInGroups(groups) if errGrp == nil { users = append(users, usersInGroups...) @@ -2132,7 +2131,7 @@ func UpdateFolder(folder *vfs.BaseVirtualFolder, users []string, groups []string u, err := provider.userExists(user, "") if err == nil { webDAVUsersCache.swap(&u) - executeAction(operationUpdate, executor, ipAddress, actionObjectUser, u.Username, &u) + executeAction(operationUpdate, executor, ipAddress, actionObjectUser, u.Username, u.Role, &u) } else { RemoveCachedWebDAVUser(user) } @@ -2142,7 +2141,7 @@ func UpdateFolder(folder *vfs.BaseVirtualFolder, users []string, groups []string } // DeleteFolder deletes an existing folder. -func DeleteFolder(folderName, executor, ipAddress string) error { +func DeleteFolder(folderName, executor, ipAddress, role string) error { folderName = config.convertName(folderName) folder, err := provider.getFolderByName(folderName) if err != nil { @@ -2150,7 +2149,7 @@ func DeleteFolder(folderName, executor, ipAddress string) error { } err = provider.deleteFolder(folder) if err == nil { - executeAction(operationDelete, executor, ipAddress, actionObjectFolder, folder.Name, &wrappedFolder{Folder: folder}) + executeAction(operationDelete, executor, ipAddress, actionObjectFolder, folder.Name, role, &wrappedFolder{Folder: folder}) users := folder.Users usersInGroups, errGrp := provider.getUsersInGroups(folder.Groups) if errGrp == nil { @@ -2163,7 +2162,7 @@ func DeleteFolder(folderName, executor, ipAddress string) error { provider.setUpdatedAt(user) u, err := provider.userExists(user, "") if err == nil { - executeAction(operationUpdate, executor, ipAddress, actionObjectUser, u.Username, &u) + executeAction(operationUpdate, executor, ipAddress, actionObjectUser, u.Username, u.Role, &u) } RemoveCachedWebDAVUser(user) } diff --git a/internal/dataprovider/memory.go b/internal/dataprovider/memory.go index 811846cf..d84fb359 100644 --- a/internal/dataprovider/memory.go +++ b/internal/dataprovider/memory.go @@ -2805,13 +2805,13 @@ func (p *MemoryProvider) restoreEventActions(dump BackupData) error { action := action // pin if err == nil { action.ID = a.ID - err = UpdateEventAction(&action, ActionExecutorSystem, "") + err = UpdateEventAction(&action, ActionExecutorSystem, "", "") if err != nil { providerLog(logger.LevelError, "error updating event action %q: %v", action.Name, err) return err } } else { - err = AddEventAction(&action, ActionExecutorSystem, "") + err = AddEventAction(&action, ActionExecutorSystem, "", "") if err != nil { providerLog(logger.LevelError, "error adding event action %q: %v", action.Name, err) return err @@ -2827,13 +2827,13 @@ func (p *MemoryProvider) restoreEventRules(dump BackupData) error { rule := rule // pin if err == nil { rule.ID = r.ID - err = UpdateEventRule(&rule, ActionExecutorSystem, "") + err = UpdateEventRule(&rule, ActionExecutorSystem, "", "") if err != nil { providerLog(logger.LevelError, "error updating event rule %q: %v", rule.Name, err) return err } } else { - err = AddEventRule(&rule, ActionExecutorSystem, "") + err = AddEventRule(&rule, ActionExecutorSystem, "", "") if err != nil { providerLog(logger.LevelError, "error adding event rule %q: %v", rule.Name, err) return err @@ -2850,13 +2850,13 @@ func (p *MemoryProvider) restoreShares(dump BackupData) error { share.IsRestore = true if err == nil { share.ID = s.ID - err = UpdateShare(&share, ActionExecutorSystem, "") + err = UpdateShare(&share, ActionExecutorSystem, "", "") if err != nil { providerLog(logger.LevelError, "error updating share %#v: %v", share.ShareID, err) return err } } else { - err = AddShare(&share, ActionExecutorSystem, "") + err = AddShare(&share, ActionExecutorSystem, "", "") if err != nil { providerLog(logger.LevelError, "error adding share %#v: %v", share.ShareID, err) return err @@ -2875,13 +2875,13 @@ func (p *MemoryProvider) restoreAPIKeys(dump BackupData) error { apiKey := apiKey // pin if err == nil { apiKey.ID = k.ID - err = UpdateAPIKey(&apiKey, ActionExecutorSystem, "") + err = UpdateAPIKey(&apiKey, ActionExecutorSystem, "", "") if err != nil { providerLog(logger.LevelError, "error updating API key %#v: %v", apiKey.KeyID, err) return err } } else { - err = AddAPIKey(&apiKey, ActionExecutorSystem, "") + err = AddAPIKey(&apiKey, ActionExecutorSystem, "", "") if err != nil { providerLog(logger.LevelError, "error adding API key %#v: %v", apiKey.KeyID, err) return err @@ -2898,13 +2898,13 @@ func (p *MemoryProvider) restoreAdmins(dump BackupData) error { a, err := p.adminExists(admin.Username) if err == nil { admin.ID = a.ID - err = UpdateAdmin(&admin, ActionExecutorSystem, "") + err = UpdateAdmin(&admin, ActionExecutorSystem, "", "") if err != nil { providerLog(logger.LevelError, "error updating admin %#v: %v", admin.Username, err) return err } } else { - err = AddAdmin(&admin, ActionExecutorSystem, "") + err = AddAdmin(&admin, ActionExecutorSystem, "", "") if err != nil { providerLog(logger.LevelError, "error adding admin %#v: %v", admin.Username, err) return err @@ -2921,7 +2921,7 @@ func (p *MemoryProvider) restoreRoles(dump BackupData) error { r, err := p.roleExists(role.Name) if err == nil { role.ID = r.ID - err = UpdateRole(&role, ActionExecutorSystem, "") + err = UpdateRole(&role, ActionExecutorSystem, "", "") if err != nil { providerLog(logger.LevelError, "error updating role %q: %v", role.Name, err) return err @@ -2929,7 +2929,7 @@ func (p *MemoryProvider) restoreRoles(dump BackupData) error { } else { role.Admins = nil role.Users = nil - err = AddRole(&role, ActionExecutorSystem, "") + err = AddRole(&role, ActionExecutorSystem, "", "") if err != nil { providerLog(logger.LevelError, "error adding role %q: %v", role.Name, err) return err @@ -2946,14 +2946,14 @@ func (p *MemoryProvider) restoreGroups(dump BackupData) error { g, err := p.groupExists(group.Name) if err == nil { group.ID = g.ID - err = UpdateGroup(&group, g.Users, ActionExecutorSystem, "") + err = UpdateGroup(&group, g.Users, ActionExecutorSystem, "", "") if err != nil { providerLog(logger.LevelError, "error updating group %#v: %v", group.Name, err) return err } } else { group.Users = nil - err = AddGroup(&group, ActionExecutorSystem, "") + err = AddGroup(&group, ActionExecutorSystem, "", "") if err != nil { providerLog(logger.LevelError, "error adding group %#v: %v", group.Name, err) return err @@ -2970,14 +2970,14 @@ func (p *MemoryProvider) restoreFolders(dump BackupData) error { f, err := p.getFolderByName(folder.Name) if err == nil { folder.ID = f.ID - err = UpdateFolder(&folder, f.Users, f.Groups, ActionExecutorSystem, "") + err = UpdateFolder(&folder, f.Users, f.Groups, ActionExecutorSystem, "", "") if err != nil { providerLog(logger.LevelError, "error updating folder %#v: %v", folder.Name, err) return err } } else { folder.Users = nil - err = AddFolder(&folder, ActionExecutorSystem, "") + err = AddFolder(&folder, ActionExecutorSystem, "", "") if err != nil { providerLog(logger.LevelError, "error adding folder %#v: %v", folder.Name, err) return err @@ -2994,13 +2994,13 @@ func (p *MemoryProvider) restoreUsers(dump BackupData) error { u, err := p.userExists(user.Username, "") if err == nil { user.ID = u.ID - err = UpdateUser(&user, ActionExecutorSystem, "") + err = UpdateUser(&user, ActionExecutorSystem, "", "") if err != nil { providerLog(logger.LevelError, "error updating user %#v: %v", user.Username, err) return err } } else { - err = AddUser(&user, ActionExecutorSystem, "") + err = AddUser(&user, ActionExecutorSystem, "", "") if err != nil { providerLog(logger.LevelError, "error adding user %#v: %v", user.Username, err) return err diff --git a/internal/dataprovider/role.go b/internal/dataprovider/role.go index 2fedd135..af9f2017 100644 --- a/internal/dataprovider/role.go +++ b/internal/dataprovider/role.go @@ -58,6 +58,9 @@ func (r *Role) validate() error { if r.Name == "" { return util.NewValidationError("name is mandatory") } + if len(r.Name) > 255 { + return util.NewValidationError("name is too long, 255 is the maximum length allowed") + } if config.NamingRules&1 == 0 && !usernameRegex.MatchString(r.Name) { return util.NewValidationError(fmt.Sprintf("name %q is not valid, the following characters are allowed: a-zA-Z0-9-_.~", r.Name)) } diff --git a/internal/ftpd/ftpd_test.go b/internal/ftpd/ftpd_test.go index a6229f71..a891c570 100644 --- a/internal/ftpd/ftpd_test.go +++ b/internal/ftpd/ftpd_test.go @@ -1024,7 +1024,7 @@ func TestMultiFactorAuth(t *testing.T) { Secret: kms.NewPlainSecret(secret), Protocols: []string{common.ProtocolFTP}, } - err = dataprovider.UpdateUser(&user, "", "") + err = dataprovider.UpdateUser(&user, "", "", "") assert.NoError(t, err) user.Password = defaultPassword @@ -1073,7 +1073,7 @@ func TestSecondFactorRequirement(t *testing.T) { Secret: kms.NewPlainSecret(secret), Protocols: []string{common.ProtocolFTP}, } - err = dataprovider.UpdateUser(&user, "", "") + err = dataprovider.UpdateUser(&user, "", "", "") assert.NoError(t, err) passcode, err := generateTOTPPasscode(secret, otp.AlgorithmSHA1) assert.NoError(t, err) @@ -1611,7 +1611,7 @@ func TestMaxConnections(t *testing.T) { }, 1000*time.Millisecond, 50*time.Millisecond) user := getTestUser() - err := dataprovider.AddUser(&user, "", "") + err := dataprovider.AddUser(&user, "", "", "") assert.NoError(t, err) user.Password = "" client, err := getFTPClient(user, true, nil) @@ -1641,7 +1641,7 @@ func TestMaxPerHostConnections(t *testing.T) { }, 1000*time.Millisecond, 50*time.Millisecond) user := getTestUser() - err := dataprovider.AddUser(&user, "", "") + err := dataprovider.AddUser(&user, "", "", "") assert.NoError(t, err) user.Password = "" client, err := getFTPClient(user, true, nil) diff --git a/internal/httpd/api_admin.go b/internal/httpd/api_admin.go index 2bb1a2dd..26ab4720 100644 --- a/internal/httpd/api_admin.go +++ b/internal/httpd/api_admin.go @@ -76,7 +76,7 @@ func addAdmin(w http.ResponseWriter, r *http.Request) { sendAPIResponse(w, r, err, "", http.StatusBadRequest) return } - err = dataprovider.AddAdmin(&admin, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)) + err = dataprovider.AddAdmin(&admin, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return @@ -100,7 +100,7 @@ func disableAdmin2FA(w http.ResponseWriter, r *http.Request) { admin.Filters.TOTPConfig = dataprovider.AdminTOTPConfig{ Enabled: false, } - if err := dataprovider.UpdateAdmin(&admin, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil { + if err := dataprovider.UpdateAdmin(&admin, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role); err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return } @@ -156,7 +156,7 @@ func updateAdmin(w http.ResponseWriter, r *http.Request) { admin.Username = username admin.Filters.TOTPConfig = totpConfig admin.Filters.RecoveryCodes = recoveryCodes - if err := dataprovider.UpdateAdmin(&admin, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil { + if err := dataprovider.UpdateAdmin(&admin, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role); err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return } @@ -176,7 +176,7 @@ func deleteAdmin(w http.ResponseWriter, r *http.Request) { return } - err = dataprovider.DeleteAdmin(username, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)) + err = dataprovider.DeleteAdmin(username, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return @@ -227,7 +227,7 @@ func updateAdminProfile(w http.ResponseWriter, r *http.Request) { admin.Email = req.Email admin.Description = req.Description admin.Filters.AllowAPIKeyAuth = req.AllowAPIKeyAuth - if err := dataprovider.UpdateAdmin(&admin, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil { + if err := dataprovider.UpdateAdmin(&admin, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role); err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return } @@ -309,7 +309,7 @@ func doChangeAdminPassword(r *http.Request, currentPassword, newPassword, confir admin.Password = newPassword - return dataprovider.UpdateAdmin(&admin, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr)) + return dataprovider.UpdateAdmin(&admin, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) } func getTokenClaims(r *http.Request) (jwtTokenClaims, error) { diff --git a/internal/httpd/api_eventrule.go b/internal/httpd/api_eventrule.go index 197065c3..0a0af224 100644 --- a/internal/httpd/api_eventrule.go +++ b/internal/httpd/api_eventrule.go @@ -74,7 +74,7 @@ func addEventAction(w http.ResponseWriter, r *http.Request) { sendAPIResponse(w, r, err, "", http.StatusBadRequest) return } - err = dataprovider.AddEventAction(&action, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)) + err = dataprovider.AddEventAction(&action, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return @@ -116,7 +116,7 @@ func updateEventAction(w http.ResponseWriter, r *http.Request) { } } - err = dataprovider.UpdateEventAction(&action, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)) + err = dataprovider.UpdateEventAction(&action, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return @@ -132,7 +132,7 @@ func deleteEventAction(w http.ResponseWriter, r *http.Request) { return } name := getURLParam(r, "name") - err = dataprovider.DeleteEventAction(name, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)) + err = dataprovider.DeleteEventAction(name, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return @@ -190,7 +190,7 @@ func addEventRule(w http.ResponseWriter, r *http.Request) { sendAPIResponse(w, r, err, "", http.StatusBadRequest) return } - err = dataprovider.AddEventRule(&rule, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)) + err = dataprovider.AddEventRule(&rule, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return @@ -224,7 +224,7 @@ func updateEventRule(w http.ResponseWriter, r *http.Request) { rule.ID = ruleID rule.Name = name - err = dataprovider.UpdateEventRule(&rule, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)) + err = dataprovider.UpdateEventRule(&rule, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return @@ -240,7 +240,7 @@ func deleteEventRule(w http.ResponseWriter, r *http.Request) { return } name := getURLParam(r, "name") - err = dataprovider.DeleteEventRule(name, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)) + err = dataprovider.DeleteEventRule(name, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return diff --git a/internal/httpd/api_events.go b/internal/httpd/api_events.go index 530eac51..c978ba54 100644 --- a/internal/httpd/api_events.go +++ b/internal/httpd/api_events.go @@ -119,12 +119,18 @@ func getProviderSearchParamsFromRequest(r *http.Request) (eventsearcher.Provider func searchFsEvents(w http.ResponseWriter, r *http.Request) { r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize) + claims, err := getTokenClaims(r) + if err != nil || claims.Username == "" { + sendAPIResponse(w, r, err, "Invalid token claims", http.StatusBadRequest) + return + } filters, err := getFsSearchParamsFromRequest(r) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return } + filters.Role = getRoleFilterForEventSearch(r, claims.Role) data, _, _, err := plugin.Handler.SearchFsEvents(&filters) if err != nil { @@ -138,12 +144,18 @@ func searchFsEvents(w http.ResponseWriter, r *http.Request) { func searchProviderEvents(w http.ResponseWriter, r *http.Request) { r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize) + claims, err := getTokenClaims(r) + if err != nil || claims.Username == "" { + sendAPIResponse(w, r, err, "Invalid token claims", http.StatusBadRequest) + return + } filters, err := getProviderSearchParamsFromRequest(r) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return } + filters.Role = getRoleFilterForEventSearch(r, claims.Role) data, _, _, err := plugin.Handler.SearchProviderEvents(&filters) if err != nil { @@ -154,3 +166,10 @@ func searchProviderEvents(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.Write(data) //nolint:errcheck } + +func getRoleFilterForEventSearch(r *http.Request, defaultValue string) string { + if defaultValue != "" { + return defaultValue + } + return r.URL.Query().Get("role") +} diff --git a/internal/httpd/api_folder.go b/internal/httpd/api_folder.go index 03fad5bd..9e8bf40e 100644 --- a/internal/httpd/api_folder.go +++ b/internal/httpd/api_folder.go @@ -54,7 +54,7 @@ func addFolder(w http.ResponseWriter, r *http.Request) { sendAPIResponse(w, r, err, "", http.StatusBadRequest) return } - err = dataprovider.AddFolder(&folder, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)) + err = dataprovider.AddFolder(&folder, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return @@ -108,7 +108,7 @@ func updateFolder(w http.ResponseWriter, r *http.Request) { 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)) + err = dataprovider.UpdateFolder(&folder, users, groups, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return @@ -145,7 +145,7 @@ func deleteFolder(w http.ResponseWriter, r *http.Request) { return } name := getURLParam(r, "name") - err = dataprovider.DeleteFolder(name, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)) + err = dataprovider.DeleteFolder(name, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return diff --git a/internal/httpd/api_group.go b/internal/httpd/api_group.go index d0e63119..a994eea4 100644 --- a/internal/httpd/api_group.go +++ b/internal/httpd/api_group.go @@ -54,7 +54,7 @@ func addGroup(w http.ResponseWriter, r *http.Request) { sendAPIResponse(w, r, err, "", http.StatusBadRequest) return } - err = dataprovider.AddGroup(&group, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)) + err = dataprovider.AddGroup(&group, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return @@ -107,7 +107,7 @@ func updateGroup(w http.ResponseWriter, r *http.Request) { updateEncryptedSecrets(&group.UserSettings.FsConfig, currentS3AccessSecret, currentAzAccountKey, currentAzSASUrl, currentGCSCredentials, currentCryptoPassphrase, currentSFTPPassword, currentSFTPKey, currentSFTPKeyPassphrase, currentHTTPPassword, currentHTTPAPIKey) - err = dataprovider.UpdateGroup(&group, users, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)) + err = dataprovider.UpdateGroup(&group, users, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return @@ -144,7 +144,7 @@ func deleteGroup(w http.ResponseWriter, r *http.Request) { return } name := getURLParam(r, "name") - err = dataprovider.DeleteGroup(name, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)) + err = dataprovider.DeleteGroup(name, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return diff --git a/internal/httpd/api_http_user.go b/internal/httpd/api_http_user.go index baa73345..e5c69ddc 100644 --- a/internal/httpd/api_http_user.go +++ b/internal/httpd/api_http_user.go @@ -453,7 +453,7 @@ func updateUserProfile(w http.ResponseWriter, r *http.Request) { user.Email = req.Email user.Description = req.Description } - if err := dataprovider.UpdateUser(&user, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil { + if err := dataprovider.UpdateUser(&user, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr), user.Role); err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return } @@ -498,7 +498,7 @@ func doChangeUserPassword(r *http.Request, currentPassword, newPassword, confirm } return dataprovider.UpdateUserPassword(claims.Username, newPassword, dataprovider.ActionExecutorSelf, - util.GetIPFromRemoteAddress(r.RemoteAddr)) + util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) } func setModificationTimeFromHeader(r *http.Request, c *Connection, filePath string) { diff --git a/internal/httpd/api_keys.go b/internal/httpd/api_keys.go index 2e81923d..e32181a2 100644 --- a/internal/httpd/api_keys.go +++ b/internal/httpd/api_keys.go @@ -70,7 +70,7 @@ func addAPIKey(w http.ResponseWriter, r *http.Request) { apiKey.KeyID = "" apiKey.Key = "" apiKey.LastUseAt = 0 - err = dataprovider.AddAPIKey(&apiKey, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)) + err = dataprovider.AddAPIKey(&apiKey, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return @@ -105,7 +105,7 @@ func updateAPIKey(w http.ResponseWriter, r *http.Request) { } apiKey.KeyID = keyID - if err := dataprovider.UpdateAPIKey(&apiKey, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil { + if err := dataprovider.UpdateAPIKey(&apiKey, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role); err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return } @@ -121,7 +121,7 @@ func deleteAPIKey(w http.ResponseWriter, r *http.Request) { return } - err = dataprovider.DeleteAPIKey(keyID, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)) + err = dataprovider.DeleteAPIKey(keyID, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return diff --git a/internal/httpd/api_maintenance.go b/internal/httpd/api_maintenance.go index de4d87a8..84fae16f 100644 --- a/internal/httpd/api_maintenance.go +++ b/internal/httpd/api_maintenance.go @@ -130,7 +130,7 @@ func loadDataFromRequest(w http.ResponseWriter, r *http.Request) { sendAPIResponse(w, r, err, "", getRespStatus(err)) return } - if err := restoreBackup(content, "", scanQuota, mode, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil { + if err := restoreBackup(content, "", scanQuota, mode, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role); err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) } sendAPIResponse(w, r, err, "Data restored", http.StatusOK) @@ -168,51 +168,51 @@ func loadData(w http.ResponseWriter, r *http.Request) { sendAPIResponse(w, r, err, "", getRespStatus(err)) return } - if err := restoreBackup(content, inputFile, scanQuota, mode, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil { + if err := restoreBackup(content, inputFile, scanQuota, mode, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role); err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) } sendAPIResponse(w, r, err, "Data restored", http.StatusOK) } -func restoreBackup(content []byte, inputFile string, scanQuota, mode int, executor, ipAddress string) error { +func restoreBackup(content []byte, inputFile string, scanQuota, mode int, executor, ipAddress, role string) error { dump, err := dataprovider.ParseDumpData(content) if err != nil { return util.NewValidationError(fmt.Sprintf("unable to parse backup content: %v", err)) } - if err = RestoreRoles(dump.Roles, inputFile, mode, executor, ipAddress); err != nil { + if err = RestoreRoles(dump.Roles, inputFile, mode, executor, ipAddress, role); err != nil { return err } - if err = RestoreFolders(dump.Folders, inputFile, mode, scanQuota, executor, ipAddress); err != nil { + if err = RestoreFolders(dump.Folders, inputFile, mode, scanQuota, executor, ipAddress, role); err != nil { return err } - if err = RestoreGroups(dump.Groups, inputFile, mode, executor, ipAddress); err != nil { + if err = RestoreGroups(dump.Groups, inputFile, mode, executor, ipAddress, role); err != nil { return err } - if err = RestoreUsers(dump.Users, inputFile, mode, scanQuota, executor, ipAddress); err != nil { + if err = RestoreUsers(dump.Users, inputFile, mode, scanQuota, executor, ipAddress, role); err != nil { return err } - if err = RestoreAdmins(dump.Admins, inputFile, mode, executor, ipAddress); err != nil { + if err = RestoreAdmins(dump.Admins, inputFile, mode, executor, ipAddress, role); err != nil { return err } - if err = RestoreAPIKeys(dump.APIKeys, inputFile, mode, executor, ipAddress); err != nil { + if err = RestoreAPIKeys(dump.APIKeys, inputFile, mode, executor, ipAddress, role); err != nil { return err } - if err = RestoreShares(dump.Shares, inputFile, mode, executor, ipAddress); err != nil { + if err = RestoreShares(dump.Shares, inputFile, mode, executor, ipAddress, role); err != nil { return err } - if err = RestoreEventActions(dump.EventActions, inputFile, mode, executor, ipAddress); err != nil { + if err = RestoreEventActions(dump.EventActions, inputFile, mode, executor, ipAddress, role); err != nil { return err } - if err = RestoreEventRules(dump.EventRules, inputFile, mode, executor, ipAddress); err != nil { + if err = RestoreEventRules(dump.EventRules, inputFile, mode, executor, ipAddress, role); err != nil { return err } @@ -248,7 +248,7 @@ func getLoaddataOptions(r *http.Request) (string, int, int, error) { } // RestoreFolders restores the specified folders -func RestoreFolders(folders []vfs.BaseVirtualFolder, inputFile string, mode, scanQuota int, executor, ipAddress string) error { +func RestoreFolders(folders []vfs.BaseVirtualFolder, inputFile string, mode, scanQuota int, executor, ipAddress, role string) error { for _, folder := range folders { folder := folder // pin f, err := dataprovider.GetFolderByName(folder.Name) @@ -259,11 +259,11 @@ func RestoreFolders(folders []vfs.BaseVirtualFolder, inputFile string, mode, sca } folder.ID = f.ID folder.Name = f.Name - err = dataprovider.UpdateFolder(&folder, f.Users, f.Groups, executor, ipAddress) + err = dataprovider.UpdateFolder(&folder, f.Users, f.Groups, executor, ipAddress, role) logger.Debug(logSender, "", "restoring existing folder %#v, dump file: %#v, error: %v", folder.Name, inputFile, err) } else { folder.Users = nil - err = dataprovider.AddFolder(&folder, executor, ipAddress) + err = dataprovider.AddFolder(&folder, executor, ipAddress, role) logger.Debug(logSender, "", "adding new folder %#v, dump file: %#v, error: %v", folder.Name, inputFile, err) } if err != nil { @@ -281,7 +281,7 @@ func RestoreFolders(folders []vfs.BaseVirtualFolder, inputFile string, mode, sca // RestoreShares restores the specified shares func RestoreShares(shares []dataprovider.Share, inputFile string, mode int, executor, - ipAddress string, + ipAddress, role string, ) error { for _, share := range shares { share := share // pin @@ -293,10 +293,10 @@ func RestoreShares(shares []dataprovider.Share, inputFile string, mode int, exec continue } share.ID = s.ID - err = dataprovider.UpdateShare(&share, executor, ipAddress) + err = dataprovider.UpdateShare(&share, executor, ipAddress, role) logger.Debug(logSender, "", "restoring existing share %#v, dump file: %#v, error: %v", share.ShareID, inputFile, err) } else { - err = dataprovider.AddShare(&share, executor, ipAddress) + err = dataprovider.AddShare(&share, executor, ipAddress, role) logger.Debug(logSender, "", "adding new share %#v, dump file: %#v, error: %v", share.ShareID, inputFile, err) } if err != nil { @@ -307,7 +307,7 @@ func RestoreShares(shares []dataprovider.Share, inputFile string, mode int, exec } // RestoreEventActions restores the specified event actions -func RestoreEventActions(actions []dataprovider.BaseEventAction, inputFile string, mode int, executor, ipAddress string) error { +func RestoreEventActions(actions []dataprovider.BaseEventAction, inputFile string, mode int, executor, ipAddress, role string) error { for _, action := range actions { action := action // pin a, err := dataprovider.EventActionExists(action.Name) @@ -317,10 +317,10 @@ func RestoreEventActions(actions []dataprovider.BaseEventAction, inputFile strin continue } action.ID = a.ID - err = dataprovider.UpdateEventAction(&action, executor, ipAddress) + err = dataprovider.UpdateEventAction(&action, executor, ipAddress, role) logger.Debug(logSender, "", "restoring event action %q, dump file: %q, error: %v", action.Name, inputFile, err) } else { - err = dataprovider.AddEventAction(&action, executor, ipAddress) + err = dataprovider.AddEventAction(&action, executor, ipAddress, role) logger.Debug(logSender, "", "adding new event action %q, dump file: %q, error: %v", action.Name, inputFile, err) } if err != nil { @@ -331,7 +331,7 @@ func RestoreEventActions(actions []dataprovider.BaseEventAction, inputFile strin } // RestoreEventRules restores the specified event rules -func RestoreEventRules(rules []dataprovider.EventRule, inputFile string, mode int, executor, ipAddress string) error { +func RestoreEventRules(rules []dataprovider.EventRule, inputFile string, mode int, executor, ipAddress, role string) error { for _, rule := range rules { rule := rule // pin r, err := dataprovider.EventRuleExists(rule.Name) @@ -341,10 +341,10 @@ func RestoreEventRules(rules []dataprovider.EventRule, inputFile string, mode in continue } rule.ID = r.ID - err = dataprovider.UpdateEventRule(&rule, executor, ipAddress) + err = dataprovider.UpdateEventRule(&rule, executor, ipAddress, role) logger.Debug(logSender, "", "restoring event rule %q, dump file: %q, error: %v", rule.Name, inputFile, err) } else { - err = dataprovider.AddEventRule(&rule, executor, ipAddress) + err = dataprovider.AddEventRule(&rule, executor, ipAddress, role) logger.Debug(logSender, "", "adding new event rule %q, dump file: %q, error: %v", rule.Name, inputFile, err) } if err != nil { @@ -355,7 +355,7 @@ func RestoreEventRules(rules []dataprovider.EventRule, inputFile string, mode in } // RestoreAPIKeys restores the specified API keys -func RestoreAPIKeys(apiKeys []dataprovider.APIKey, inputFile string, mode int, executor, ipAddress string) error { +func RestoreAPIKeys(apiKeys []dataprovider.APIKey, inputFile string, mode int, executor, ipAddress, role string) error { for _, apiKey := range apiKeys { apiKey := apiKey // pin if apiKey.Key == "" { @@ -369,10 +369,10 @@ func RestoreAPIKeys(apiKeys []dataprovider.APIKey, inputFile string, mode int, e continue } apiKey.ID = k.ID - err = dataprovider.UpdateAPIKey(&apiKey, executor, ipAddress) + err = dataprovider.UpdateAPIKey(&apiKey, executor, ipAddress, role) logger.Debug(logSender, "", "restoring existing API key %#v, dump file: %#v, error: %v", apiKey.KeyID, inputFile, err) } else { - err = dataprovider.AddAPIKey(&apiKey, executor, ipAddress) + err = dataprovider.AddAPIKey(&apiKey, executor, ipAddress, role) logger.Debug(logSender, "", "adding new API key %#v, dump file: %#v, error: %v", apiKey.KeyID, inputFile, err) } if err != nil { @@ -383,7 +383,7 @@ func RestoreAPIKeys(apiKeys []dataprovider.APIKey, inputFile string, mode int, e } // RestoreAdmins restores the specified admins -func RestoreAdmins(admins []dataprovider.Admin, inputFile string, mode int, executor, ipAddress string) error { +func RestoreAdmins(admins []dataprovider.Admin, inputFile string, mode int, executor, ipAddress, role string) error { for _, admin := range admins { admin := admin // pin a, err := dataprovider.AdminExists(admin.Username) @@ -394,10 +394,10 @@ func RestoreAdmins(admins []dataprovider.Admin, inputFile string, mode int, exec } admin.ID = a.ID admin.Username = a.Username - err = dataprovider.UpdateAdmin(&admin, executor, ipAddress) + err = dataprovider.UpdateAdmin(&admin, executor, ipAddress, role) logger.Debug(logSender, "", "restoring existing admin %#v, dump file: %#v, error: %v", admin.Username, inputFile, err) } else { - err = dataprovider.AddAdmin(&admin, executor, ipAddress) + err = dataprovider.AddAdmin(&admin, executor, ipAddress, role) logger.Debug(logSender, "", "adding new admin %#v, dump file: %#v, error: %v", admin.Username, inputFile, err) } if err != nil { @@ -409,7 +409,7 @@ func RestoreAdmins(admins []dataprovider.Admin, inputFile string, mode int, exec } // RestoreRoles restores the specified roles -func RestoreRoles(roles []dataprovider.Role, inputFile string, mode int, executor, ipAddress string) error { +func RestoreRoles(roles []dataprovider.Role, inputFile string, mode int, executor, ipAddress, executorRole string) error { for _, role := range roles { role := role // pin r, err := dataprovider.RoleExists(role.Name) @@ -419,10 +419,10 @@ func RestoreRoles(roles []dataprovider.Role, inputFile string, mode int, executo continue } role.ID = r.ID - err = dataprovider.UpdateRole(&role, executor, ipAddress) + err = dataprovider.UpdateRole(&role, executor, ipAddress, executorRole) logger.Debug(logSender, "", "restoring existing role: %q, dump file: %#v, error: %v", role.Name, inputFile, err) } else { - err = dataprovider.AddRole(&role, executor, ipAddress) + err = dataprovider.AddRole(&role, executor, ipAddress, executorRole) logger.Debug(logSender, "", "adding new role: %q, dump file: %q, error: %v", role.Name, inputFile, err) } if err != nil { @@ -433,7 +433,7 @@ func RestoreRoles(roles []dataprovider.Role, inputFile string, mode int, executo } // RestoreGroups restores the specified groups -func RestoreGroups(groups []dataprovider.Group, inputFile string, mode int, executor, ipAddress string) error { +func RestoreGroups(groups []dataprovider.Group, inputFile string, mode int, executor, ipAddress, role string) error { for _, group := range groups { group := group // pin g, err := dataprovider.GroupExists(group.Name) @@ -444,10 +444,10 @@ func RestoreGroups(groups []dataprovider.Group, inputFile string, mode int, exec } group.ID = g.ID group.Name = g.Name - err = dataprovider.UpdateGroup(&group, g.Users, executor, ipAddress) + err = dataprovider.UpdateGroup(&group, g.Users, executor, ipAddress, role) logger.Debug(logSender, "", "restoring existing group: %#v, dump file: %#v, error: %v", group.Name, inputFile, err) } else { - err = dataprovider.AddGroup(&group, executor, ipAddress) + err = dataprovider.AddGroup(&group, executor, ipAddress, role) logger.Debug(logSender, "", "adding new group: %#v, dump file: %#v, error: %v", group.Name, inputFile, err) } if err != nil { @@ -458,7 +458,7 @@ func RestoreGroups(groups []dataprovider.Group, inputFile string, mode int, exec } // RestoreUsers restores the specified users -func RestoreUsers(users []dataprovider.User, inputFile string, mode, scanQuota int, executor, ipAddress string) error { +func RestoreUsers(users []dataprovider.User, inputFile string, mode, scanQuota int, executor, ipAddress, role string) error { for _, user := range users { user := user // pin u, err := dataprovider.UserExists(user.Username, "") @@ -469,13 +469,13 @@ func RestoreUsers(users []dataprovider.User, inputFile string, mode, scanQuota i } user.ID = u.ID user.Username = u.Username - err = dataprovider.UpdateUser(&user, executor, ipAddress) + err = dataprovider.UpdateUser(&user, executor, ipAddress, role) logger.Debug(logSender, "", "restoring existing user: %#v, dump file: %#v, error: %v", user.Username, inputFile, err) if mode == 2 && err == nil { disconnectUser(user.Username) } } else { - err = dataprovider.AddUser(&user, executor, ipAddress) + err = dataprovider.AddUser(&user, executor, ipAddress, role) logger.Debug(logSender, "", "adding new user: %#v, dump file: %#v, error: %v", user.Username, inputFile, err) } if err != nil { diff --git a/internal/httpd/api_mfa.go b/internal/httpd/api_mfa.go index 3d878275..d535f0ae 100644 --- a/internal/httpd/api_mfa.go +++ b/internal/httpd/api_mfa.go @@ -213,7 +213,7 @@ func generateRecoveryCodes(w http.ResponseWriter, r *http.Request) { return } user.Filters.RecoveryCodes = accountRecoveryCodes - if err := dataprovider.UpdateUser(&user, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil { + if err := dataprovider.UpdateUser(&user, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr), user.Role); err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return } @@ -228,7 +228,7 @@ func generateRecoveryCodes(w http.ResponseWriter, r *http.Request) { return } admin.Filters.RecoveryCodes = accountRecoveryCodes - if err := dataprovider.UpdateAdmin(&admin, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil { + if err := dataprovider.UpdateAdmin(&admin, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr), admin.Role); err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return } @@ -271,7 +271,7 @@ func saveUserTOTPConfig(username string, r *http.Request, recoveryCodes []datapr } else { user.Filters.RecoveryCodes = nil } - return dataprovider.UpdateUser(&user, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr)) + return dataprovider.UpdateUser(&user, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr), user.Role) } func saveAdminTOTPConfig(username string, r *http.Request, recoveryCodes []dataprovider.RecoveryCode) error { @@ -295,5 +295,5 @@ func saveAdminTOTPConfig(username string, r *http.Request, recoveryCodes []datap if admin.Filters.TOTPConfig.Secret == nil || !admin.Filters.TOTPConfig.Secret.IsPlain() { admin.Filters.TOTPConfig.Secret = currentTOTPSecret } - return dataprovider.UpdateAdmin(&admin, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr)) + return dataprovider.UpdateAdmin(&admin, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr), admin.Role) } diff --git a/internal/httpd/api_role.go b/internal/httpd/api_role.go index 248c46ba..9976d7e1 100644 --- a/internal/httpd/api_role.go +++ b/internal/httpd/api_role.go @@ -53,7 +53,7 @@ func addRole(w http.ResponseWriter, r *http.Request) { sendAPIResponse(w, r, err, "", http.StatusBadRequest) return } - err = dataprovider.AddRole(&role, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)) + err = dataprovider.AddRole(&role, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return @@ -84,7 +84,7 @@ func updateRole(w http.ResponseWriter, r *http.Request) { } role.ID = roleID role.Name = name - err = dataprovider.UpdateRole(&role, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)) + err = dataprovider.UpdateRole(&role, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return @@ -120,7 +120,7 @@ func deleteRole(w http.ResponseWriter, r *http.Request) { return } name := getURLParam(r, "name") - err = dataprovider.DeleteRole(name, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)) + err = dataprovider.DeleteRole(name, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return diff --git a/internal/httpd/api_shares.go b/internal/httpd/api_shares.go index bb2fdbd5..e98d8f52 100644 --- a/internal/httpd/api_shares.go +++ b/internal/httpd/api_shares.go @@ -107,7 +107,7 @@ func addShare(w http.ResponseWriter, r *http.Request) { return } } - err = dataprovider.AddShare(&share, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)) + err = dataprovider.AddShare(&share, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return @@ -150,7 +150,7 @@ func updateShare(w http.ResponseWriter, r *http.Request) { return } } - if err := dataprovider.UpdateShare(&share, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil { + if err := dataprovider.UpdateShare(&share, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role); err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return } @@ -166,7 +166,7 @@ func deleteShare(w http.ResponseWriter, r *http.Request) { return } - err = dataprovider.DeleteShare(shareID, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)) + err = dataprovider.DeleteShare(shareID, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return diff --git a/internal/httpd/api_user.go b/internal/httpd/api_user.go index d023efdb..54d41b64 100644 --- a/internal/httpd/api_user.go +++ b/internal/httpd/api_user.go @@ -107,7 +107,7 @@ func addUser(w http.ResponseWriter, r *http.Request) { user.Filters.TOTPConfig = dataprovider.UserTOTPConfig{ Enabled: false, } - err = dataprovider.AddUser(&user, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)) + err = dataprovider.AddUser(&user, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return @@ -132,7 +132,7 @@ func disableUser2FA(w http.ResponseWriter, r *http.Request) { user.Filters.TOTPConfig = dataprovider.UserTOTPConfig{ Enabled: false, } - if err := dataprovider.UpdateUser(&user, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil { + if err := dataprovider.UpdateUser(&user, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role); err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return } @@ -208,7 +208,7 @@ func updateUser(w http.ResponseWriter, r *http.Request) { if claims.Role != "" { user.Role = claims.Role } - err = dataprovider.UpdateUser(&user, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr)) + err = dataprovider.UpdateUser(&user, claims.Username, util.GetIPFromRemoteAddress(r.RemoteAddr), claims.Role) if err != nil { sendAPIResponse(w, r, err, "", getRespStatus(err)) return diff --git a/internal/httpd/api_utils.go b/internal/httpd/api_utils.go index 9d97c8f6..cba8e027 100644 --- a/internal/httpd/api_utils.go +++ b/internal/httpd/api_utils.go @@ -712,7 +712,7 @@ func handleResetPassword(r *http.Request, code, newPassword string, isAdmin bool return &admin, &user, util.NewValidationError("unable to associate the confirmation code with an existing admin") } admin.Password = newPassword - err = dataprovider.UpdateAdmin(&admin, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr)) + err = dataprovider.UpdateAdmin(&admin, dataprovider.ActionExecutorSelf, util.GetIPFromRemoteAddress(r.RemoteAddr), admin.Role) if err != nil { return &admin, &user, util.NewGenericError(fmt.Sprintf("unable to set the new password: %v", err)) } @@ -729,7 +729,7 @@ func handleResetPassword(r *http.Request, code, newPassword string, isAdmin bool } } err = dataprovider.UpdateUserPassword(user.Username, newPassword, dataprovider.ActionExecutorSelf, - util.GetIPFromRemoteAddress(r.RemoteAddr)) + util.GetIPFromRemoteAddress(r.RemoteAddr), user.Role) if err == nil { err = resetCodesMgr.Delete(code) } diff --git a/internal/httpd/auth_utils.go b/internal/httpd/auth_utils.go index 5690af55..911ab70f 100644 --- a/internal/httpd/auth_utils.go +++ b/internal/httpd/auth_utils.go @@ -348,6 +348,7 @@ func getUserFromToken(r *http.Request) *dataprovider.User { tokenClaims.Decode(claims) user.Username = tokenClaims.Username user.Filters.WebClient = tokenClaims.Permissions + user.Role = tokenClaims.Role return user } diff --git a/internal/httpd/httpd_test.go b/internal/httpd/httpd_test.go index 3745654d..b6db0c9d 100644 --- a/internal/httpd/httpd_test.go +++ b/internal/httpd/httpd_test.go @@ -3065,7 +3065,7 @@ func TestChangeAdminPassword(t *testing.T) { admin, err := dataprovider.AdminExists(defaultTokenAuthUser) assert.NoError(t, err) admin.Password = defaultTokenAuthPass - err = dataprovider.UpdateAdmin(&admin, "", "") + err = dataprovider.UpdateAdmin(&admin, "", "", "") assert.NoError(t, err) } @@ -3717,7 +3717,7 @@ func TestUserRedactedPassword(t *testing.T) { _, resp, err := httpdtest.AddUser(u, http.StatusBadRequest) assert.NoError(t, err, string(resp)) assert.Contains(t, string(resp), "cannot save a user with a redacted secret") - err = dataprovider.AddUser(&u, "", "") + err = dataprovider.AddUser(&u, "", "", "") if assert.Error(t, err) { assert.Contains(t, err.Error(), "cannot save a user with a redacted secret") } @@ -3742,7 +3742,7 @@ func TestUserRedactedPassword(t *testing.T) { user.Password = defaultPassword user.VirtualFolders = append(user.VirtualFolders, vfolder) - err = dataprovider.UpdateUser(&user, "", "") + err = dataprovider.UpdateUser(&user, "", "", "") if assert.Error(t, err) { assert.Contains(t, err.Error(), "cannot save a user with a redacted secret") } @@ -5707,7 +5707,7 @@ func TestAdminGenerateRecoveryCodesSaveError(t *testing.T) { Secret: kms.NewPlainSecret(secret), } admin.Password = defaultTokenAuthPass - err = dataprovider.UpdateAdmin(&admin, "", "") + err = dataprovider.UpdateAdmin(&admin, "", "", "") assert.NoError(t, err) admin, _, err = httpdtest.GetAdminByUsername(a.Username, http.StatusOK) assert.NoError(t, err) @@ -5773,7 +5773,7 @@ func TestNamingRules(t *testing.T) { Protocols: []string{common.ProtocolSSH}, } user.Password = u.Password - err = dataprovider.UpdateUser(&user, "", "") + err = dataprovider.UpdateUser(&user, "", "", "") assert.NoError(t, err) user.Username = u.Username user.AdditionalInfo = "info" @@ -6012,7 +6012,7 @@ func TestSaveErrors(t *testing.T) { Protocols: []string{common.ProtocolSSH, common.ProtocolHTTP}, } user.Filters.RecoveryCodes = recoveryCodes - err = dataprovider.UpdateUser(&user, "", "") + err = dataprovider.UpdateUser(&user, "", "", "") assert.NoError(t, err) user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK) assert.NoError(t, err) @@ -6033,7 +6033,7 @@ func TestSaveErrors(t *testing.T) { Secret: kms.NewPlainSecret(secret), } admin.Filters.RecoveryCodes = recoveryCodes - err = dataprovider.UpdateAdmin(&admin, "", "") + err = dataprovider.UpdateAdmin(&admin, "", "", "") assert.NoError(t, err) admin, _, err = httpdtest.GetAdminByUsername(admin.Username, http.StatusOK) assert.NoError(t, err) @@ -7360,7 +7360,7 @@ func TestLoaddataMode(t *testing.T) { apiKey, _, err = httpdtest.UpdateAPIKey(apiKey, http.StatusOK) assert.NoError(t, err) share.Description = "test desc" - err = dataprovider.UpdateShare(&share, "", "") + err = dataprovider.UpdateShare(&share, "", "", "") assert.NoError(t, err) action, _, err = httpdtest.GetEventActionByName(action.Name, http.StatusOK) @@ -8785,11 +8785,20 @@ func TestSearchEvents(t *testing.T) { if assert.Len(t, events, 1) { ev := events[0] for _, field := range []string{"id", "timestamp", "action", "username", "fs_path", "status", "protocol", - "ip", "session_id", "fs_provider", "bucket", "endpoint", "open_flags", "instance_id"} { + "ip", "session_id", "fs_provider", "bucket", "endpoint", "open_flags", "role", "instance_id"} { _, ok := ev[field] assert.True(t, ok, field) } } + req, err = http.NewRequest(http.MethodGet, fsEventsPath+"?limit=10&order=ASC&role=role1", nil) + assert.NoError(t, err) + setBearerForReq(req, token) + rr = executeRequest(req) + checkResponseCode(t, http.StatusOK, rr) + events = nil + err = json.Unmarshal(rr.Body.Bytes(), &events) + assert.NoError(t, err) + assert.Len(t, events, 1) // the test eventsearcher plugin returns error if start_timestamp < 0 req, err = http.NewRequest(http.MethodGet, fsEventsPath+"?start_timestamp=-1&end_timestamp=123456&statuses=1,2", nil) @@ -8815,7 +8824,7 @@ func TestSearchEvents(t *testing.T) { if assert.Len(t, events, 1) { ev := events[0] for _, field := range []string{"id", "timestamp", "action", "username", "object_type", "object_name", - "object_data", "instance_id"} { + "object_data", "role", "instance_id"} { _, ok := ev[field] assert.True(t, ok, field) } @@ -9047,7 +9056,7 @@ func TestMFAInvalidSecret(t *testing.T) { Used: false, Secret: kms.NewSecret(sdkkms.SecretStatusSecretBox, "payload", "key", user.Username), }) - err = dataprovider.UpdateUser(&user, "", "") + err = dataprovider.UpdateUser(&user, "", "", "") assert.NoError(t, err) req, err := http.NewRequest(http.MethodGet, user2FARecoveryCodesPath, nil) @@ -9122,7 +9131,7 @@ func TestMFAInvalidSecret(t *testing.T) { Used: false, Secret: kms.NewSecret(sdkkms.SecretStatusSecretBox, "payload", "key", user.Username), }) - err = dataprovider.UpdateAdmin(&admin, "", "") + err = dataprovider.UpdateAdmin(&admin, "", "", "") assert.NoError(t, err) csrfToken, err = getCSRFToken(httpBaseURL + webLoginPath) @@ -10025,7 +10034,7 @@ func TestAdminHandlingWithAPIKeys(t *testing.T) { dbAdmin, err := dataprovider.AdminExists(defaultTokenAuthUser) assert.NoError(t, err) dbAdmin.Filters.AllowAPIKeyAuth = false - err = dataprovider.UpdateAdmin(&dbAdmin, "", "") + err = dataprovider.UpdateAdmin(&dbAdmin, "", "", "") assert.NoError(t, err) sysAdmin, _, err = httpdtest.GetAdminByUsername(defaultTokenAuthUser, http.StatusOK) assert.NoError(t, err) @@ -11943,7 +11952,7 @@ func TestShareUsage(t *testing.T) { checkResponseCode(t, http.StatusNotFound, rr) share.MaxTokens = 0 - err = dataprovider.UpdateShare(&share, user.Username, "") + err = dataprovider.UpdateShare(&share, user.Username, "", "") assert.NoError(t, err) user.Permissions["/"] = []string{dataprovider.PermListItems, dataprovider.PermDownload} @@ -11997,7 +12006,7 @@ func TestShareUsage(t *testing.T) { user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") assert.NoError(t, err) share.Password = "" - err = dataprovider.UpdateShare(&share, user.Username, "") + err = dataprovider.UpdateShare(&share, user.Username, "", "") assert.NoError(t, err) req, err = http.NewRequest(http.MethodPost, sharesPath+"/"+objectID, reader) @@ -12014,7 +12023,7 @@ func TestShareUsage(t *testing.T) { share.Scope = dataprovider.ShareScopeRead share.Paths = []string{"/missing1", "/missing2"} - err = dataprovider.UpdateShare(&share, user.Username, "") + err = dataprovider.UpdateShare(&share, user.Username, "", "") assert.NoError(t, err) defer func() { @@ -15406,7 +15415,7 @@ func TestWebAdminSetupMock(t *testing.T) { admins, err := dataprovider.GetAdmins(100, 0, dataprovider.OrderASC) assert.NoError(t, err) for _, admin := range admins { - err = dataprovider.DeleteAdmin(admin.Username, "", "") + err = dataprovider.DeleteAdmin(admin.Username, "", "", "") assert.NoError(t, err) } // close the provider and initializes it without creating the default admin diff --git a/internal/httpd/internal_test.go b/internal/httpd/internal_test.go index 2da4c782..ca851f61 100644 --- a/internal/httpd/internal_test.go +++ b/internal/httpd/internal_test.go @@ -746,6 +746,16 @@ func TestInvalidToken(t *testing.T) { assert.Equal(t, http.StatusBadRequest, rr.Code) assert.Contains(t, rr.Body.String(), "Invalid token claims") + rr = httptest.NewRecorder() + searchFsEvents(rr, req) + assert.Equal(t, http.StatusBadRequest, rr.Code) + assert.Contains(t, rr.Body.String(), "Invalid token claims") + + rr = httptest.NewRecorder() + searchProviderEvents(rr, req) + assert.Equal(t, http.StatusBadRequest, rr.Code) + assert.Contains(t, rr.Body.String(), "Invalid token claims") + rr = httptest.NewRecorder() server.handleGetWebUsers(rr, req) assert.Equal(t, http.StatusBadRequest, rr.Code) @@ -863,7 +873,7 @@ func TestRetentionInvalidTokenClaims(t *testing.T) { user.Permissions = make(map[string][]string) user.Permissions["/"] = []string{dataprovider.PermAny} user.Filters.AllowAPIKeyAuth = true - err := dataprovider.AddUser(&user, "", "") + err := dataprovider.AddUser(&user, "", "", "") assert.NoError(t, err) folderRetention := []dataprovider.FolderRetention{ { @@ -1144,7 +1154,7 @@ func TestCreateTokenError(t *testing.T) { user.Permissions = make(map[string][]string) user.Permissions["/"] = []string{dataprovider.PermAny} user.Filters.AllowAPIKeyAuth = true - err = dataprovider.AddUser(&user, "", "") + err = dataprovider.AddUser(&user, "", "", "") assert.NoError(t, err) rr = httptest.NewRecorder() @@ -1170,13 +1180,13 @@ func TestCreateTokenError(t *testing.T) { admin.Status = 1 admin.Filters.AllowAPIKeyAuth = true admin.Permissions = []string{dataprovider.PermAdminAny} - err = dataprovider.AddAdmin(&admin, "", "") + err = dataprovider.AddAdmin(&admin, "", "", "") assert.NoError(t, err) err = authenticateAdminWithAPIKey(admin.Username, "", server.tokenAuth, req) assert.Error(t, err) - err = dataprovider.DeleteAdmin(admin.Username, "", "") + err = dataprovider.DeleteAdmin(admin.Username, "", "", "") assert.NoError(t, err) } @@ -1346,7 +1356,7 @@ func TestCookieExpiration(t *testing.T) { assert.Empty(t, cookie) admin.Status = 0 - err = dataprovider.AddAdmin(&admin, "", "") + err = dataprovider.AddAdmin(&admin, "", "", "") assert.NoError(t, err) req, _ = http.NewRequest(http.MethodGet, tokenPath, nil) ctx = jwtauth.NewContext(req.Context(), token, nil) @@ -1356,7 +1366,7 @@ func TestCookieExpiration(t *testing.T) { admin.Status = 1 admin.Filters.AllowList = []string{"172.16.1.0/24"} - err = dataprovider.UpdateAdmin(&admin, "", "") + err = dataprovider.UpdateAdmin(&admin, "", "", "") assert.NoError(t, err) req, _ = http.NewRequest(http.MethodGet, tokenPath, nil) ctx = jwtauth.NewContext(req.Context(), token, nil) @@ -1388,7 +1398,7 @@ func TestCookieExpiration(t *testing.T) { cookie = rr.Header().Get("Set-Cookie") assert.True(t, strings.HasPrefix(cookie, "jwt=")) - err = dataprovider.DeleteAdmin(admin.Username, "", "") + err = dataprovider.DeleteAdmin(admin.Username, "", "", "") assert.NoError(t, err) // now check client cookie expiration username := "client" @@ -1420,7 +1430,7 @@ func TestCookieExpiration(t *testing.T) { cookie = rr.Header().Get("Set-Cookie") assert.Empty(t, cookie) // the password will be hashed and so the signature will change - err = dataprovider.AddUser(&user, "", "") + err = dataprovider.AddUser(&user, "", "", "") assert.NoError(t, err) req, _ = http.NewRequest(http.MethodGet, webClientFilesPath, nil) ctx = jwtauth.NewContext(req.Context(), token, nil) @@ -1431,7 +1441,7 @@ func TestCookieExpiration(t *testing.T) { user, err = dataprovider.UserExists(user.Username, "") assert.NoError(t, err) user.Filters.AllowedIP = []string{"172.16.4.0/24"} - err = dataprovider.UpdateUser(&user, "", "") + err = dataprovider.UpdateUser(&user, "", "", "") assert.NoError(t, err) user, err = dataprovider.UserExists(user.Username, "") @@ -1755,7 +1765,7 @@ func TestProxyHeaders(t *testing.T) { }, } - err := dataprovider.AddAdmin(&admin, "", "") + err := dataprovider.AddAdmin(&admin, "", "", "") assert.NoError(t, err) testIP := "10.29.1.9" @@ -1846,7 +1856,7 @@ func TestProxyHeaders(t *testing.T) { cookie = rr.Header().Get("Set-Cookie") assert.NotContains(t, cookie, "Secure") - err = dataprovider.DeleteAdmin(username, "", "") + err = dataprovider.DeleteAdmin(username, "", "", "") assert.NoError(t, err) } @@ -2521,7 +2531,7 @@ func TestMetadataAPI(t *testing.T) { } user.Permissions = make(map[string][]string) user.Permissions["/"] = []string{dataprovider.PermAny} - err := dataprovider.AddUser(&user, "", "") + err := dataprovider.AddUser(&user, "", "", "") assert.NoError(t, err) assert.True(t, common.ActiveMetadataChecks.Add(username, "")) @@ -2725,7 +2735,7 @@ func TestWebAdminSetupWithInstallCode(t *testing.T) { admins, err := dataprovider.GetAdmins(100, 0, dataprovider.OrderASC) assert.NoError(t, err) for _, admin := range admins { - err = dataprovider.DeleteAdmin(admin.Username, "", "") + err = dataprovider.DeleteAdmin(admin.Username, "", "", "") assert.NoError(t, err) } // close the provider and initializes it without creating the default admin @@ -2787,7 +2797,7 @@ func TestWebAdminSetupWithInstallCode(t *testing.T) { assert.NoError(t, err) // delete the admin and test the installation code resolver - err = dataprovider.DeleteAdmin(defaultAdminUsername, "", "") + err = dataprovider.DeleteAdmin(defaultAdminUsername, "", "", "") assert.NoError(t, err) err = dataprovider.Close() @@ -2891,6 +2901,16 @@ func TestDbResetCodeManager(t *testing.T) { } } +func TestEventRoleFilter(t *testing.T) { + defaultVal := "default" + req, err := http.NewRequest(http.MethodGet, fsEventsPath+"?role=role1", nil) + require.NoError(t, err) + role := getRoleFilterForEventSearch(req, defaultVal) + assert.Equal(t, defaultVal, role) + role = getRoleFilterForEventSearch(req, "") + assert.Equal(t, "role1", role) +} + func isSharedProviderSupported() bool { // SQLite shares the implementation with other SQL-based provider but it makes no sense // to use it outside test cases diff --git a/internal/httpd/middleware.go b/internal/httpd/middleware.go index d257e1b8..03eaf846 100644 --- a/internal/httpd/middleware.go +++ b/internal/httpd/middleware.go @@ -445,6 +445,7 @@ func authenticateAdminWithAPIKey(username, keyID string, tokenAuth *jwtauth.JWTA Username: admin.Username, Permissions: admin.Permissions, Signature: admin.GetSignature(), + Role: admin.Role, APIKeyID: keyID, } @@ -499,6 +500,7 @@ func authenticateUserWithAPIKey(username, keyID string, tokenAuth *jwtauth.JWTAu Username: user.Username, Permissions: user.Filters.WebClient, Signature: user.GetSignature(), + Role: user.Role, APIKeyID: keyID, } diff --git a/internal/httpd/oidc.go b/internal/httpd/oidc.go index 1b37437f..3fc88484 100644 --- a/internal/httpd/oidc.go +++ b/internal/httpd/oidc.go @@ -205,8 +205,8 @@ type oidcToken struct { Username string `json:"username"` Permissions []string `json:"permissions"` HideUserPageSections int `json:"hide_user_page_sections,omitempty"` - AdminRole string `json:"admin_role,omitempty"` - Role any `json:"role"` + TokenRole string `json:"token_role,omitempty"` // SFTPGo role name + Role any `json:"role"` // oidc user role: SFTPGo user or admin CustomFields *map[string]any `json:"custom_fields,omitempty"` Cookie string `json:"cookie"` UsedAt int64 `json:"used_at"` @@ -390,7 +390,7 @@ func (t *oidcToken) refreshUser(r *http.Request) error { return err } t.Permissions = admin.Permissions - t.AdminRole = admin.Role + t.TokenRole = admin.Role t.HideUserPageSections = admin.Filters.Preferences.HideUserPageSections return nil } @@ -405,6 +405,7 @@ func (t *oidcToken) refreshUser(r *http.Request) error { return err } t.Permissions = user.Filters.WebClient + t.TokenRole = user.Role return nil } @@ -418,7 +419,7 @@ func (t *oidcToken) getUser(r *http.Request) error { return err } t.Permissions = admin.Permissions - t.AdminRole = admin.Role + t.TokenRole = admin.Role t.HideUserPageSections = admin.Filters.Preferences.HideUserPageSections dataprovider.UpdateAdminLastLogin(&admin) return nil @@ -451,6 +452,7 @@ func (t *oidcToken) getUser(r *http.Request) error { updateLoginMetrics(&user, dataprovider.LoginMethodIDP, ipAddr, nil) dataprovider.UpdateLastLogin(&user) t.Permissions = user.Filters.WebClient + t.TokenRole = user.Role return nil } @@ -518,7 +520,7 @@ func (s *httpdServer) oidcTokenAuthenticator(audience tokenAudience) func(next h jwtTokenClaims := jwtTokenClaims{ Username: token.Username, Permissions: token.Permissions, - Role: token.AdminRole, + Role: token.TokenRole, HideUserPageSections: token.HideUserPageSections, } _, tokenString, err := jwtTokenClaims.createToken(s.tokenAuth, audience, util.GetIPFromRemoteAddress(r.RemoteAddr)) diff --git a/internal/httpd/oidc_test.go b/internal/httpd/oidc_test.go index d5e3318c..d7c5f6bf 100644 --- a/internal/httpd/oidc_test.go +++ b/internal/httpd/oidc_test.go @@ -444,7 +444,7 @@ func TestOIDCLoginLogout(t *testing.T) { }, }, } - err = dataprovider.AddUser(&user, "", "") + err = dataprovider.AddUser(&user, "", "", "") assert.NoError(t, err) authReq = newOIDCPendingAuth(tokenAudienceWebClient) @@ -656,7 +656,7 @@ func TestOIDCRefreshUser(t *testing.T) { }, }, } - err = dataprovider.AddAdmin(&admin, "", "") + err = dataprovider.AddAdmin(&admin, "", "", "") assert.NoError(t, err) token.Username = admin.Username @@ -666,14 +666,14 @@ func TestOIDCRefreshUser(t *testing.T) { } admin.Status = 1 - err = dataprovider.UpdateAdmin(&admin, "", "") + err = dataprovider.UpdateAdmin(&admin, "", "", "") assert.NoError(t, err) err = token.refreshUser(r) assert.NoError(t, err) assert.Equal(t, admin.Permissions, token.Permissions) assert.Equal(t, admin.Filters.Preferences.HideUserPageSections, token.HideUserPageSections) - err = dataprovider.DeleteAdmin(admin.Username, "", "") + err = dataprovider.DeleteAdmin(admin.Username, "", "", "") assert.NoError(t, err) username := "test_oidc_user_refresh_token" @@ -694,7 +694,7 @@ func TestOIDCRefreshUser(t *testing.T) { }, }, } - err = dataprovider.AddUser(&user, "", "") + err = dataprovider.AddUser(&user, "", "", "") assert.NoError(t, err) r, err = http.NewRequest(http.MethodGet, webClientFilesPath, nil) @@ -709,7 +709,7 @@ func TestOIDCRefreshUser(t *testing.T) { user, err = dataprovider.UserExists(username, "") assert.NoError(t, err) user.Status = 1 - err = dataprovider.UpdateUser(&user, "", "") + err = dataprovider.UpdateUser(&user, "", "", "") assert.NoError(t, err) err = token.refreshUser(r) if assert.Error(t, err) { @@ -717,7 +717,7 @@ func TestOIDCRefreshUser(t *testing.T) { } user.Filters.DeniedProtocols = []string{common.ProtocolFTP} - err = dataprovider.UpdateUser(&user, "", "") + err = dataprovider.UpdateUser(&user, "", "", "") assert.NoError(t, err) err = token.refreshUser(r) assert.NoError(t, err) @@ -830,7 +830,7 @@ func TestOIDCToken(t *testing.T) { Permissions: []string{dataprovider.PermAdminAny}, Status: 0, } - err := dataprovider.AddAdmin(&admin, "", "") + err := dataprovider.AddAdmin(&admin, "", "", "") assert.NoError(t, err) token := oidcToken{ @@ -843,7 +843,7 @@ func TestOIDCToken(t *testing.T) { if assert.Error(t, err) { assert.Contains(t, err.Error(), "is disabled") } - err = dataprovider.DeleteAdmin(admin.Username, "", "") + err = dataprovider.DeleteAdmin(admin.Username, "", "", "") assert.NoError(t, err) username := "test_oidc_user" @@ -871,7 +871,7 @@ func TestOIDCToken(t *testing.T) { }, }, } - err = dataprovider.AddUser(&user, "", "") + err = dataprovider.AddUser(&user, "", "", "") assert.NoError(t, err) err = token.getUser(req) if assert.Error(t, err) { @@ -881,7 +881,7 @@ func TestOIDCToken(t *testing.T) { assert.NoError(t, err) user.Status = 1 user.Password = "np" - err = dataprovider.UpdateUser(&user, "", "") + err = dataprovider.UpdateUser(&user, "", "", "") assert.NoError(t, err) err = token.getUser(req) @@ -898,7 +898,7 @@ func TestOIDCToken(t *testing.T) { }, Password: kms.NewPlainSecret("np"), } - err = dataprovider.UpdateUser(&user, "", "") + err = dataprovider.UpdateUser(&user, "", "", "") assert.NoError(t, err) err = token.getUser(req) if assert.Error(t, err) { @@ -1001,7 +1001,7 @@ func TestOIDCImplicitRoles(t *testing.T) { }, }, } - err = dataprovider.AddUser(&user, "", "") + err = dataprovider.AddUser(&user, "", "", "") assert.NoError(t, err) authReq = newOIDCPendingAuth(tokenAudienceWebClient) @@ -1390,7 +1390,7 @@ func TestOIDCWithLoginFormsDisabled(t *testing.T) { assert.Equal(t, http.StatusSeeOther, rr.Code) _, err = dataprovider.AdminExists(adminUsername) assert.NoError(t, err) - err = dataprovider.DeleteAdmin(adminUsername, "", "") + err = dataprovider.DeleteAdmin(adminUsername, "", "", "") assert.NoError(t, err) // login and password related routes are disabled rr = httptest.NewRecorder() diff --git a/internal/httpd/server.go b/internal/httpd/server.go index b86677b7..d9ee16ff 100644 --- a/internal/httpd/server.go +++ b/internal/httpd/server.go @@ -349,7 +349,7 @@ func (s *httpdServer) handleWebClientTwoFactorRecoveryPost(w http.ResponseWriter return } user.Filters.RecoveryCodes[idx].Used = true - err = dataprovider.UpdateUser(&user, dataprovider.ActionExecutorSelf, ipAddr) + err = dataprovider.UpdateUser(&user, dataprovider.ActionExecutorSelf, ipAddr, user.Role) if err != nil { logger.Warn(logSender, "", "unable to set the recovery code %#v as used: %v", recoveryCode, err) s.renderClientInternalServerErrorPage(w, r, errors.New("unable to set the recovery code as used")) @@ -453,7 +453,7 @@ func (s *httpdServer) handleWebAdminTwoFactorRecoveryPost(w http.ResponseWriter, return } admin.Filters.RecoveryCodes[idx].Used = true - err = dataprovider.UpdateAdmin(&admin, dataprovider.ActionExecutorSelf, ipAddr) + err = dataprovider.UpdateAdmin(&admin, dataprovider.ActionExecutorSelf, ipAddr, admin.Role) if err != nil { logger.Warn(logSender, "", "unable to set the recovery code %#v as used: %v", recoveryCode, err) s.renderInternalServerErrorPage(w, r, errors.New("unable to set the recovery code as used")) @@ -666,7 +666,7 @@ func (s *httpdServer) handleWebAdminSetupPost(w http.ResponseWriter, r *http.Req Status: 1, Permissions: []string{dataprovider.PermAdminAny}, } - err = dataprovider.AddAdmin(&admin, username, ipAddr) + err = dataprovider.AddAdmin(&admin, username, ipAddr, "") if err != nil { s.renderAdminSetupPage(w, r, username, err.Error()) return @@ -682,6 +682,7 @@ func (s *httpdServer) loginUser( Username: user.Username, Permissions: user.Filters.WebClient, Signature: user.GetSignature(), + Role: user.Role, MustSetTwoFactorAuth: user.MustSetSecondFactor(), RequiredTwoFactorProtocols: user.Filters.TwoFactorAuthProtocols, } @@ -839,6 +840,7 @@ func (s *httpdServer) generateAndSendUserToken(w http.ResponseWriter, r *http.Re Username: user.Username, Permissions: user.Filters.WebClient, Signature: user.GetSignature(), + Role: user.Role, MustSetTwoFactorAuth: user.MustSetSecondFactor(), RequiredTwoFactorProtocols: user.Filters.TwoFactorAuthProtocols, } @@ -946,16 +948,17 @@ func (s *httpdServer) refreshClientToken(w http.ResponseWriter, r *http.Request, return } if user.GetSignature() != tokenClaims.Signature { - logger.Debug(logSender, "", "signature mismatch for user %#v, unable to refresh cookie", user.Username) + logger.Debug(logSender, "", "signature mismatch for user %q, unable to refresh cookie", user.Username) return } if err := checkHTTPClientUser(&user, r, xid.New().String(), true); err != nil { - logger.Debug(logSender, "", "unable to refresh cookie for user %#v: %v", user.Username, err) + logger.Debug(logSender, "", "unable to refresh cookie for user %q: %v", user.Username, err) return } tokenClaims.Permissions = user.Filters.WebClient - logger.Debug(logSender, "", "cookie refreshed for user %#v", user.Username) + tokenClaims.Role = user.Role + logger.Debug(logSender, "", "cookie refreshed for user %q", user.Username) tokenClaims.createAndSetCookie(w, r, s.tokenAuth, tokenAudienceWebClient, util.GetIPFromRemoteAddress(r.RemoteAddr)) //nolint:errcheck } diff --git a/internal/httpd/webadmin.go b/internal/httpd/webadmin.go index 863daf89..40bd42c5 100644 --- a/internal/httpd/webadmin.go +++ b/internal/httpd/webadmin.go @@ -2407,7 +2407,7 @@ func (s *httpdServer) handleWebAdminProfilePost(w http.ResponseWriter, r *http.R admin.Filters.AllowAPIKeyAuth = r.Form.Get("allow_api_key_auth") != "" admin.Email = r.Form.Get("email") admin.Description = r.Form.Get("description") - err = dataprovider.UpdateAdmin(&admin, dataprovider.ActionExecutorSelf, ipAddr) + err = dataprovider.UpdateAdmin(&admin, dataprovider.ActionExecutorSelf, ipAddr, admin.Role) if err != nil { s.renderProfilePage(w, r, err.Error()) return @@ -2466,7 +2466,7 @@ func (s *httpdServer) handleWebRestore(w http.ResponseWriter, r *http.Request) { return } - if err := restoreBackup(backupContent, "", scanQuota, restoreMode, claims.Username, ipAddr); err != nil { + if err := restoreBackup(backupContent, "", scanQuota, restoreMode, claims.Username, ipAddr, claims.Role); err != nil { s.renderMaintenancePage(w, r, err.Error()) return } @@ -2554,7 +2554,7 @@ func (s *httpdServer) handleWebAddAdminPost(w http.ResponseWriter, r *http.Reque s.renderForbiddenPage(w, r, err.Error()) return } - err = dataprovider.AddAdmin(&admin, claims.Username, ipAddr) + err = dataprovider.AddAdmin(&admin, claims.Username, ipAddr, claims.Role) if err != nil { s.renderAddUpdateAdminPage(w, r, &admin, err.Error(), true) return @@ -2611,7 +2611,7 @@ func (s *httpdServer) handleWebUpdateAdminPost(w http.ResponseWriter, r *http.Re return } } - err = dataprovider.UpdateAdmin(&updatedAdmin, claims.Username, ipAddr) + err = dataprovider.UpdateAdmin(&updatedAdmin, claims.Username, ipAddr, claims.Role) if err != nil { s.renderAddUpdateAdminPage(w, r, &updatedAdmin, err.Error(), false) return @@ -2739,7 +2739,7 @@ func (s *httpdServer) handleWebTemplateFolderPost(w http.ResponseWriter, r *http render.JSON(w, r, dump) return } - if err = RestoreFolders(dump.Folders, "", 1, 0, claims.Username, ipAddr); err != nil { + if err = RestoreFolders(dump.Folders, "", 1, 0, claims.Username, ipAddr, claims.Role); err != nil { s.renderMessagePage(w, r, "Unable to save folders", "Cannot save the defined folders:", getRespStatus(err), err, "") return @@ -2836,7 +2836,7 @@ func (s *httpdServer) handleWebTemplateUserPost(w http.ResponseWriter, r *http.R render.JSON(w, r, dump) return } - if err = RestoreUsers(dump.Users, "", 1, 0, claims.Username, ipAddr); err != nil { + if err = RestoreUsers(dump.Users, "", 1, 0, claims.Username, ipAddr, claims.Role); err != nil { s.renderMessagePage(w, r, "Unable to save users", "Cannot save the defined users:", getRespStatus(err), err, "") return @@ -2911,7 +2911,7 @@ func (s *httpdServer) handleWebAddUserPost(w http.ResponseWriter, r *http.Reques user.Filters.TOTPConfig = dataprovider.UserTOTPConfig{ Enabled: false, } - err = dataprovider.AddUser(&user, claims.Username, ipAddr) + err = dataprovider.AddUser(&user, claims.Username, ipAddr, claims.Role) if err != nil { s.renderUserPage(w, r, &user, userPageModeAdd, err.Error(), nil) return @@ -2967,7 +2967,7 @@ func (s *httpdServer) handleWebUpdateUserPost(w http.ResponseWriter, r *http.Req updatedUser.Role = claims.Role } - err = dataprovider.UpdateUser(&updatedUser, claims.Username, ipAddr) + err = dataprovider.UpdateUser(&updatedUser, claims.Username, ipAddr, claims.Role) if err != nil { s.renderUserPage(w, r, &updatedUser, userPageModeUpdate, err.Error(), nil) return @@ -3039,7 +3039,7 @@ func (s *httpdServer) handleWebAddFolderPost(w http.ResponseWriter, r *http.Requ folder.FsConfig = fsConfig folder = getFolderFromTemplate(folder, folder.Name) - err = dataprovider.AddFolder(&folder, claims.Username, ipAddr) + err = dataprovider.AddFolder(&folder, claims.Username, ipAddr, claims.Role) if err == nil { http.Redirect(w, r, webFoldersPath, http.StatusSeeOther) } else { @@ -3109,7 +3109,7 @@ func (s *httpdServer) handleWebUpdateFolderPost(w http.ResponseWriter, r *http.R updatedFolder = getFolderFromTemplate(updatedFolder, updatedFolder.Name) - err = dataprovider.UpdateFolder(&updatedFolder, folder.Users, folder.Groups, claims.Username, ipAddr) + err = dataprovider.UpdateFolder(&updatedFolder, folder.Users, folder.Groups, claims.Username, ipAddr, claims.Role) if err != nil { s.renderFolderPage(w, r, updatedFolder, folderPageModeUpdate, err.Error()) return @@ -3215,7 +3215,7 @@ func (s *httpdServer) handleWebAddGroupPost(w http.ResponseWriter, r *http.Reque s.renderForbiddenPage(w, r, err.Error()) return } - err = dataprovider.AddGroup(&group, claims.Username, ipAddr) + err = dataprovider.AddGroup(&group, claims.Username, ipAddr, claims.Role) if err != nil { s.renderGroupPage(w, r, group, genericPageModeAdd, err.Error()) return @@ -3273,7 +3273,7 @@ func (s *httpdServer) handleWebUpdateGroupPost(w http.ResponseWriter, r *http.Re group.UserSettings.FsConfig.SFTPConfig.KeyPassphrase, group.UserSettings.FsConfig.HTTPConfig.Password, group.UserSettings.FsConfig.HTTPConfig.APIKey) - err = dataprovider.UpdateGroup(&updatedGroup, group.Users, claims.Username, ipAddr) + err = dataprovider.UpdateGroup(&updatedGroup, group.Users, claims.Username, ipAddr, claims.Role) if err != nil { s.renderGroupPage(w, r, updatedGroup, genericPageModeUpdate, err.Error()) return @@ -3345,7 +3345,7 @@ func (s *httpdServer) handleWebAddEventActionPost(w http.ResponseWriter, r *http s.renderForbiddenPage(w, r, err.Error()) return } - if err = dataprovider.AddEventAction(&action, claims.Username, ipAddr); err != nil { + if err = dataprovider.AddEventAction(&action, claims.Username, ipAddr, claims.Role); err != nil { s.renderEventActionPage(w, r, action, genericPageModeAdd, err.Error()) return } @@ -3400,7 +3400,7 @@ func (s *httpdServer) handleWebUpdateEventActionPost(w http.ResponseWriter, r *h updatedAction.Options.HTTPConfig.Password = action.Options.HTTPConfig.Password } } - err = dataprovider.UpdateEventAction(&updatedAction, claims.Username, ipAddr) + err = dataprovider.UpdateEventAction(&updatedAction, claims.Username, ipAddr, claims.Role) if err != nil { s.renderEventActionPage(w, r, updatedAction, genericPageModeUpdate, err.Error()) return @@ -3462,7 +3462,7 @@ func (s *httpdServer) handleWebAddEventRulePost(w http.ResponseWriter, r *http.R s.renderForbiddenPage(w, r, err.Error()) return } - if err = dataprovider.AddEventRule(&rule, claims.Username, ipAddr); err != nil { + if err = dataprovider.AddEventRule(&rule, claims.Username, ipAddr, claims.Role); err != nil { s.renderEventRulePage(w, r, rule, genericPageModeAdd, err.Error()) return } @@ -3510,7 +3510,7 @@ func (s *httpdServer) handleWebUpdateEventRulePost(w http.ResponseWriter, r *htt } updatedRule.ID = rule.ID updatedRule.Name = rule.Name - err = dataprovider.UpdateEventRule(&updatedRule, claims.Username, ipAddr) + err = dataprovider.UpdateEventRule(&updatedRule, claims.Username, ipAddr, claims.Role) if err != nil { s.renderEventRulePage(w, r, updatedRule, genericPageModeUpdate, err.Error()) return @@ -3569,7 +3569,7 @@ func (s *httpdServer) handleWebAddRolePost(w http.ResponseWriter, r *http.Reques s.renderForbiddenPage(w, r, err.Error()) return } - err = dataprovider.AddRole(&role, claims.Username, ipAddr) + err = dataprovider.AddRole(&role, claims.Username, ipAddr, claims.Role) if err != nil { s.renderRolePage(w, r, role, genericPageModeAdd, err.Error()) return @@ -3617,7 +3617,7 @@ func (s *httpdServer) handleWebUpdateRolePost(w http.ResponseWriter, r *http.Req } updatedRole.ID = role.ID updatedRole.Name = role.Name - err = dataprovider.UpdateRole(&updatedRole, claims.Username, ipAddr) + err = dataprovider.UpdateRole(&updatedRole, claims.Username, ipAddr, claims.Role) if err != nil { s.renderRolePage(w, r, updatedRole, genericPageModeUpdate, err.Error()) return diff --git a/internal/httpd/webclient.go b/internal/httpd/webclient.go index 7719754f..8861f3e5 100644 --- a/internal/httpd/webclient.go +++ b/internal/httpd/webclient.go @@ -1103,7 +1103,7 @@ func (s *httpdServer) handleClientAddSharePost(w http.ResponseWriter, r *http.Re return } } - err = dataprovider.AddShare(share, claims.Username, ipAddr) + err = dataprovider.AddShare(share, claims.Username, ipAddr, claims.Role) if err == nil { http.Redirect(w, r, webClientSharesPath, http.StatusSeeOther) } else { @@ -1148,7 +1148,7 @@ func (s *httpdServer) handleClientUpdateSharePost(w http.ResponseWriter, r *http return } } - err = dataprovider.UpdateShare(updatedShare, claims.Username, ipAddr) + err = dataprovider.UpdateShare(updatedShare, claims.Username, ipAddr, claims.Role) if err == nil { http.Redirect(w, r, webClientSharesPath, http.StatusSeeOther) } else { @@ -1237,7 +1237,7 @@ func (s *httpdServer) handleWebClientProfilePost(w http.ResponseWriter, r *http. user.Email = r.Form.Get("email") user.Description = r.Form.Get("description") } - err = dataprovider.UpdateUser(&user, dataprovider.ActionExecutorSelf, ipAddr) + err = dataprovider.UpdateUser(&user, dataprovider.ActionExecutorSelf, ipAddr, user.Role) if err != nil { s.renderClientProfilePage(w, r, err.Error()) return diff --git a/internal/service/service.go b/internal/service/service.go index 41343358..a4e751d9 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -162,7 +162,7 @@ func (s *Service) initializeServices(disableAWSInstallationCode bool) error { if s.PortableMode == 1 { // create the user for portable mode - err = dataprovider.AddUser(&s.PortableUser, dataprovider.ActionExecutorSystem, "") + err = dataprovider.AddUser(&s.PortableUser, dataprovider.ActionExecutorSystem, "", "") if err != nil { logger.ErrorToConsole("error adding portable user: %v", err) return err @@ -350,39 +350,39 @@ func (s *Service) LoadInitialData() error { } func (s *Service) restoreDump(dump *dataprovider.BackupData) error { - err := httpd.RestoreRoles(dump.Roles, s.LoadDataFrom, s.LoadDataMode, dataprovider.ActionExecutorSystem, "") + err := httpd.RestoreRoles(dump.Roles, s.LoadDataFrom, s.LoadDataMode, dataprovider.ActionExecutorSystem, "", "") if err != nil { return fmt.Errorf("unable to restore roles from file %#v: %v", s.LoadDataFrom, err) } - err = httpd.RestoreFolders(dump.Folders, s.LoadDataFrom, s.LoadDataMode, s.LoadDataQuotaScan, dataprovider.ActionExecutorSystem, "") + err = httpd.RestoreFolders(dump.Folders, s.LoadDataFrom, s.LoadDataMode, s.LoadDataQuotaScan, dataprovider.ActionExecutorSystem, "", "") if err != nil { return fmt.Errorf("unable to restore folders from file %#v: %v", s.LoadDataFrom, err) } - err = httpd.RestoreGroups(dump.Groups, s.LoadDataFrom, s.LoadDataMode, dataprovider.ActionExecutorSystem, "") + err = httpd.RestoreGroups(dump.Groups, s.LoadDataFrom, s.LoadDataMode, dataprovider.ActionExecutorSystem, "", "") if err != nil { return fmt.Errorf("unable to restore groups from file %#v: %v", s.LoadDataFrom, err) } - err = httpd.RestoreUsers(dump.Users, s.LoadDataFrom, s.LoadDataMode, s.LoadDataQuotaScan, dataprovider.ActionExecutorSystem, "") + err = httpd.RestoreUsers(dump.Users, s.LoadDataFrom, s.LoadDataMode, s.LoadDataQuotaScan, dataprovider.ActionExecutorSystem, "", "") if err != nil { return fmt.Errorf("unable to restore users from file %#v: %v", s.LoadDataFrom, err) } - err = httpd.RestoreAdmins(dump.Admins, s.LoadDataFrom, s.LoadDataMode, dataprovider.ActionExecutorSystem, "") + err = httpd.RestoreAdmins(dump.Admins, s.LoadDataFrom, s.LoadDataMode, dataprovider.ActionExecutorSystem, "", "") if err != nil { return fmt.Errorf("unable to restore admins from file %#v: %v", s.LoadDataFrom, err) } - err = httpd.RestoreAPIKeys(dump.APIKeys, s.LoadDataFrom, s.LoadDataMode, dataprovider.ActionExecutorSystem, "") + err = httpd.RestoreAPIKeys(dump.APIKeys, s.LoadDataFrom, s.LoadDataMode, dataprovider.ActionExecutorSystem, "", "") if err != nil { return fmt.Errorf("unable to restore API keys from file %#v: %v", s.LoadDataFrom, err) } - err = httpd.RestoreShares(dump.Shares, s.LoadDataFrom, s.LoadDataMode, dataprovider.ActionExecutorSystem, "") + err = httpd.RestoreShares(dump.Shares, s.LoadDataFrom, s.LoadDataMode, dataprovider.ActionExecutorSystem, "", "") if err != nil { return fmt.Errorf("unable to restore API keys from file %#v: %v", s.LoadDataFrom, err) } - err = httpd.RestoreEventActions(dump.EventActions, s.LoadDataFrom, s.LoadDataMode, dataprovider.ActionExecutorSystem, "") + err = httpd.RestoreEventActions(dump.EventActions, s.LoadDataFrom, s.LoadDataMode, dataprovider.ActionExecutorSystem, "", "") if err != nil { return fmt.Errorf("unable to restore event actions from file %#v: %v", s.LoadDataFrom, err) } - err = httpd.RestoreEventRules(dump.EventRules, s.LoadDataFrom, s.LoadDataMode, dataprovider.ActionExecutorSystem, "") + err = httpd.RestoreEventRules(dump.EventRules, s.LoadDataFrom, s.LoadDataMode, dataprovider.ActionExecutorSystem, "", "") if err != nil { return fmt.Errorf("unable to restore event rules from file %#v: %v", s.LoadDataFrom, err) } diff --git a/internal/sftpd/sftpd_test.go b/internal/sftpd/sftpd_test.go index 98fe4f96..496ba9a9 100644 --- a/internal/sftpd/sftpd_test.go +++ b/internal/sftpd/sftpd_test.go @@ -2790,7 +2790,7 @@ func TestInteractiveLoginWithPasscode(t *testing.T) { Secret: kms.NewPlainSecret(secret), Protocols: []string{common.ProtocolSSH}, } - err = dataprovider.UpdateUser(&user, "", "") + err = dataprovider.UpdateUser(&user, "", "", "") assert.NoError(t, err) passcode, err := totp.GenerateCodeCustom(secret, time.Now(), totp.ValidateOpts{ @@ -2839,7 +2839,7 @@ func TestInteractiveLoginWithPasscode(t *testing.T) { Secret: kms.NewPlainSecret(secret), Protocols: []string{common.ProtocolSSH}, } - err = dataprovider.UpdateUser(&user, "", "") + err = dataprovider.UpdateUser(&user, "", "", "") assert.NoError(t, err) passcode, err = totp.GenerateCodeCustom(secret, time.Now(), totp.ValidateOpts{ Period: 30, @@ -2897,7 +2897,7 @@ func TestSecondFactorRequirement(t *testing.T) { Secret: kms.NewPlainSecret(secret), Protocols: []string{common.ProtocolSSH}, } - err = dataprovider.UpdateUser(&user, "", "") + err = dataprovider.UpdateUser(&user, "", "", "") assert.NoError(t, err) conn, client, err := getSftpClient(user, usePubKey) @@ -3111,7 +3111,7 @@ func TestPreLoginHookPreserveMFAConfig(t *testing.T) { Secret: kms.NewPlainSecret(fmt.Sprintf("RC-%v", strings.ToUpper(util.GenerateUniqueID()))), }) } - err = dataprovider.UpdateUser(&user, "", "") + err = dataprovider.UpdateUser(&user, "", "", "") assert.NoError(t, err) conn, client, err = getSftpClient(u, usePubKey) @@ -4166,7 +4166,7 @@ func TestExternalAuthPreserveMFAConfig(t *testing.T) { Secret: kms.NewPlainSecret(fmt.Sprintf("RC-%v", strings.ToUpper(util.GenerateUniqueID()))), }) } - err = dataprovider.UpdateUser(&user, "", "") + err = dataprovider.UpdateUser(&user, "", "", "") assert.NoError(t, err) // login again and check that the MFA configs are preserved conn, client, err = getSftpClient(u, usePubKey) @@ -4274,7 +4274,7 @@ func TestMaxConnections(t *testing.T) { usePubKey := true user := getTestUser(usePubKey) - err := dataprovider.AddUser(&user, "", "") + err := dataprovider.AddUser(&user, "", "", "") assert.NoError(t, err) user.Password = "" conn, client, err := getSftpClient(user, usePubKey) @@ -4309,7 +4309,7 @@ func TestMaxPerHostConnections(t *testing.T) { usePubKey := true user := getTestUser(usePubKey) - err := dataprovider.AddUser(&user, "", "") + err := dataprovider.AddUser(&user, "", "", "") assert.NoError(t, err) user.Password = "" conn, client, err := getSftpClient(user, usePubKey) diff --git a/internal/webdavd/internal_test.go b/internal/webdavd/internal_test.go index 335f8d1d..25339885 100644 --- a/internal/webdavd/internal_test.go +++ b/internal/webdavd/internal_test.go @@ -958,7 +958,7 @@ func TestBasicUsersCache(t *testing.T) { } u.Permissions = make(map[string][]string) u.Permissions["/"] = []string{dataprovider.PermAny} - err := dataprovider.AddUser(&u, "", "") + err := dataprovider.AddUser(&u, "", "", "") assert.NoError(t, err) user, err := dataprovider.UserExists(u.Username, "") assert.NoError(t, err) @@ -1030,7 +1030,7 @@ func TestBasicUsersCache(t *testing.T) { assert.False(t, cachedUser.IsExpired()) } // cache is not invalidated after a user modification if the fs does not change - err = dataprovider.UpdateUser(&user, "", "") + err = dataprovider.UpdateUser(&user, "", "", "") assert.NoError(t, err) _, ok = dataprovider.GetCachedWebDAVUser(username) assert.True(t, ok) @@ -1043,7 +1043,7 @@ func TestBasicUsersCache(t *testing.T) { VirtualPath: "/vdir", }) - err = dataprovider.UpdateUser(&user, "", "") + err = dataprovider.UpdateUser(&user, "", "", "") assert.NoError(t, err) _, ok = dataprovider.GetCachedWebDAVUser(username) assert.False(t, ok) @@ -1060,7 +1060,7 @@ func TestBasicUsersCache(t *testing.T) { _, ok = dataprovider.GetCachedWebDAVUser(username) assert.False(t, ok) - err = dataprovider.DeleteFolder(folderName, "", "") + err = dataprovider.DeleteFolder(folderName, "", "", "") assert.NoError(t, err) err = os.RemoveAll(u.GetHomeDir()) @@ -1089,7 +1089,7 @@ func TestCachedUserWithFolders(t *testing.T) { }, VirtualPath: "/vpath", }) - err := dataprovider.AddUser(&u, "", "") + err := dataprovider.AddUser(&u, "", "", "") assert.NoError(t, err) user, err := dataprovider.UserExists(u.Username, "") assert.NoError(t, err) @@ -1142,7 +1142,7 @@ func TestCachedUserWithFolders(t *testing.T) { folder, err := dataprovider.GetFolderByName(folderName) assert.NoError(t, err) // updating a used folder should invalidate the cache only if the fs changed - err = dataprovider.UpdateFolder(&folder, folder.Users, folder.Groups, "", "") + err = dataprovider.UpdateFolder(&folder, folder.Users, folder.Groups, "", "", "") assert.NoError(t, err) _, isCached, _, loginMethod, err = server.authenticate(req, ipAddr) @@ -1155,7 +1155,7 @@ func TestCachedUserWithFolders(t *testing.T) { } // changing the folder path should invalidate the cache folder.MappedPath = filepath.Join(os.TempDir(), "anotherpath") - err = dataprovider.UpdateFolder(&folder, folder.Users, folder.Groups, "", "") + err = dataprovider.UpdateFolder(&folder, folder.Users, folder.Groups, "", "", "") assert.NoError(t, err) _, isCached, _, loginMethod, err = server.authenticate(req, ipAddr) assert.NoError(t, err) @@ -1166,7 +1166,7 @@ func TestCachedUserWithFolders(t *testing.T) { assert.False(t, cachedUser.IsExpired()) } - err = dataprovider.DeleteFolder(folderName, "", "") + err = dataprovider.DeleteFolder(folderName, "", "", "") assert.NoError(t, err) // removing a used folder should invalidate the cache _, isCached, _, loginMethod, err = server.authenticate(req, ipAddr) @@ -1204,25 +1204,25 @@ func TestUsersCacheSizeAndExpiration(t *testing.T) { u.Password = password + "1" u.Permissions = make(map[string][]string) u.Permissions["/"] = []string{dataprovider.PermAny} - err := dataprovider.AddUser(&u, "", "") + err := dataprovider.AddUser(&u, "", "", "") assert.NoError(t, err) user1, err := dataprovider.UserExists(u.Username, "") assert.NoError(t, err) u.Username = username + "2" u.Password = password + "2" - err = dataprovider.AddUser(&u, "", "") + err = dataprovider.AddUser(&u, "", "", "") assert.NoError(t, err) user2, err := dataprovider.UserExists(u.Username, "") assert.NoError(t, err) u.Username = username + "3" u.Password = password + "3" - err = dataprovider.AddUser(&u, "", "") + err = dataprovider.AddUser(&u, "", "", "") assert.NoError(t, err) user3, err := dataprovider.UserExists(u.Username, "") assert.NoError(t, err) u.Username = username + "4" u.Password = password + "4" - err = dataprovider.AddUser(&u, "", "") + err = dataprovider.AddUser(&u, "", "", "") assert.NoError(t, err) user4, err := dataprovider.UserExists(u.Username, "") assert.NoError(t, err) @@ -1355,7 +1355,7 @@ func TestUsersCacheSizeAndExpiration(t *testing.T) { // now remove user1 after an update user1.HomeDir += "_mod" - err = dataprovider.UpdateUser(&user1, "", "") + err = dataprovider.UpdateUser(&user1, "", "", "") assert.NoError(t, err) _, ok = dataprovider.GetCachedWebDAVUser(user1.Username) assert.False(t, ok) @@ -1414,7 +1414,7 @@ func TestUserCacheIsolation(t *testing.T) { } u.Permissions = make(map[string][]string) u.Permissions["/"] = []string{dataprovider.PermAny} - err := dataprovider.AddUser(&u, "", "") + err := dataprovider.AddUser(&u, "", "", "") assert.NoError(t, err) user, err := dataprovider.UserExists(u.Username, "") assert.NoError(t, err) diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index bfe01f8e..93ef9a3b 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -2299,6 +2299,12 @@ paths: description: 'the event id must not be included among those specified. This is useful for cursor based pagination. Empty or missing means omit this filter. Values must be specified comma separated' explode: false required: false + - in: query + name: role + schema: + type: string + description: 'User role. Empty or missing means omit this filter. Ignored if the admin has a role' + required: false - in: query name: limit schema: @@ -2417,6 +2423,12 @@ paths: description: 'the event id must not be included among those specified. This is useful for cursor based pagination. Empty or missing means omit this filter. Values must be specified comma separated' explode: false required: false + - in: query + name: role + schema: + type: string + description: 'Admin role. Empty or missing means omit this filter. Ignored if the admin has a role' + required: false - in: query name: limit schema: @@ -5482,7 +5494,7 @@ components: description: Last user login as unix timestamp in milliseconds. It is saved at most once every 10 minutes role: type: string - description: 'If set the admin can only administer users with the same role. Role admins cannot have the following permissions: "manage_admins", "manage_apikeys", "manage_system", "manage_event_rules", "manage_roles", "view_events"' + description: 'If set the admin can only administer users with the same role. Role admins cannot have the following permissions: "manage_admins", "manage_apikeys", "manage_system", "manage_event_rules", "manage_roles"' AdminProfile: type: object properties: diff --git a/pkgs/build.sh b/pkgs/build.sh index 19610c73..77e2a076 100755 --- a/pkgs/build.sh +++ b/pkgs/build.sh @@ -1,6 +1,6 @@ #!/bin/bash -NFPM_VERSION=2.22.1 +NFPM_VERSION=2.22.2 NFPM_ARCH=${NFPM_ARCH:-amd64} if [ -z ${SFTPGO_VERSION} ] then diff --git a/templates/webadmin/eventaction.html b/templates/webadmin/eventaction.html index 2cbca9cd..7aa36453 100644 --- a/templates/webadmin/eventaction.html +++ b/templates/webadmin/eventaction.html @@ -702,6 +702,9 @@ along with this program. If not, see .

{{`{{IP}}`}} => Client IP address.

+

+ {{`{{Role}}`}} => User or admin role. +

{{`{{Timestamp}}`}} => Event timestamp as nanoseconds since epoch.

diff --git a/tests/eventsearcher/go.mod b/tests/eventsearcher/go.mod index 5b9bd29d..65bdebcb 100644 --- a/tests/eventsearcher/go.mod +++ b/tests/eventsearcher/go.mod @@ -3,8 +3,8 @@ module github.com/drakkan/sftpgo/tests/eventsearcher go 1.19 require ( - github.com/hashicorp/go-plugin v1.4.5 - github.com/sftpgo/sdk v0.1.2 + github.com/hashicorp/go-plugin v1.4.6 + github.com/sftpgo/sdk v0.1.3-0.20221203095324-2feef3600930 ) require ( @@ -17,10 +17,10 @@ require ( github.com/mattn/go-isatty v0.0.16 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/oklog/run v1.1.0 // indirect - golang.org/x/net v0.1.0 // indirect - golang.org/x/sys v0.1.0 // indirect + golang.org/x/net v0.2.0 // indirect + golang.org/x/sys v0.2.0 // indirect golang.org/x/text v0.4.0 // indirect - google.golang.org/genproto v0.0.0-20221018160656-63c7b68cfc55 // indirect - google.golang.org/grpc v1.50.1 // indirect + google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd // indirect + google.golang.org/grpc v1.51.0 // indirect google.golang.org/protobuf v1.28.1 // indirect ) diff --git a/tests/eventsearcher/go.sum b/tests/eventsearcher/go.sum index ffbf8602..59aa8f0c 100644 --- a/tests/eventsearcher/go.sum +++ b/tests/eventsearcher/go.sum @@ -11,8 +11,8 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/hashicorp/go-hclog v1.3.1 h1:vDwF1DFNZhntP4DAjuTpOw3uEgMUpXh1pB5fW9DqHpo= github.com/hashicorp/go-hclog v1.3.1/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-plugin v1.4.5 h1:oTE/oQR4eghggRg8VY7PAz3dr++VwDNBGCcOfIvHpBo= -github.com/hashicorp/go-plugin v1.4.5/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-plugin v1.4.6 h1:MDV3UrKQBM3du3G7MApDGvOsMYy3JQJ4exhSoKBAeVA= +github.com/hashicorp/go-plugin v1.4.6/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= @@ -30,28 +30,28 @@ github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/sftpgo/sdk v0.1.2 h1:j4V63RuVcYfJAOWV0zRUofa1PlQvKU2ujly0lB7quVA= -github.com/sftpgo/sdk v0.1.2/go.mod h1:PTp1TfXa+95wHw9yuZu7BA3vmzLqbRkz3gBmMNnwFQg= +github.com/sftpgo/sdk v0.1.3-0.20221203095324-2feef3600930 h1:znJ52fQBSAQhacaQvZAfkpTioqpcutDREM/H8NttKzU= +github.com/sftpgo/sdk v0.1.3-0.20221203095324-2feef3600930/go.mod h1:S2S/Q9fgUpXmL11YoCCt0hyCkEwH1LzQM/6QVsbUCFg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto v0.0.0-20221018160656-63c7b68cfc55 h1:U1u4KB2kx6KR/aJDjQ97hZ15wQs8ZPvDcGcRynBhkvg= -google.golang.org/genproto v0.0.0-20221018160656-63c7b68cfc55/go.mod h1:45EK0dUbEZ2NHjCeAd2LXmyjAgGUGrpGROgjhC3ADck= -google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY= -google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd h1:OjndDrsik+Gt+e6fs45z9AxiewiKyLKYpA45W5Kpkks= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= +google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= diff --git a/tests/eventsearcher/main.go b/tests/eventsearcher/main.go index 21885797..403f7b33 100644 --- a/tests/eventsearcher/main.go +++ b/tests/eventsearcher/main.go @@ -31,6 +31,7 @@ type fsEvent struct { Bucket string `json:"bucket,omitempty"` Endpoint string `json:"endpoint,omitempty"` OpenFlags int `json:"open_flags,omitempty"` + Role string `json:"role,omitempty"` InstanceID string `json:"instance_id,omitempty"` } @@ -43,6 +44,7 @@ type providerEvent struct { ObjectType string `json:"object_type"` ObjectName string `json:"object_name"` ObjectData []byte `json:"object_data"` + Role string `json:"role,omitempty"` InstanceID string `json:"instance_id,omitempty"` } @@ -74,6 +76,7 @@ func (s *Searcher) SearchFsEvents(filters *eventsearcher.FsEventSearch) ([]byte, Bucket: "bucket", Endpoint: "endpoint", OpenFlags: 512, + Role: "role1", }, } @@ -100,6 +103,7 @@ func (s *Searcher) SearchProviderEvents(filters *eventsearcher.ProviderEventSear ObjectType: "api_key", ObjectName: "123", ObjectData: []byte("data"), + Role: "role2", InstanceID: "instance1", }, } diff --git a/tests/ipfilter/go.mod b/tests/ipfilter/go.mod index 28ae4b2c..407f0b8e 100644 --- a/tests/ipfilter/go.mod +++ b/tests/ipfilter/go.mod @@ -3,7 +3,7 @@ module github.com/drakkan/sftpgo/tests/ipfilter go 1.19 require ( - github.com/hashicorp/go-plugin v1.4.5 + github.com/hashicorp/go-plugin v1.4.6 github.com/sftpgo/sdk v0.1.2 ) @@ -16,10 +16,10 @@ require ( github.com/mattn/go-isatty v0.0.16 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/oklog/run v1.1.0 // indirect - golang.org/x/net v0.1.0 // indirect - golang.org/x/sys v0.1.0 // indirect + golang.org/x/net v0.2.0 // indirect + golang.org/x/sys v0.2.0 // indirect golang.org/x/text v0.4.0 // indirect - google.golang.org/genproto v0.0.0-20221018160656-63c7b68cfc55 // indirect - google.golang.org/grpc v1.50.1 // indirect + google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd // indirect + google.golang.org/grpc v1.51.0 // indirect google.golang.org/protobuf v1.28.1 // indirect ) diff --git a/tests/ipfilter/go.sum b/tests/ipfilter/go.sum index 8b28eb70..f5baee91 100644 --- a/tests/ipfilter/go.sum +++ b/tests/ipfilter/go.sum @@ -10,8 +10,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/hashicorp/go-hclog v1.3.1 h1:vDwF1DFNZhntP4DAjuTpOw3uEgMUpXh1pB5fW9DqHpo= github.com/hashicorp/go-hclog v1.3.1/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-plugin v1.4.5 h1:oTE/oQR4eghggRg8VY7PAz3dr++VwDNBGCcOfIvHpBo= -github.com/hashicorp/go-plugin v1.4.5/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-plugin v1.4.6 h1:MDV3UrKQBM3du3G7MApDGvOsMYy3JQJ4exhSoKBAeVA= +github.com/hashicorp/go-plugin v1.4.6/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= @@ -34,24 +34,24 @@ github.com/sftpgo/sdk v0.1.2/go.mod h1:PTp1TfXa+95wHw9yuZu7BA3vmzLqbRkz3gBmMNnwF github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -google.golang.org/genproto v0.0.0-20221018160656-63c7b68cfc55 h1:U1u4KB2kx6KR/aJDjQ97hZ15wQs8ZPvDcGcRynBhkvg= -google.golang.org/genproto v0.0.0-20221018160656-63c7b68cfc55/go.mod h1:45EK0dUbEZ2NHjCeAd2LXmyjAgGUGrpGROgjhC3ADck= -google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY= -google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd h1:OjndDrsik+Gt+e6fs45z9AxiewiKyLKYpA45W5Kpkks= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= +google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=