mirror of
https://github.com/drakkan/sftpgo.git
synced 2024-11-25 09:00:27 +00:00
EventManager: add IDP login trigger and check account action
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
parent
40344ec0ff
commit
e29f6857db
58 changed files with 1660 additions and 385 deletions
|
@ -15,6 +15,7 @@ The following actions are supported:
|
||||||
- `Metadata check`. A metadata check requires a metadata plugin such as [this one](https://github.com/sftpgo/sftpgo-plugin-metadata) and removes the metadata associated to missing items (for example objects deleted outside SFTPGo). A metadata check does nothing is no metadata plugin is installed or external metadata are not supported for a filesystem.
|
- `Metadata check`. A metadata check requires a metadata plugin such as [this one](https://github.com/sftpgo/sftpgo-plugin-metadata) and removes the metadata associated to missing items (for example objects deleted outside SFTPGo). A metadata check does nothing is no metadata plugin is installed or external metadata are not supported for a filesystem.
|
||||||
- `Password expiration check`. You can send an email notification to users whose password is about to expire.
|
- `Password expiration check`. You can send an email notification to users whose password is about to expire.
|
||||||
- `User expiration check`. You can receive notifications with expired users.
|
- `User expiration check`. You can receive notifications with expired users.
|
||||||
|
- `Identity Provider account check`. You can create/update accounts for users/admins logging in using an Identity Provider.
|
||||||
- `Filesystem`. For these actions, the required permissions are automatically granted. This is the same as executing the actions from an SFTP client and the same restrictions applies. Supported actions:
|
- `Filesystem`. For these actions, the required permissions are automatically granted. This is the same as executing the actions from an SFTP client and the same restrictions applies. Supported actions:
|
||||||
- `Rename`. You can rename one or more files or directories.
|
- `Rename`. You can rename one or more files or directories.
|
||||||
- `Delete`. You can delete one or more files and directories.
|
- `Delete`. You can delete one or more files and directories.
|
||||||
|
@ -47,6 +48,7 @@ The following placeholders are supported:
|
||||||
- `{{Timestamp}}`. Event timestamp as nanoseconds since epoch.
|
- `{{Timestamp}}`. Event timestamp as nanoseconds since epoch.
|
||||||
- `{{ObjectData}}`. Provider object data serialized as JSON with sensitive fields removed.
|
- `{{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.
|
- `{{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.
|
||||||
|
- `{{IDPField<fieldname>}}`. Identity Provider custom fields containing a string.
|
||||||
|
|
||||||
Event rules are based on the premise that an event occours. To each rule you can associate one or more actions.
|
Event rules are based on the premise that an event occours. To each rule you can associate one or more actions.
|
||||||
The following trigger events are supported:
|
The following trigger events are supported:
|
||||||
|
@ -57,6 +59,7 @@ The following trigger events are supported:
|
||||||
- `IP Blocked`, this event can be generated if you enable the [defender](./defender.md).
|
- `IP Blocked`, this event can be generated if you enable the [defender](./defender.md).
|
||||||
- `Certificate`, this event is generated when a certificate is renewed using the built-in ACME protocol. Both successful and failed renewals are notified.
|
- `Certificate`, this event is generated when a certificate is renewed using the built-in ACME protocol. Both successful and failed renewals are notified.
|
||||||
- `On demand`, this trigger is generated manually using the WebAdmin or the REST API.
|
- `On demand`, this trigger is generated manually using the WebAdmin or the REST API.
|
||||||
|
- `Identity Provider login`, this trigger is generated when a user/admin logs in using an external Identity Provider.
|
||||||
|
|
||||||
You can further restrict a rule by specifying additional conditions that must be met before the rule’s actions are taken. For example you can react to uploads only if they are performed by a particular user or using a specified protocol.
|
You can further restrict a rule by specifying additional conditions that must be met before the rule’s actions are taken. For example you can react to uploads only if they are performed by a particular user or using a specified protocol.
|
||||||
|
|
||||||
|
|
|
@ -121,6 +121,7 @@ And the following is an example ID token which allows the SFTPGo user `user1` to
|
||||||
```
|
```
|
||||||
|
|
||||||
SFTPGo users (not admins) can be created/updated after successful OpenID authentication by defining a [pre-login hook](./dynamic-user-mod.md).
|
SFTPGo users (not admins) can be created/updated after successful OpenID authentication by defining a [pre-login hook](./dynamic-user-mod.md).
|
||||||
|
Users and admins can also be created/updated after successful OpenID authentication using the [EventManager](./eventmanager.md).
|
||||||
You can use `scopes` configuration to request additional information (claims) about authenticated users (See your provider's own documentation for more information).
|
You can use `scopes` configuration to request additional information (claims) about authenticated users (See your provider's own documentation for more information).
|
||||||
By default the scopes `"openid", "profile", "email"` are retrieved.
|
By default the scopes `"openid", "profile", "email"` are retrieved.
|
||||||
The `custom_fields` configuration parameter can be used to define claim field names to pass to the pre-login hook,
|
The `custom_fields` configuration parameter can be used to define claim field names to pass to the pre-login hook,
|
||||||
|
@ -165,3 +166,5 @@ The pre-login hook will receive a JSON serialized user with the following field:
|
||||||
},
|
},
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
In EventManager actions you can use the placeholder `{{IDPFieldsftpgo_home_dir}}` for string-based custom fields.
|
||||||
|
|
64
go.mod
64
go.mod
|
@ -3,22 +3,22 @@ module github.com/drakkan/sftpgo/v2
|
||||||
go 1.20
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go/storage v1.29.0
|
cloud.google.com/go/storage v1.30.1
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0
|
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0
|
||||||
github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962
|
github.com/GehirnInc/crypt v0.0.0-20230320061759-8cc1b52080c5
|
||||||
github.com/alexedwards/argon2id v0.0.0-20230305115115-4b3c3280a736
|
github.com/alexedwards/argon2id v0.0.0-20230305115115-4b3c3280a736
|
||||||
github.com/aws/aws-sdk-go-v2 v1.17.6
|
github.com/aws/aws-sdk-go-v2 v1.17.7
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.18.17
|
github.com/aws/aws-sdk-go-v2/config v1.18.19
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.17
|
github.com/aws/aws-sdk-go-v2/credentials v1.13.18
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.0
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.1
|
||||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.57
|
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.59
|
||||||
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.14.6
|
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.14.7
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.30.6
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.31.0
|
||||||
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.19.0
|
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.19.1
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.18.6
|
github.com/aws/aws-sdk-go-v2/service/sts v1.18.7
|
||||||
github.com/bmatcuk/doublestar/v4 v4.6.0
|
github.com/bmatcuk/doublestar/v4 v4.6.0
|
||||||
github.com/cockroachdb/cockroach-go/v2 v2.3.2
|
github.com/cockroachdb/cockroach-go/v2 v2.3.3
|
||||||
github.com/coreos/go-oidc/v3 v3.5.0
|
github.com/coreos/go-oidc/v3 v3.5.0
|
||||||
github.com/drakkan/webdav v0.0.0-20230227175313-32996838bcd8
|
github.com/drakkan/webdav v0.0.0-20230227175313-32996838bcd8
|
||||||
github.com/eikenb/pipeat v0.0.0-20210730190139-06b3e6902001
|
github.com/eikenb/pipeat v0.0.0-20210730190139-06b3e6902001
|
||||||
|
@ -32,13 +32,13 @@ require (
|
||||||
github.com/golang/mock v1.6.0
|
github.com/golang/mock v1.6.0
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/hashicorp/go-hclog v1.4.0
|
github.com/hashicorp/go-hclog v1.5.0
|
||||||
github.com/hashicorp/go-plugin v1.4.10-0.20230306173702-d78f3fc2891d
|
github.com/hashicorp/go-plugin v1.4.10-0.20230306173702-d78f3fc2891d
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.2
|
github.com/hashicorp/go-retryablehttp v0.7.2
|
||||||
github.com/jackc/pgx/v5 v5.3.2-0.20230311213408-9ae852eb583d
|
github.com/jackc/pgx/v5 v5.3.2-0.20230311213408-9ae852eb583d
|
||||||
github.com/jlaffaye/ftp v0.0.0-20201112195030-9aae4d151126
|
github.com/jlaffaye/ftp v0.0.0-20201112195030-9aae4d151126
|
||||||
github.com/klauspost/compress v1.16.3
|
github.com/klauspost/compress v1.16.3
|
||||||
github.com/lestrrat-go/jwx/v2 v2.0.8
|
github.com/lestrrat-go/jwx/v2 v2.0.9
|
||||||
github.com/lithammer/shortuuid/v3 v3.0.7
|
github.com/lithammer/shortuuid/v3 v3.0.7
|
||||||
github.com/mattn/go-sqlite3 v1.14.16
|
github.com/mattn/go-sqlite3 v1.14.16
|
||||||
github.com/mhale/smtpd v0.8.0
|
github.com/mhale/smtpd v0.8.0
|
||||||
|
@ -62,10 +62,10 @@ require (
|
||||||
github.com/subosito/gotenv v1.4.2
|
github.com/subosito/gotenv v1.4.2
|
||||||
github.com/unrolled/secure v1.13.0
|
github.com/unrolled/secure v1.13.0
|
||||||
github.com/wagslane/go-password-validator v0.3.0
|
github.com/wagslane/go-password-validator v0.3.0
|
||||||
github.com/wneessen/go-mail v0.3.8
|
github.com/wneessen/go-mail v0.3.9
|
||||||
github.com/yl2chen/cidranger v1.0.3-0.20210928021809-d1cb2c52f37a
|
github.com/yl2chen/cidranger v1.0.3-0.20210928021809-d1cb2c52f37a
|
||||||
go.etcd.io/bbolt v1.3.7
|
go.etcd.io/bbolt v1.3.7
|
||||||
go.uber.org/automaxprocs v1.5.1
|
go.uber.org/automaxprocs v1.5.2
|
||||||
gocloud.dev v0.29.0
|
gocloud.dev v0.29.0
|
||||||
golang.org/x/crypto v0.7.0
|
golang.org/x/crypto v0.7.0
|
||||||
golang.org/x/net v0.8.0
|
golang.org/x/net v0.8.0
|
||||||
|
@ -73,7 +73,7 @@ require (
|
||||||
golang.org/x/sys v0.6.0
|
golang.org/x/sys v0.6.0
|
||||||
golang.org/x/term v0.6.0
|
golang.org/x/term v0.6.0
|
||||||
golang.org/x/time v0.3.0
|
golang.org/x/time v0.3.0
|
||||||
google.golang.org/api v0.112.0
|
google.golang.org/api v0.114.0
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -81,20 +81,20 @@ require (
|
||||||
cloud.google.com/go v0.110.0 // indirect
|
cloud.google.com/go v0.110.0 // indirect
|
||||||
cloud.google.com/go/compute v1.18.0 // indirect
|
cloud.google.com/go/compute v1.18.0 // indirect
|
||||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||||
cloud.google.com/go/iam v0.12.0 // indirect
|
cloud.google.com/go/iam v0.13.0 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.2.0 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.2.0 // indirect
|
||||||
github.com/ajg/form v1.5.1 // indirect
|
github.com/ajg/form v1.5.1 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // 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.30 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.31 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.32 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.22 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.23 // 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/accept-encoding v1.9.11 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.25 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.26 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.24 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.25 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.24 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.0 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.12.5 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sso v1.12.6 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.5 // indirect
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.6 // indirect
|
||||||
github.com/aws/smithy-go v1.13.5 // indirect
|
github.com/aws/smithy-go v1.13.5 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/boombuler/barcode v1.0.1 // indirect
|
github.com/boombuler/barcode v1.0.1 // indirect
|
||||||
|
@ -108,7 +108,7 @@ require (
|
||||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||||
github.com/go-jose/go-jose/v3 v3.0.0 // indirect
|
github.com/go-jose/go-jose/v3 v3.0.0 // indirect
|
||||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||||
github.com/goccy/go-json v0.10.1 // indirect
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
github.com/google/go-cmp v0.5.9 // indirect
|
github.com/google/go-cmp v0.5.9 // indirect
|
||||||
|
@ -131,7 +131,7 @@ require (
|
||||||
github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de // indirect
|
github.com/lufia/plan9stats v0.0.0-20230110061619-bbe2e5e100de // indirect
|
||||||
github.com/magiconair/properties v1.8.7 // indirect
|
github.com/magiconair/properties v1.8.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
github.com/mattn/go-isatty v0.0.18 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||||
github.com/miekg/dns v1.1.52 // indirect
|
github.com/miekg/dns v1.1.52 // indirect
|
||||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||||
|
@ -157,9 +157,9 @@ require (
|
||||||
golang.org/x/tools v0.7.0 // indirect
|
golang.org/x/tools v0.7.0 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect
|
google.golang.org/genproto v0.0.0-20230320184635-7606e756e683 // indirect
|
||||||
google.golang.org/grpc v1.53.0 // indirect
|
google.golang.org/grpc v1.54.0 // indirect
|
||||||
google.golang.org/protobuf v1.29.1 // indirect
|
google.golang.org/protobuf v1.30.0 // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
126
go.sum
126
go.sum
|
@ -217,8 +217,8 @@ cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHD
|
||||||
cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg=
|
cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg=
|
||||||
cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE=
|
cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE=
|
||||||
cloud.google.com/go/iam v0.10.0/go.mod h1:nXAECrMt2qHpF6RZUZseteD6QyanL68reN4OXPw0UWM=
|
cloud.google.com/go/iam v0.10.0/go.mod h1:nXAECrMt2qHpF6RZUZseteD6QyanL68reN4OXPw0UWM=
|
||||||
cloud.google.com/go/iam v0.12.0 h1:DRtTY29b75ciH6Ov1PHb4/iat2CLCvrOm40Q0a6DFpE=
|
cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k=
|
||||||
cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY=
|
cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0=
|
||||||
cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc=
|
cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc=
|
||||||
cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A=
|
cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A=
|
||||||
cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM=
|
cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM=
|
||||||
|
@ -368,8 +368,9 @@ cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq
|
||||||
cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc=
|
cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc=
|
||||||
cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s=
|
cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s=
|
||||||
cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y=
|
cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y=
|
||||||
cloud.google.com/go/storage v1.29.0 h1:6weCgzRvMg7lzuUurI4697AqIRPU1SvzHhynwpW31jI=
|
|
||||||
cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4=
|
cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4=
|
||||||
|
cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM=
|
||||||
|
cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E=
|
||||||
cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w=
|
cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w=
|
||||||
cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I=
|
cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I=
|
||||||
cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw=
|
cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw=
|
||||||
|
@ -478,8 +479,8 @@ github.com/AzureAD/microsoft-authentication-library-for-go v0.8.1/go.mod h1:4qFo
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||||
github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962 h1:KeNholpO2xKjgaaSyd+DyQRrsQjhbSeS7qe4nEw8aQw=
|
github.com/GehirnInc/crypt v0.0.0-20230320061759-8cc1b52080c5 h1:IEjq88XO4PuBDcvmjQJcQGg+w+UaafSy8G5Kcb5tBhI=
|
||||||
github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962/go.mod h1:kC29dT1vFpj7py2OvG1khBdQpo3kInWP+6QipLbdngo=
|
github.com/GehirnInc/crypt v0.0.0-20230320061759-8cc1b52080c5/go.mod h1:exZ0C/1emQJAw5tHOaUDyY1ycttqBAPcxuzf7QbY6ec=
|
||||||
github.com/GoogleCloudPlatform/cloudsql-proxy v1.33.2/go.mod h1:uqoR4sJc63p7ugW8a/vsEspOsNuehbi7ptS2CHCyOnY=
|
github.com/GoogleCloudPlatform/cloudsql-proxy v1.33.2/go.mod h1:uqoR4sJc63p7ugW8a/vsEspOsNuehbi7ptS2CHCyOnY=
|
||||||
github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
|
github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
|
||||||
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
|
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
|
||||||
|
@ -556,67 +557,67 @@ github.com/aws/aws-sdk-go v1.44.187/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8
|
||||||
github.com/aws/aws-sdk-go v1.44.200/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
github.com/aws/aws-sdk-go v1.44.200/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
|
github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.17.4/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
|
github.com/aws/aws-sdk-go-v2 v1.17.4/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.17.6 h1:Y773UK7OBqhzi5VDXMi1zVGsoj+CVHs2eaC2bDsLwi0=
|
github.com/aws/aws-sdk-go-v2 v1.17.7 h1:CLSjnhJSTSogvqUGhIC6LqFKATMRexcxLZ0i/Nzk9Eg=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.17.6/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
|
github.com/aws/aws-sdk-go-v2 v1.17.7/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
|
||||||
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 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/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.18.12/go.mod h1:J36fOhj1LQBr+O4hJCiT8FwVvieeoSGOtPuvhKlsNu8=
|
github.com/aws/aws-sdk-go-v2/config v1.18.12/go.mod h1:J36fOhj1LQBr+O4hJCiT8FwVvieeoSGOtPuvhKlsNu8=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.18.17 h1:jwTkhULSrbr/SQA8tfdYqZxpG8YsRycmIXxJcbrqY5E=
|
github.com/aws/aws-sdk-go-v2/config v1.18.19 h1:AqFK6zFNtq4i1EYu+eC7lcKHYnZagMn6SW171la0bGw=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.18.17/go.mod h1:Lj3E7XcxJnxMa+AYo89YiL68s1cFJRGduChynYU67VA=
|
github.com/aws/aws-sdk-go-v2/config v1.18.19/go.mod h1:XvTmGMY8d52ougvakOv1RpiTLPz9dlG/OQHsKU/cMmY=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.12/go.mod h1:37HG2MBroXK3jXfxVGtbM2J48ra2+Ltu+tmwr/jO0KA=
|
github.com/aws/aws-sdk-go-v2/credentials v1.13.12/go.mod h1:37HG2MBroXK3jXfxVGtbM2J48ra2+Ltu+tmwr/jO0KA=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.17 h1:IubQO/RNeIVKF5Jy77w/LfUvmmCxTnk2TP1UZZIMiF4=
|
github.com/aws/aws-sdk-go-v2/credentials v1.13.18 h1:EQMdtHwz0ILTW1hoP+EwuWhwCG1hD6l3+RWFQABET4c=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.17/go.mod h1:K9xeFo1g/YPMguMUD69YpwB4Nyi6W/5wn706xIInJFg=
|
github.com/aws/aws-sdk-go-v2/credentials v1.13.18/go.mod h1:vnwlwjIe+3XJPBYKu1et30ZPABG3VaXJYr8ryohpIyM=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.22/go.mod h1:YGSIJyQ6D6FjKMQh16hVFSIUD54L4F7zTGePqYMYYJU=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.22/go.mod h1:YGSIJyQ6D6FjKMQh16hVFSIUD54L4F7zTGePqYMYYJU=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.0 h1:/2Cb3SK3xVOQA7Xfr5nCWCo5H3UiNINtsVvVdk8sQqA=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.1 h1:gt57MN3liKiyGopcqgNzJb2+d9MJaKT/q1OksHNXVE4=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.0/go.mod h1:neYVaeKr5eT7BzwULuG2YbLhzWZ22lpjKdCybR7AXrQ=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.1/go.mod h1:lfUx8puBRdM5lVVMQlwt2v+ofiG/X6Ms+dy0UkG/kXw=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.51/go.mod h1:7Grl2gV+dx9SWrUIgwwlUvU40t7+lOSbx34XwfmsTkY=
|
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.51/go.mod h1:7Grl2gV+dx9SWrUIgwwlUvU40t7+lOSbx34XwfmsTkY=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.57 h1:ubKS0iZH5veiqb44qeHzaoKNPvCZQeBVFw4JDhfeWjk=
|
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.59 h1:E3Y+OfzOK1+rmRo/K2G0ml8Vs+Xqk0kOnf4nS0kUtBc=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.57/go.mod h1:dRBjXtcjmYglxVHpdoGGVWvZumDC27I2GLDGI0Uw4RQ=
|
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.59/go.mod h1:1M4PLSBUVfBI0aP+C9XI7SM6kZPCGYyI6izWz0TGprE=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.28/go.mod h1:3lwChorpIM/BhImY/hy+Z6jekmN92cXGPI1QJasVPYY=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.28/go.mod h1:3lwChorpIM/BhImY/hy+Z6jekmN92cXGPI1QJasVPYY=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30 h1:y+8n9AGDjikyXoMBTRaHHHSaFEB8267ykmvyPodJfys=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31 h1:sJLYcS+eZn5EeNINGHSCRAwUJMFVqklwkH36Vbyai7M=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30/go.mod h1:LUBAO3zNXQjoONBKn/kR1y0Q4cj/D02Ts0uHYjcCQLM=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31/go.mod h1:QT0BqUvX1Bh2ABdTGnjqEjvjzrCfIniM9Sc8zn9Yndo=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.22/go.mod h1:EqK7gVrIGAHyZItrD1D8B0ilgwMD1GiWAmbU4u/JHNk=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.22/go.mod h1:EqK7gVrIGAHyZItrD1D8B0ilgwMD1GiWAmbU4u/JHNk=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24 h1:r+Kv+SEJquhAZXaJ7G4u44cIwXV3f8K+N482NNAzJZA=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25 h1:1mnRASEKnkqsntcxHaysxwgVoUUp5dkiB+l3llKnqyg=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24/go.mod h1:gAuCezX/gob6BSMbItsSlMb6WZGV7K2+fWOvk8xBSto=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25/go.mod h1:zBHOPwhBc3FlQjQJE/D3IfPWiWaQmT06Vq9aNukDo0k=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.29/go.mod h1:TwuqRBGzxjQJIwH16/fOZodwXt2Zxa9/cwJC5ke4j7s=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.29/go.mod h1:TwuqRBGzxjQJIwH16/fOZodwXt2Zxa9/cwJC5ke4j7s=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.31 h1:hf+Vhp5WtTdcSdE+yEcUz8L73sAzN0R+0jQv+Z51/mI=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.32 h1:p5luUImdIqywn6JpQsW3tq5GNOxKmOnEpybzPx+d1lk=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.31/go.mod h1:5zUjguZfG5qjhG9/wqmuyHRyUftl2B5Cp6NNxNC6kRA=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.32/go.mod h1:XGhIBZDEgfqmFIugclZ6FU7v75nHhBDtzuB4xB/tEi4=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.19/go.mod h1:8W88sW3PjamQpKFUQvHWWKay6ARsNvZnzU7+a4apubw=
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.19/go.mod h1:8W88sW3PjamQpKFUQvHWWKay6ARsNvZnzU7+a4apubw=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.22 h1:lTqBRUuy8oLhBsnnVZf14uRbIHPHCrGqg4Plc8gU/1U=
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.23 h1:DWYZIsyqagnWL00f8M/SOr9fN063OEQWn9LLTbdYXsk=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.22/go.mod h1:YsOa3tFriwWNvBPYHXM5ARiU2yqBNWPWeUiq+4i7Na0=
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.23/go.mod h1:uIiFgURZbACBEQJfqTZPb/jxO7R+9LeoHUFudtIdeQI=
|
||||||
github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o=
|
github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o=
|
||||||
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 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/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.23/go.mod h1:1jcUfF+FAOEwtIcNiHPaV4TSoZqkUIPzrohmD7fb95c=
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.23/go.mod h1:1jcUfF+FAOEwtIcNiHPaV4TSoZqkUIPzrohmD7fb95c=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.25 h1:B/hO3jfWRm7hP00UeieNlI5O2xP5WJ27tyJG5lzc7AM=
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.26 h1:CeuSeq/8FnYpPtnuIeLQEEvDv9zUjneuYi8EghMBdwQ=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.25/go.mod h1:54K1zgxK/lai3a4HosE4IKBwZsP/5YAJ6dzJfwsjJ0U=
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.26/go.mod h1:2UqAAwMUXKeRkAHIlDJqvMVgOWkUi/AUXPk/YIe+Dg4=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.22/go.mod h1:xt0Au8yPIwYXf/GYPy/vl4K3CgwhfQMYbrH7DlUUIws=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.22/go.mod h1:xt0Au8yPIwYXf/GYPy/vl4K3CgwhfQMYbrH7DlUUIws=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.24 h1:c5qGfdbCHav6viBwiyDns3OXqhqAbGjfIB4uVu2ayhk=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.25 h1:5LHn8JQ0qvjD9L9JhMtylnkcw7j05GDZqM9Oin6hpr0=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.24/go.mod h1:HMA4FZG6fyib+NDo5bpIxX1EhYjrAOveZJY2YR0xrNE=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.25/go.mod h1:/95IA+0lMnzW6XzqYJRpjjsAbKEORVeO0anQqjd2CNU=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.22/go.mod h1:QFVbqK54XArazLvn2wvWMRBi/jGrWii46qbr5DyPGjc=
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.22/go.mod h1:QFVbqK54XArazLvn2wvWMRBi/jGrWii46qbr5DyPGjc=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.24 h1:i4RH8DLv/BHY0fCrXYQDr+DGnWzaxB3Ee/esxUaSavk=
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.0 h1:e2ooMhpYGhDnBfSvIyusvAwX7KexuZaHbQY2Dyei7VU=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.24/go.mod h1:N8X45/o2cngvjCYi2ZnvI0P4mU4ZRJfEYC3maCSsPyw=
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.0/go.mod h1:bh2E0CXKZsQN+faiKVqC40vfNMAWheoULBCnEgO9K+8=
|
||||||
github.com/aws/aws-sdk-go-v2/service/kms v1.20.2/go.mod h1:vdqtUOdVuf5ooy+hJ2GnzqNo94xiAA9s1xbZ1hQgRE0=
|
github.com/aws/aws-sdk-go-v2/service/kms v1.20.2/go.mod h1:vdqtUOdVuf5ooy+hJ2GnzqNo94xiAA9s1xbZ1hQgRE0=
|
||||||
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.14.6 h1:3yAJmDgUzVGGp5PkHA/HGFquEJRK0uEaep22XZj4UJg=
|
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.14.7 h1:QA+w3BlShNMgOTRN1kBG2qOIHuTzVTxZ0l3ImKkz+ic=
|
||||||
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.14.6/go.mod h1:kFXyTQKLc5KyBUhJ0kUckwncHElnSEbXbBeGpNJUMEY=
|
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.14.7/go.mod h1:8Ma9cuRQADU+FwLPYmoSdvUt4tItX2kleWi/++H0BF0=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.30.2/go.mod h1:SXDHd6fI2RhqB7vmAzyYQCTQnpZrIprVJvYxpzW3JAM=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.30.2/go.mod h1:SXDHd6fI2RhqB7vmAzyYQCTQnpZrIprVJvYxpzW3JAM=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.30.6 h1:zzTm99krKsFcF4N7pu2z17yCcAZpQYZ7jnJZPIgEMXE=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.31.0 h1:B1G2pSPvbAtQjilPq+Y7jLIzCOwKzuVEl+aBBaNG0AQ=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.30.6/go.mod h1:PudwVKUTApfm0nYaPutOXaKdPKTlZYClGBQpVIRdcbs=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.31.0/go.mod h1:ncltU6n4Nof5uJttDtcNQ537uNuwYqsZZQcpkd2/GUQ=
|
||||||
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.18.3/go.mod h1:hqPcyOuLU6yWIbLy3qMnQnmidgKuIEwqIlW6+chYnog=
|
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.18.3/go.mod h1:hqPcyOuLU6yWIbLy3qMnQnmidgKuIEwqIlW6+chYnog=
|
||||||
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.19.0 h1:B4LvuBxrxh2WXakqwJL22EPAWgqGGK9/E4YQV/IIkYo=
|
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.19.1 h1:+rANS0SbrDUqF3VJeil1HJHhNK8vdUu1VGqnkr4o6kw=
|
||||||
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.19.0/go.mod h1:XF4Gbmcn6V9xIIm6lhwtyX1NXConNJ8x6yizt2Ejx/0=
|
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.19.1/go.mod h1:SUiYnlcBDUvSLD6iUmwSwXni2i6iGa9WHc+eM5061W4=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sns v1.20.2/go.mod h1:VN2n9SOMS1lNbh5YD7o+ho0/rgfifSrK//YYNiVVF5E=
|
github.com/aws/aws-sdk-go-v2/service/sns v1.20.2/go.mod h1:VN2n9SOMS1lNbh5YD7o+ho0/rgfifSrK//YYNiVVF5E=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.20.2/go.mod h1:1ttxGjUHZliCQMpPss1sU5+Ph/5NvdMFRzr96bv8gm0=
|
github.com/aws/aws-sdk-go-v2/service/sqs v1.20.2/go.mod h1:1ttxGjUHZliCQMpPss1sU5+Ph/5NvdMFRzr96bv8gm0=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssm v1.35.2/go.mod h1:VLSz2SHUKYFSOlXB/GlXoLU6KPYQJAbw7I20TDJdyws=
|
github.com/aws/aws-sdk-go-v2/service/ssm v1.35.2/go.mod h1:VLSz2SHUKYFSOlXB/GlXoLU6KPYQJAbw7I20TDJdyws=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.12.1/go.mod h1:IgV8l3sj22nQDd5qcAGY0WenwCzCphqdbFOpfktZPrI=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.12.1/go.mod h1:IgV8l3sj22nQDd5qcAGY0WenwCzCphqdbFOpfktZPrI=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.12.5 h1:bdKIX6SVF3nc3xJFw6Nf0igzS6Ff/louGq8Z6VP/3Hs=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.12.6 h1:5V7DWLBd7wTELVz5bPpwzYy/sikk0gsgZfj40X+l5OI=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.12.5/go.mod h1:vuWiaDB30M/QTC+lI3Wj6S/zb7tpUK2MSYgy3Guh2L0=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.12.6/go.mod h1:Y1VOmit/Fn6Tz1uFAeCO6Q7M2fmfXSCLeL5INVYsLuY=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.1/go.mod h1:O1YSOg3aekZibh2SngvCRRG+cRHKKlYgxf/JBF/Kr/k=
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.1/go.mod h1:O1YSOg3aekZibh2SngvCRRG+cRHKKlYgxf/JBF/Kr/k=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.5 h1:xLPZMyuZ4GuqRCIec/zWuIhRFPXh2UOJdLXBSi64ZWQ=
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.6 h1:B8cauxOH1W1v7rd8RdI/MWnoR4Ze0wIHWrb90qczxj4=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.5/go.mod h1:QjxpHmCwAg0ESGtPQnLIVp7SedTOBMYy+Slr3IfMKeI=
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.6/go.mod h1:Lh/bc9XUf8CfOY6Jp5aIkQtN+j1mc+nExc+KXj9jx2s=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.18.3/go.mod h1:b+psTJn33Q4qGoDaM7ZiOVVG8uVjGI6HaZ8WBHdgDgU=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.18.3/go.mod h1:b+psTJn33Q4qGoDaM7ZiOVVG8uVjGI6HaZ8WBHdgDgU=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.18.6 h1:rIFn5J3yDoeuKCE9sESXqM5POTAhOP1du3bv/qTL+tE=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.18.7 h1:bWNgNdRko2x6gqa0blfATqAZKZokPIeM1vfmQt2pnvM=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.18.6/go.mod h1:48WJ9l3dwP0GSHWGc5sFGGlCkuA82Mc2xnw+T6Q8aDw=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.18.7/go.mod h1:JuTnSoeePXmMVe9G8NcjjwgOKEfZ4cOjMuT2IBT/2eI=
|
||||||
github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
|
github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
|
||||||
github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8=
|
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/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
|
||||||
|
@ -693,8 +694,8 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH
|
||||||
github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||||
github.com/cockroachdb/cockroach-go/v2 v2.3.2 h1:r+HgkUAPoRtB5UUxnSvmh3irEVeUETHSAjCSxX5Tfto=
|
github.com/cockroachdb/cockroach-go/v2 v2.3.3 h1:fNmtG6XhoA1DhdDCIu66YyGSsNb1szj4CaAsbDxRmy4=
|
||||||
github.com/cockroachdb/cockroach-go/v2 v2.3.2/go.mod h1:1wNJ45eSXW9AnOc3skntW9ZUZz6gxrQK3cOj3rK+BC8=
|
github.com/cockroachdb/cockroach-go/v2 v2.3.3/go.mod h1:1wNJ45eSXW9AnOc3skntW9ZUZz6gxrQK3cOj3rK+BC8=
|
||||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||||
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
|
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
|
||||||
github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
|
github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
|
||||||
|
@ -1062,9 +1063,8 @@ github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY9
|
||||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
||||||
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||||
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
||||||
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
github.com/goccy/go-json v0.10.1 h1:lEs5Ob+oOG/Ze199njvzHbhn6p9T+h64F5hRj69iTTo=
|
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
github.com/goccy/go-json v0.10.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
|
||||||
github.com/goccy/go-yaml v1.9.5/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA=
|
github.com/goccy/go-yaml v1.9.5/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA=
|
||||||
github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
||||||
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
||||||
|
@ -1278,8 +1278,8 @@ github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39
|
||||||
github.com/hashicorp/go-hclog v0.12.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
github.com/hashicorp/go-hclog v0.12.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||||
github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||||
github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||||
github.com/hashicorp/go-hclog v1.4.0 h1:ctuWFGrhFha8BnnzxqeRGidlEcQkDyL5u8J8t5eA11I=
|
github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
|
||||||
github.com/hashicorp/go-hclog v1.4.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||||
github.com/hashicorp/go-immutable-radix v1.2.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
github.com/hashicorp/go-immutable-radix v1.2.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||||
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||||
|
@ -1475,8 +1475,8 @@ github.com/lestrrat-go/httprc v1.0.4 h1:bAZymwoZQb+Oq8MEbyipag7iSq6YIga8Wj6GOiJG
|
||||||
github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
|
github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
|
||||||
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
|
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
|
||||||
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
|
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
|
||||||
github.com/lestrrat-go/jwx/v2 v2.0.8 h1:jCFT8oc0hEDVjgUgsBy1F9cbjsjAVZSXNi7JaU9HR/Q=
|
github.com/lestrrat-go/jwx/v2 v2.0.9 h1:TRX4Q630UXxPVLvP5vGaqVJO7S+0PE6msRZUsFSBoC8=
|
||||||
github.com/lestrrat-go/jwx/v2 v2.0.8/go.mod h1:zLxnyv9rTlEvOUHbc48FAfIL8iYu2hHvIRaTFGc8mT0=
|
github.com/lestrrat-go/jwx/v2 v2.0.9/go.mod h1:K68euYaR95FnL0hIQB8VvzL70vB7pSifbJUydCTPmgM=
|
||||||
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
||||||
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
|
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
|
||||||
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
||||||
|
@ -1529,8 +1529,8 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
|
||||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
||||||
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
||||||
|
@ -1963,8 +1963,8 @@ github.com/wagslane/go-password-validator v0.3.0 h1:vfxOPzGHkz5S146HDpavl0cw1DSV
|
||||||
github.com/wagslane/go-password-validator v0.3.0/go.mod h1:TI1XJ6T5fRdRnHqHt14pvy1tNVnrwe7m3/f1f2fDphQ=
|
github.com/wagslane/go-password-validator v0.3.0/go.mod h1:TI1XJ6T5fRdRnHqHt14pvy1tNVnrwe7m3/f1f2fDphQ=
|
||||||
github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||||
github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
|
github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
|
||||||
github.com/wneessen/go-mail v0.3.8 h1:ja5D/o/RVwrtRIYFlrO7GmtcjDNeMakGQuwQRZYv0JM=
|
github.com/wneessen/go-mail v0.3.9 h1:Q4DbCk3htT5DtDWKeMgNXCiHc4bBY/vv/XQPT6XDXzc=
|
||||||
github.com/wneessen/go-mail v0.3.8/go.mod h1:m25lkU2GYQnlVr6tdwK533/UXxo57V0kLOjaFYmub0E=
|
github.com/wneessen/go-mail v0.3.9/go.mod h1:zxOlafWCP/r6FEhAaRgH4IC1vg2YXxO0Nar9u0IScZ8=
|
||||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||||
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
|
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
|
||||||
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
|
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
|
||||||
|
@ -2080,8 +2080,9 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
go.uber.org/automaxprocs v1.5.1 h1:e1YG66Lrk73dn4qhg8WFSvhF0JuFQF0ERIp4rpuV8Qk=
|
|
||||||
go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU=
|
go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU=
|
||||||
|
go.uber.org/automaxprocs v1.5.2 h1:2LxUOGiR3O6tw8ui5sZa2LAaHnsviZdVOUZw4fvbnME=
|
||||||
|
go.uber.org/automaxprocs v1.5.2/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
|
||||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||||
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||||
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||||
|
@ -2655,8 +2656,8 @@ google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/
|
||||||
google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=
|
google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=
|
||||||
google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=
|
google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=
|
||||||
google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI=
|
google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI=
|
||||||
google.golang.org/api v0.112.0 h1:iDmzvZ4C086R3+en4nSyIf07HlQKMOX1Xx2dmia/+KQ=
|
google.golang.org/api v0.114.0 h1:1xQPji6cO2E2vLiI+C/XiFAnsn1WV3mjaEwGLhi3grE=
|
||||||
google.golang.org/api v0.112.0/go.mod h1:737UfWHNsOq4F3REUTmb+GN9pugkgNLCayLTfoIKpPc=
|
google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
@ -2801,8 +2802,8 @@ google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ
|
||||||
google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
||||||
google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
||||||
google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
||||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA=
|
google.golang.org/genproto v0.0.0-20230320184635-7606e756e683 h1:khxVcsk/FhnzxMKOyD+TDGwjbEOpcPuIpmafPGFmhMA=
|
||||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
|
google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
|
||||||
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
|
@ -2846,8 +2847,9 @@ google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCD
|
||||||
google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||||
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
|
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
|
||||||
google.golang.org/grpc v1.52.1/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY=
|
google.golang.org/grpc v1.52.1/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY=
|
||||||
google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
|
|
||||||
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
|
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
|
||||||
|
google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=
|
||||||
|
google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
|
||||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
@ -2864,8 +2866,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
|
||||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
google.golang.org/protobuf v1.29.1 h1:7QBf+IK2gx70Ap/hDsOmam3GE0v9HicjfEdAxE62UoM=
|
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||||
google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|
|
@ -287,10 +287,7 @@ func (c *Configuration) validateChallenges() error {
|
||||||
if err := c.HTTP01Challenge.validate(); err != nil {
|
if err := c.HTTP01Challenge.validate(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := c.TLSALPN01Challenge.validate(); err != nil {
|
return c.TLSALPN01Challenge.validate()
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Configuration) checkDomains() {
|
func (c *Configuration) checkDomains() {
|
||||||
|
|
|
@ -321,7 +321,7 @@ type actionHandlerStub struct {
|
||||||
called bool
|
called bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *actionHandlerStub) Handle(event *notifier.FsEvent) (int, error) {
|
func (h *actionHandlerStub) Handle(_ *notifier.FsEvent) (int, error) {
|
||||||
h.called = true
|
h.called = true
|
||||||
|
|
||||||
return 1, nil
|
return 1, nil
|
||||||
|
|
|
@ -1235,7 +1235,7 @@ func TestParseAllowedIPAndRanges(t *testing.T) {
|
||||||
assert.False(t, allow[1](net.ParseIP("172.16.1.1")))
|
assert.False(t, allow[1](net.ParseIP("172.16.1.1")))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHideConfidentialData(t *testing.T) {
|
func TestHideConfidentialData(_ *testing.T) {
|
||||||
for _, provider := range []sdk.FilesystemProvider{sdk.LocalFilesystemProvider,
|
for _, provider := range []sdk.FilesystemProvider{sdk.LocalFilesystemProvider,
|
||||||
sdk.CryptedFilesystemProvider, sdk.S3FilesystemProvider, sdk.GCSFilesystemProvider,
|
sdk.CryptedFilesystemProvider, sdk.S3FilesystemProvider, sdk.GCSFilesystemProvider,
|
||||||
sdk.AzureBlobFilesystemProvider, sdk.SFTPFilesystemProvider,
|
sdk.AzureBlobFilesystemProvider, sdk.SFTPFilesystemProvider,
|
||||||
|
|
|
@ -63,7 +63,7 @@ func (fs *MockOsFs) IsUploadResumeSupported() bool {
|
||||||
return !fs.hasVirtualFolders
|
return !fs.hasVirtualFolders
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *MockOsFs) Chtimes(name string, atime, mtime time.Time, isUploading bool) error {
|
func (fs *MockOsFs) Chtimes(_ string, _, _ time.Time, _ bool) error {
|
||||||
return vfs.ErrVfsUnsupported
|
return vfs.ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ func (fs *MockOsFs) Lstat(name string) (os.FileInfo, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Walk returns a duplicate path for testing
|
// Walk returns a duplicate path for testing
|
||||||
func (fs *MockOsFs) Walk(root string, walkFn filepath.WalkFunc) error {
|
func (fs *MockOsFs) Walk(_ string, walkFn filepath.WalkFunc) error {
|
||||||
if fs.err == errWalkDir {
|
if fs.err == errWalkDir {
|
||||||
walkFn("fsdpath", vfs.NewFileInfo("dpath", true, 0, time.Now(), false), nil) //nolint:errcheck
|
walkFn("fsdpath", vfs.NewFileInfo("dpath", true, 0, time.Now(), false), nil) //nolint:errcheck
|
||||||
return walkFn("fsdpath", vfs.NewFileInfo("dpath", true, 0, time.Now(), false), nil) //nolint:errcheck
|
return walkFn("fsdpath", vfs.NewFileInfo("dpath", true, 0, time.Now(), false), nil) //nolint:errcheck
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/csv"
|
"encoding/csv"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
@ -56,6 +57,12 @@ const (
|
||||||
maxAttachmentsSize = int64(10 * 1024 * 1024)
|
maxAttachmentsSize = int64(10 * 1024 * 1024)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Supported IDP login events
|
||||||
|
const (
|
||||||
|
IDPLoginUser = "IDP login user"
|
||||||
|
IDPLoginAdmin = "IDP login admin"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// eventManager handle the supported event rules actions
|
// eventManager handle the supported event rules actions
|
||||||
eventManager eventRulesContainer
|
eventManager eventRulesContainer
|
||||||
|
@ -90,6 +97,11 @@ func HandleCertificateEvent(params EventParams) {
|
||||||
eventManager.handleCertificateEvent(params)
|
eventManager.handleCertificateEvent(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HandleIDPLoginEvent executes actions defined for a successful login from an Identity Provider
|
||||||
|
func HandleIDPLoginEvent(params EventParams, customFields *map[string]any) (*dataprovider.User, *dataprovider.Admin, error) {
|
||||||
|
return eventManager.handleIDPLoginEvent(params, customFields)
|
||||||
|
}
|
||||||
|
|
||||||
// eventRulesContainer stores event rules by trigger
|
// eventRulesContainer stores event rules by trigger
|
||||||
type eventRulesContainer struct {
|
type eventRulesContainer struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
|
@ -99,6 +111,7 @@ type eventRulesContainer struct {
|
||||||
Schedules []dataprovider.EventRule
|
Schedules []dataprovider.EventRule
|
||||||
IPBlockedEvents []dataprovider.EventRule
|
IPBlockedEvents []dataprovider.EventRule
|
||||||
CertificateEvents []dataprovider.EventRule
|
CertificateEvents []dataprovider.EventRule
|
||||||
|
IPDLoginEvents []dataprovider.EventRule
|
||||||
schedulesMapping map[string][]cron.EntryID
|
schedulesMapping map[string][]cron.EntryID
|
||||||
concurrencyGuard chan struct{}
|
concurrencyGuard chan struct{}
|
||||||
}
|
}
|
||||||
|
@ -168,6 +181,15 @@ func (r *eventRulesContainer) removeRuleInternal(name string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for idx := range r.IPDLoginEvents {
|
||||||
|
if r.IPDLoginEvents[idx].Name == name {
|
||||||
|
lastIdx := len(r.IPDLoginEvents) - 1
|
||||||
|
r.IPDLoginEvents[idx] = r.IPDLoginEvents[lastIdx]
|
||||||
|
r.IPDLoginEvents = r.IPDLoginEvents[:lastIdx]
|
||||||
|
eventManagerLog(logger.LevelDebug, "removed rule %q from IDP login events", name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
for idx := range r.Schedules {
|
for idx := range r.Schedules {
|
||||||
if r.Schedules[idx].Name == name {
|
if r.Schedules[idx].Name == name {
|
||||||
if schedules, ok := r.schedulesMapping[name]; ok {
|
if schedules, ok := r.schedulesMapping[name]; ok {
|
||||||
|
@ -213,6 +235,9 @@ func (r *eventRulesContainer) addUpdateRuleInternal(rule dataprovider.EventRule)
|
||||||
case dataprovider.EventTriggerCertificate:
|
case dataprovider.EventTriggerCertificate:
|
||||||
r.CertificateEvents = append(r.CertificateEvents, rule)
|
r.CertificateEvents = append(r.CertificateEvents, rule)
|
||||||
eventManagerLog(logger.LevelDebug, "added rule %q to certificate events", rule.Name)
|
eventManagerLog(logger.LevelDebug, "added rule %q to certificate events", rule.Name)
|
||||||
|
case dataprovider.EventTriggerIDPLogin:
|
||||||
|
r.IPDLoginEvents = append(r.IPDLoginEvents, rule)
|
||||||
|
eventManagerLog(logger.LevelDebug, "added rule %q to IDP login events", rule.Name)
|
||||||
case dataprovider.EventTriggerSchedule:
|
case dataprovider.EventTriggerSchedule:
|
||||||
for _, schedule := range rule.Conditions.Schedules {
|
for _, schedule := range rule.Conditions.Schedules {
|
||||||
cronSpec := schedule.GetCronSpec()
|
cronSpec := schedule.GetCronSpec()
|
||||||
|
@ -253,13 +278,27 @@ func (r *eventRulesContainer) loadRules() {
|
||||||
r.addUpdateRuleInternal(rule)
|
r.addUpdateRuleInternal(rule)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
eventManagerLog(logger.LevelDebug, "event rules updated, fs events: %d, provider events: %d, schedules: %d, ip blocked events: %d, certificate events: %d",
|
eventManagerLog(logger.LevelDebug, "event rules updated, fs events: %d, provider events: %d, schedules: %d, ip blocked events: %d, certificate events: %d, IDP login events: %d",
|
||||||
len(r.FsEvents), len(r.ProviderEvents), len(r.Schedules), len(r.IPBlockedEvents), len(r.CertificateEvents))
|
len(r.FsEvents), len(r.ProviderEvents), len(r.Schedules), len(r.IPBlockedEvents), len(r.CertificateEvents), len(r.IPDLoginEvents))
|
||||||
|
|
||||||
r.setLastLoadTime(modTime)
|
r.setLastLoadTime(modTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *eventRulesContainer) checkProviderEventMatch(conditions dataprovider.EventConditions, params EventParams) bool {
|
func (*eventRulesContainer) checkIPDLoginEventMatch(conditions *dataprovider.EventConditions, params *EventParams) bool {
|
||||||
|
switch conditions.IDPLoginEvent {
|
||||||
|
case dataprovider.IDPLoginUser:
|
||||||
|
if params.Event != IDPLoginUser {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case dataprovider.IDPLoginAdmin:
|
||||||
|
if params.Event != IDPLoginAdmin {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return checkEventConditionPatterns(params.Name, conditions.Options.Names)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*eventRulesContainer) checkProviderEventMatch(conditions *dataprovider.EventConditions, params *EventParams) bool {
|
||||||
if !util.Contains(conditions.ProviderEvents, params.Event) {
|
if !util.Contains(conditions.ProviderEvents, params.Event) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -275,7 +314,7 @@ func (r *eventRulesContainer) checkProviderEventMatch(conditions dataprovider.Ev
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *eventRulesContainer) checkFsEventMatch(conditions dataprovider.EventConditions, params EventParams) bool {
|
func (*eventRulesContainer) checkFsEventMatch(conditions *dataprovider.EventConditions, params *EventParams) bool {
|
||||||
if !util.Contains(conditions.FsEvents, params.Event) {
|
if !util.Contains(conditions.FsEvents, params.Event) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -327,7 +366,7 @@ func (r *eventRulesContainer) handleFsEvent(params EventParams) (bool, error) {
|
||||||
|
|
||||||
var rulesWithSyncActions, rulesAsync []dataprovider.EventRule
|
var rulesWithSyncActions, rulesAsync []dataprovider.EventRule
|
||||||
for _, rule := range r.FsEvents {
|
for _, rule := range r.FsEvents {
|
||||||
if r.checkFsEventMatch(rule.Conditions, params) {
|
if r.checkFsEventMatch(&rule.Conditions, ¶ms) {
|
||||||
if err := rule.CheckActionsConsistency(""); err != nil {
|
if err := rule.CheckActionsConsistency(""); err != nil {
|
||||||
eventManagerLog(logger.LevelWarn, "rule %q skipped: %v, event %q",
|
eventManagerLog(logger.LevelWarn, "rule %q skipped: %v, event %q",
|
||||||
rule.Name, err, params.Event)
|
rule.Name, err, params.Event)
|
||||||
|
@ -361,6 +400,59 @@ func (r *eventRulesContainer) handleFsEvent(params EventParams) (bool, error) {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *eventRulesContainer) handleIDPLoginEvent(params EventParams, customFields *map[string]any) (*dataprovider.User,
|
||||||
|
*dataprovider.Admin, error,
|
||||||
|
) {
|
||||||
|
r.RLock()
|
||||||
|
|
||||||
|
var rulesWithSyncActions, rulesAsync []dataprovider.EventRule
|
||||||
|
for _, rule := range r.IPDLoginEvents {
|
||||||
|
if r.checkIPDLoginEventMatch(&rule.Conditions, ¶ms) {
|
||||||
|
if err := rule.CheckActionsConsistency(""); err != nil {
|
||||||
|
eventManagerLog(logger.LevelWarn, "rule %q skipped: %v, event %q",
|
||||||
|
rule.Name, err, params.Event)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
hasSyncActions := false
|
||||||
|
for _, action := range rule.Actions {
|
||||||
|
if action.Options.ExecuteSync {
|
||||||
|
hasSyncActions = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if hasSyncActions {
|
||||||
|
rulesWithSyncActions = append(rulesWithSyncActions, rule)
|
||||||
|
} else {
|
||||||
|
rulesAsync = append(rulesAsync, rule)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r.RUnlock()
|
||||||
|
|
||||||
|
if len(rulesAsync) == 0 && len(rulesWithSyncActions) == 0 {
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
params.addIDPCustomFields(customFields)
|
||||||
|
if len(rulesWithSyncActions) > 1 {
|
||||||
|
var ruleNames []string
|
||||||
|
for _, r := range rulesWithSyncActions {
|
||||||
|
ruleNames = append(ruleNames, r.Name)
|
||||||
|
}
|
||||||
|
return nil, nil, fmt.Errorf("more than one account check action rules matches: %q", strings.Join(ruleNames, ","))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rulesAsync) > 0 {
|
||||||
|
go executeAsyncRulesActions(rulesAsync, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rulesWithSyncActions) > 0 {
|
||||||
|
return executeIDPAccountCheckRule(rulesWithSyncActions[0], params)
|
||||||
|
}
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
// username is populated for user objects
|
// username is populated for user objects
|
||||||
func (r *eventRulesContainer) handleProviderEvent(params EventParams) {
|
func (r *eventRulesContainer) handleProviderEvent(params EventParams) {
|
||||||
r.RLock()
|
r.RLock()
|
||||||
|
@ -368,7 +460,7 @@ func (r *eventRulesContainer) handleProviderEvent(params EventParams) {
|
||||||
|
|
||||||
var rules []dataprovider.EventRule
|
var rules []dataprovider.EventRule
|
||||||
for _, rule := range r.ProviderEvents {
|
for _, rule := range r.ProviderEvents {
|
||||||
if r.checkProviderEventMatch(rule.Conditions, params) {
|
if r.checkProviderEventMatch(&rule.Conditions, ¶ms) {
|
||||||
if err := rule.CheckActionsConsistency(params.ObjectType); err == nil {
|
if err := rule.CheckActionsConsistency(params.ObjectType); err == nil {
|
||||||
rules = append(rules, rule)
|
rules = append(rules, rule)
|
||||||
} else {
|
} else {
|
||||||
|
@ -452,6 +544,7 @@ type EventParams struct {
|
||||||
IP string
|
IP string
|
||||||
Role string
|
Role string
|
||||||
Timestamp int64
|
Timestamp int64
|
||||||
|
IDPCustomFields *map[string]string
|
||||||
Object plugin.Renderer
|
Object plugin.Renderer
|
||||||
sender string
|
sender string
|
||||||
updateStatusFromError bool
|
updateStatusFromError bool
|
||||||
|
@ -474,10 +567,32 @@ func (p *EventParams) getACopy() *EventParams {
|
||||||
retentionChecks = append(retentionChecks, executedCheck)
|
retentionChecks = append(retentionChecks, executedCheck)
|
||||||
}
|
}
|
||||||
params.retentionChecks = retentionChecks
|
params.retentionChecks = retentionChecks
|
||||||
|
if p.IDPCustomFields != nil {
|
||||||
|
fields := make(map[string]string)
|
||||||
|
for k, v := range *p.IDPCustomFields {
|
||||||
|
fields[k] = v
|
||||||
|
}
|
||||||
|
params.IDPCustomFields = &fields
|
||||||
|
}
|
||||||
|
|
||||||
return ¶ms
|
return ¶ms
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *EventParams) addIDPCustomFields(customFields *map[string]any) {
|
||||||
|
if customFields == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := make(map[string]string)
|
||||||
|
for k, v := range *customFields {
|
||||||
|
switch val := v.(type) {
|
||||||
|
case string:
|
||||||
|
fields[k] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.IDPCustomFields = &fields
|
||||||
|
}
|
||||||
|
|
||||||
// AddError adds a new error to the event params and update the status if needed
|
// AddError adds a new error to the event params and update the status if needed
|
||||||
func (p *EventParams) AddError(err error) {
|
func (p *EventParams) AddError(err error) {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -622,34 +737,41 @@ func (p *EventParams) getRetentionReportsAsMailAttachment() (*mail.File, error)
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *EventParams) getStringReplacements(addObjectData bool) []string {
|
func (*EventParams) getStringReplacement(val string, jsonEscaped bool) string {
|
||||||
|
if jsonEscaped {
|
||||||
|
return util.JSONEscape(val)
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *EventParams) getStringReplacements(addObjectData, jsonEscaped bool) []string {
|
||||||
replacements := []string{
|
replacements := []string{
|
||||||
"{{Name}}", p.Name,
|
"{{Name}}", p.getStringReplacement(p.Name, jsonEscaped),
|
||||||
"{{Event}}", p.Event,
|
"{{Event}}", p.Event,
|
||||||
"{{Status}}", fmt.Sprintf("%d", p.Status),
|
"{{Status}}", fmt.Sprintf("%d", p.Status),
|
||||||
"{{VirtualPath}}", p.VirtualPath,
|
"{{VirtualPath}}", p.getStringReplacement(p.VirtualPath, jsonEscaped),
|
||||||
"{{FsPath}}", p.FsPath,
|
"{{FsPath}}", p.getStringReplacement(p.FsPath, jsonEscaped),
|
||||||
"{{VirtualTargetPath}}", p.VirtualTargetPath,
|
"{{VirtualTargetPath}}", p.getStringReplacement(p.VirtualTargetPath, jsonEscaped),
|
||||||
"{{FsTargetPath}}", p.FsTargetPath,
|
"{{FsTargetPath}}", p.getStringReplacement(p.FsTargetPath, jsonEscaped),
|
||||||
"{{ObjectName}}", p.ObjectName,
|
"{{ObjectName}}", p.getStringReplacement(p.ObjectName, jsonEscaped),
|
||||||
"{{ObjectType}}", p.ObjectType,
|
"{{ObjectType}}", p.ObjectType,
|
||||||
"{{FileSize}}", fmt.Sprintf("%d", p.FileSize),
|
"{{FileSize}}", fmt.Sprintf("%d", p.FileSize),
|
||||||
"{{Elapsed}}", fmt.Sprintf("%d", p.Elapsed),
|
"{{Elapsed}}", fmt.Sprintf("%d", p.Elapsed),
|
||||||
"{{Protocol}}", p.Protocol,
|
"{{Protocol}}", p.Protocol,
|
||||||
"{{IP}}", p.IP,
|
"{{IP}}", p.IP,
|
||||||
"{{Role}}", p.Role,
|
"{{Role}}", p.getStringReplacement(p.Role, jsonEscaped),
|
||||||
"{{Timestamp}}", fmt.Sprintf("%d", p.Timestamp),
|
"{{Timestamp}}", fmt.Sprintf("%d", p.Timestamp),
|
||||||
"{{StatusString}}", p.getStatusString(),
|
"{{StatusString}}", p.getStatusString(),
|
||||||
}
|
}
|
||||||
if p.VirtualPath != "" {
|
if p.VirtualPath != "" {
|
||||||
replacements = append(replacements, "{{VirtualDirPath}}", path.Dir(p.VirtualPath))
|
replacements = append(replacements, "{{VirtualDirPath}}", p.getStringReplacement(path.Dir(p.VirtualPath), jsonEscaped))
|
||||||
}
|
}
|
||||||
if p.VirtualTargetPath != "" {
|
if p.VirtualTargetPath != "" {
|
||||||
replacements = append(replacements, "{{VirtualTargetDirPath}}", path.Dir(p.VirtualTargetPath))
|
replacements = append(replacements, "{{VirtualTargetDirPath}}", p.getStringReplacement(path.Dir(p.VirtualTargetPath), jsonEscaped))
|
||||||
replacements = append(replacements, "{{TargetName}}", path.Base(p.VirtualTargetPath))
|
replacements = append(replacements, "{{TargetName}}", p.getStringReplacement(path.Base(p.VirtualTargetPath), jsonEscaped))
|
||||||
}
|
}
|
||||||
if len(p.errors) > 0 {
|
if len(p.errors) > 0 {
|
||||||
replacements = append(replacements, "{{ErrorString}}", strings.Join(p.errors, ", "))
|
replacements = append(replacements, "{{ErrorString}}", p.getStringReplacement(strings.Join(p.errors, ", "), jsonEscaped))
|
||||||
} else {
|
} else {
|
||||||
replacements = append(replacements, "{{ErrorString}}", "")
|
replacements = append(replacements, "{{ErrorString}}", "")
|
||||||
}
|
}
|
||||||
|
@ -660,6 +782,11 @@ func (p *EventParams) getStringReplacements(addObjectData bool) []string {
|
||||||
replacements[len(replacements)-1] = string(data)
|
replacements[len(replacements)-1] = string(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if p.IDPCustomFields != nil {
|
||||||
|
for k, v := range *p.IDPCustomFields {
|
||||||
|
replacements = append(replacements, fmt.Sprintf("{{IDPField%s}}", k), p.getStringReplacement(v, jsonEscaped))
|
||||||
|
}
|
||||||
|
}
|
||||||
return replacements
|
return replacements
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1060,7 +1187,7 @@ func getHTTPRuleActionEndpoint(c dataprovider.EventActionHTTPConfig, replacer *s
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeHTTPPart(m *multipart.Writer, part dataprovider.HTTPPart, h textproto.MIMEHeader,
|
func writeHTTPPart(m *multipart.Writer, part dataprovider.HTTPPart, h textproto.MIMEHeader,
|
||||||
conn *BaseConnection, replacer *strings.Replacer, params *EventParams,
|
conn *BaseConnection, replacer *strings.Replacer, params *EventParams, addObjectData bool,
|
||||||
) error {
|
) error {
|
||||||
partWriter, err := m.CreatePart(h)
|
partWriter, err := m.CreatePart(h)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1068,7 +1195,14 @@ func writeHTTPPart(m *multipart.Writer, part dataprovider.HTTPPart, h textproto.
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if part.Body != "" {
|
if part.Body != "" {
|
||||||
_, err = partWriter.Write([]byte(replaceWithReplacer(part.Body, replacer)))
|
cType := h.Get("Content-Type")
|
||||||
|
if strings.Contains(strings.ToLower(cType), "application/json") {
|
||||||
|
replacements := params.getStringReplacements(addObjectData, true)
|
||||||
|
jsonReplacer := strings.NewReplacer(replacements...)
|
||||||
|
_, err = partWriter.Write([]byte(replaceWithReplacer(part.Body, jsonReplacer)))
|
||||||
|
} else {
|
||||||
|
_, err = partWriter.Write([]byte(replaceWithReplacer(part.Body, replacer)))
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
eventManagerLog(logger.LevelError, "unable to write part %q, err: %v", part.Name, err)
|
eventManagerLog(logger.LevelError, "unable to write part %q, err: %v", part.Name, err)
|
||||||
return err
|
return err
|
||||||
|
@ -1095,8 +1229,8 @@ func writeHTTPPart(m *multipart.Writer, part dataprovider.HTTPPart, h textproto.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getHTTPRuleActionBody(c dataprovider.EventActionHTTPConfig, replacer *strings.Replacer,
|
func getHTTPRuleActionBody(c *dataprovider.EventActionHTTPConfig, replacer *strings.Replacer,
|
||||||
cancel context.CancelFunc, user dataprovider.User, params *EventParams,
|
cancel context.CancelFunc, user dataprovider.User, params *EventParams, addObjectData bool,
|
||||||
) (io.ReadCloser, string, error) {
|
) (io.ReadCloser, string, error) {
|
||||||
var body io.ReadCloser
|
var body io.ReadCloser
|
||||||
if c.Method == http.MethodGet {
|
if c.Method == http.MethodGet {
|
||||||
|
@ -1110,6 +1244,11 @@ func getHTTPRuleActionBody(c dataprovider.EventActionHTTPConfig, replacer *strin
|
||||||
}
|
}
|
||||||
return io.NopCloser(bytes.NewBuffer(data)), "", nil
|
return io.NopCloser(bytes.NewBuffer(data)), "", nil
|
||||||
}
|
}
|
||||||
|
if c.HasJSONBody() {
|
||||||
|
replacements := params.getStringReplacements(addObjectData, true)
|
||||||
|
jsonReplacer := strings.NewReplacer(replacements...)
|
||||||
|
return io.NopCloser(bytes.NewBufferString(replaceWithReplacer(c.Body, jsonReplacer))), "", nil
|
||||||
|
}
|
||||||
return io.NopCloser(bytes.NewBufferString(replaceWithReplacer(c.Body, replacer))), "", nil
|
return io.NopCloser(bytes.NewBufferString(replaceWithReplacer(c.Body, replacer))), "", nil
|
||||||
}
|
}
|
||||||
if len(c.Parts) > 0 {
|
if len(c.Parts) > 0 {
|
||||||
|
@ -1154,7 +1293,7 @@ func getHTTPRuleActionBody(c dataprovider.EventActionHTTPConfig, replacer *strin
|
||||||
for _, keyVal := range part.Headers {
|
for _, keyVal := range part.Headers {
|
||||||
h.Set(keyVal.Key, replaceWithReplacer(keyVal.Value, replacer))
|
h.Set(keyVal.Key, replaceWithReplacer(keyVal.Value, replacer))
|
||||||
}
|
}
|
||||||
if err := writeHTTPPart(m, part, h, conn, replacer, params); err != nil {
|
if err := writeHTTPPart(m, part, h, conn, replacer, params, addObjectData); err != nil {
|
||||||
cancel()
|
cancel()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1176,7 +1315,7 @@ func executeHTTPRuleAction(c dataprovider.EventActionHTTPConfig, params *EventPa
|
||||||
addObjectData = c.HasObjectData()
|
addObjectData = c.HasObjectData()
|
||||||
}
|
}
|
||||||
|
|
||||||
replacements := params.getStringReplacements(addObjectData)
|
replacements := params.getStringReplacements(addObjectData, false)
|
||||||
replacer := strings.NewReplacer(replacements...)
|
replacer := strings.NewReplacer(replacements...)
|
||||||
endpoint, err := getHTTPRuleActionEndpoint(c, replacer)
|
endpoint, err := getHTTPRuleActionEndpoint(c, replacer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1193,7 +1332,7 @@ func executeHTTPRuleAction(c dataprovider.EventActionHTTPConfig, params *EventPa
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
body, contentType, err := getHTTPRuleActionBody(c, replacer, cancel, user, params)
|
body, contentType, err := getHTTPRuleActionBody(&c, replacer, cancel, user, params, addObjectData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1244,7 +1383,7 @@ func executeCommandRuleAction(c dataprovider.EventActionCommandConfig, params *E
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
replacements := params.getStringReplacements(addObjectData)
|
replacements := params.getStringReplacements(addObjectData, false)
|
||||||
replacer := strings.NewReplacer(replacements...)
|
replacer := strings.NewReplacer(replacements...)
|
||||||
|
|
||||||
args := make([]string, 0, len(c.Args))
|
args := make([]string, 0, len(c.Args))
|
||||||
|
@ -1277,7 +1416,7 @@ func executeEmailRuleAction(c dataprovider.EventActionEmailConfig, params *Event
|
||||||
addObjectData = true
|
addObjectData = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
replacements := params.getStringReplacements(addObjectData)
|
replacements := params.getStringReplacements(addObjectData, false)
|
||||||
replacer := strings.NewReplacer(replacements...)
|
replacer := strings.NewReplacer(replacements...)
|
||||||
body := replaceWithReplacer(c.Body, replacer)
|
body := replaceWithReplacer(c.Body, replacer)
|
||||||
subject := replaceWithReplacer(c.Subject, replacer)
|
subject := replaceWithReplacer(c.Subject, replacer)
|
||||||
|
@ -1825,7 +1964,7 @@ func executeFsRuleAction(c dataprovider.EventActionFilesystemConfig, conditions
|
||||||
params *EventParams,
|
params *EventParams,
|
||||||
) error {
|
) error {
|
||||||
addObjectData := false
|
addObjectData := false
|
||||||
replacements := params.getStringReplacements(addObjectData)
|
replacements := params.getStringReplacements(addObjectData, false)
|
||||||
replacer := strings.NewReplacer(replacements...)
|
replacer := strings.NewReplacer(replacements...)
|
||||||
switch c.Type {
|
switch c.Type {
|
||||||
case dataprovider.FilesystemActionRename:
|
case dataprovider.FilesystemActionRename:
|
||||||
|
@ -2207,6 +2346,71 @@ func executePwdExpirationCheckRuleAction(config dataprovider.EventActionPassword
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func executeAdminCheckAction(c *dataprovider.EventActionIDPAccountCheck, params *EventParams) (*dataprovider.Admin, error) {
|
||||||
|
admin, err := dataprovider.AdminExists(params.Name)
|
||||||
|
exists := err == nil
|
||||||
|
if exists && c.Mode == 1 {
|
||||||
|
return &admin, nil
|
||||||
|
}
|
||||||
|
if err != nil && !errors.Is(err, util.ErrNotFound) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
replacements := params.getStringReplacements(false, true)
|
||||||
|
replacer := strings.NewReplacer(replacements...)
|
||||||
|
data := replaceWithReplacer(c.TemplateAdmin, replacer)
|
||||||
|
|
||||||
|
var newAdmin dataprovider.Admin
|
||||||
|
err = json.Unmarshal([]byte(data), &newAdmin)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if newAdmin.Password == "" {
|
||||||
|
newAdmin.Password = util.GenerateUniqueID()
|
||||||
|
}
|
||||||
|
if exists {
|
||||||
|
eventManagerLog(logger.LevelDebug, "updating admin %q after IDP login", params.Name)
|
||||||
|
err = dataprovider.UpdateAdmin(&newAdmin, dataprovider.ActionExecutorSystem, "", "")
|
||||||
|
} else {
|
||||||
|
eventManagerLog(logger.LevelDebug, "creating admin %q after IDP login", params.Name)
|
||||||
|
err = dataprovider.AddAdmin(&newAdmin, dataprovider.ActionExecutorSystem, "", "")
|
||||||
|
}
|
||||||
|
return &newAdmin, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func executeUserCheckAction(c *dataprovider.EventActionIDPAccountCheck, params *EventParams) (*dataprovider.User, error) {
|
||||||
|
user, err := dataprovider.UserExists(params.Name, "")
|
||||||
|
exists := err == nil
|
||||||
|
if exists && c.Mode == 1 {
|
||||||
|
err = user.LoadAndApplyGroupSettings()
|
||||||
|
return &user, err
|
||||||
|
}
|
||||||
|
if err != nil && !errors.Is(err, util.ErrNotFound) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
replacements := params.getStringReplacements(false, true)
|
||||||
|
replacer := strings.NewReplacer(replacements...)
|
||||||
|
data := replaceWithReplacer(c.TemplateUser, replacer)
|
||||||
|
|
||||||
|
var newUser dataprovider.User
|
||||||
|
err = json.Unmarshal([]byte(data), &newUser)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if exists {
|
||||||
|
eventManagerLog(logger.LevelDebug, "updating user %q after IDP login", params.Name)
|
||||||
|
err = dataprovider.UpdateUser(&newUser, dataprovider.ActionExecutorSystem, "", "")
|
||||||
|
} else {
|
||||||
|
eventManagerLog(logger.LevelDebug, "creating user %q after IDP login", params.Name)
|
||||||
|
err = dataprovider.AddUser(&newUser, dataprovider.ActionExecutorSystem, "", "")
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u, err := dataprovider.GetUserWithGroupSettings(params.Name, "")
|
||||||
|
return &u, err
|
||||||
|
}
|
||||||
|
|
||||||
func executeRuleAction(action dataprovider.BaseEventAction, params *EventParams,
|
func executeRuleAction(action dataprovider.BaseEventAction, params *EventParams,
|
||||||
conditions dataprovider.ConditionOptions,
|
conditions dataprovider.ConditionOptions,
|
||||||
) error {
|
) error {
|
||||||
|
@ -2252,6 +2456,43 @@ func executeRuleAction(action dataprovider.BaseEventAction, params *EventParams,
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func executeIDPAccountCheckRule(rule dataprovider.EventRule, params EventParams) (*dataprovider.User,
|
||||||
|
*dataprovider.Admin, error,
|
||||||
|
) {
|
||||||
|
for _, action := range rule.Actions {
|
||||||
|
if action.Type == dataprovider.ActionTypeIDPAccountCheck {
|
||||||
|
startTime := time.Now()
|
||||||
|
var user *dataprovider.User
|
||||||
|
var admin *dataprovider.Admin
|
||||||
|
var err error
|
||||||
|
var failedActions []string
|
||||||
|
paramsCopy := params.getACopy()
|
||||||
|
|
||||||
|
switch params.Event {
|
||||||
|
case IDPLoginAdmin:
|
||||||
|
admin, err = executeAdminCheckAction(&action.BaseEventAction.Options.IDPConfig, paramsCopy)
|
||||||
|
case IDPLoginUser:
|
||||||
|
user, err = executeUserCheckAction(&action.BaseEventAction.Options.IDPConfig, paramsCopy)
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("unsupported IDP login event: %q", params.Event)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
paramsCopy.AddError(fmt.Errorf("unable to handle %q: %w", params.Event, err))
|
||||||
|
eventManagerLog(logger.LevelError, "unable to handle IDP login event %q, err: %v", params.Event, err)
|
||||||
|
failedActions = append(failedActions, action.Name)
|
||||||
|
} else {
|
||||||
|
eventManagerLog(logger.LevelDebug, "executed action %q for rule %q, elapsed %s",
|
||||||
|
action.Name, rule.Name, time.Since(startTime))
|
||||||
|
}
|
||||||
|
// execute async actions if any, including failure actions
|
||||||
|
go executeRuleAsyncActions(rule, paramsCopy, failedActions)
|
||||||
|
return user, admin, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eventManagerLog(logger.LevelError, "no action executed for IDP login event %q, event rule: %q", params.Event, rule.Name)
|
||||||
|
return nil, nil, errors.New("no action executed")
|
||||||
|
}
|
||||||
|
|
||||||
func executeSyncRulesActions(rules []dataprovider.EventRule, params EventParams) error {
|
func executeSyncRulesActions(rules []dataprovider.EventRule, params EventParams) error {
|
||||||
var errRes error
|
var errRes error
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ import (
|
||||||
|
|
||||||
func TestEventRuleMatch(t *testing.T) {
|
func TestEventRuleMatch(t *testing.T) {
|
||||||
role := "role1"
|
role := "role1"
|
||||||
conditions := dataprovider.EventConditions{
|
conditions := &dataprovider.EventConditions{
|
||||||
ProviderEvents: []string{"add", "update"},
|
ProviderEvents: []string{"add", "update"},
|
||||||
Options: dataprovider.ConditionOptions{
|
Options: dataprovider.ConditionOptions{
|
||||||
Names: []dataprovider.ConditionPattern{
|
Names: []dataprovider.ConditionPattern{
|
||||||
|
@ -62,40 +62,40 @@ func TestEventRuleMatch(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
res := eventManager.checkProviderEventMatch(conditions, EventParams{
|
res := eventManager.checkProviderEventMatch(conditions, &EventParams{
|
||||||
Name: "user1",
|
Name: "user1",
|
||||||
Role: role,
|
Role: role,
|
||||||
Event: "add",
|
Event: "add",
|
||||||
})
|
})
|
||||||
assert.False(t, res)
|
assert.False(t, res)
|
||||||
res = eventManager.checkProviderEventMatch(conditions, EventParams{
|
res = eventManager.checkProviderEventMatch(conditions, &EventParams{
|
||||||
Name: "user2",
|
Name: "user2",
|
||||||
Role: role,
|
Role: role,
|
||||||
Event: "update",
|
Event: "update",
|
||||||
})
|
})
|
||||||
assert.True(t, res)
|
assert.True(t, res)
|
||||||
res = eventManager.checkProviderEventMatch(conditions, EventParams{
|
res = eventManager.checkProviderEventMatch(conditions, &EventParams{
|
||||||
Name: "user2",
|
Name: "user2",
|
||||||
Role: role,
|
Role: role,
|
||||||
Event: "delete",
|
Event: "delete",
|
||||||
})
|
})
|
||||||
assert.False(t, res)
|
assert.False(t, res)
|
||||||
conditions.Options.ProviderObjects = []string{"api_key"}
|
conditions.Options.ProviderObjects = []string{"api_key"}
|
||||||
res = eventManager.checkProviderEventMatch(conditions, EventParams{
|
res = eventManager.checkProviderEventMatch(conditions, &EventParams{
|
||||||
Name: "user2",
|
Name: "user2",
|
||||||
Event: "update",
|
Event: "update",
|
||||||
Role: role,
|
Role: role,
|
||||||
ObjectType: "share",
|
ObjectType: "share",
|
||||||
})
|
})
|
||||||
assert.False(t, res)
|
assert.False(t, res)
|
||||||
res = eventManager.checkProviderEventMatch(conditions, EventParams{
|
res = eventManager.checkProviderEventMatch(conditions, &EventParams{
|
||||||
Name: "user2",
|
Name: "user2",
|
||||||
Event: "update",
|
Event: "update",
|
||||||
Role: role,
|
Role: role,
|
||||||
ObjectType: "api_key",
|
ObjectType: "api_key",
|
||||||
})
|
})
|
||||||
assert.True(t, res)
|
assert.True(t, res)
|
||||||
res = eventManager.checkProviderEventMatch(conditions, EventParams{
|
res = eventManager.checkProviderEventMatch(conditions, &EventParams{
|
||||||
Name: "user2",
|
Name: "user2",
|
||||||
Event: "update",
|
Event: "update",
|
||||||
Role: role + "1",
|
Role: role + "1",
|
||||||
|
@ -103,7 +103,7 @@ func TestEventRuleMatch(t *testing.T) {
|
||||||
})
|
})
|
||||||
assert.False(t, res)
|
assert.False(t, res)
|
||||||
// now test fs events
|
// now test fs events
|
||||||
conditions = dataprovider.EventConditions{
|
conditions = &dataprovider.EventConditions{
|
||||||
FsEvents: []string{operationUpload, operationDownload},
|
FsEvents: []string{operationUpload, operationDownload},
|
||||||
Options: dataprovider.ConditionOptions{
|
Options: dataprovider.ConditionOptions{
|
||||||
Names: []dataprovider.ConditionPattern{
|
Names: []dataprovider.ConditionPattern{
|
||||||
|
@ -138,41 +138,41 @@ func TestEventRuleMatch(t *testing.T) {
|
||||||
ObjectName: "path.txt",
|
ObjectName: "path.txt",
|
||||||
FileSize: 20,
|
FileSize: 20,
|
||||||
}
|
}
|
||||||
res = eventManager.checkFsEventMatch(conditions, params)
|
res = eventManager.checkFsEventMatch(conditions, ¶ms)
|
||||||
assert.False(t, res)
|
assert.False(t, res)
|
||||||
params.Event = operationDownload
|
params.Event = operationDownload
|
||||||
res = eventManager.checkFsEventMatch(conditions, params)
|
res = eventManager.checkFsEventMatch(conditions, ¶ms)
|
||||||
assert.True(t, res)
|
assert.True(t, res)
|
||||||
params.Role = role
|
params.Role = role
|
||||||
res = eventManager.checkFsEventMatch(conditions, params)
|
res = eventManager.checkFsEventMatch(conditions, ¶ms)
|
||||||
assert.False(t, res)
|
assert.False(t, res)
|
||||||
params.Role = ""
|
params.Role = ""
|
||||||
params.Name = "name"
|
params.Name = "name"
|
||||||
res = eventManager.checkFsEventMatch(conditions, params)
|
res = eventManager.checkFsEventMatch(conditions, ¶ms)
|
||||||
assert.False(t, res)
|
assert.False(t, res)
|
||||||
params.Name = "user5"
|
params.Name = "user5"
|
||||||
res = eventManager.checkFsEventMatch(conditions, params)
|
res = eventManager.checkFsEventMatch(conditions, ¶ms)
|
||||||
assert.True(t, res)
|
assert.True(t, res)
|
||||||
params.VirtualPath = "/sub/f.jpg"
|
params.VirtualPath = "/sub/f.jpg"
|
||||||
params.ObjectName = path.Base(params.VirtualPath)
|
params.ObjectName = path.Base(params.VirtualPath)
|
||||||
res = eventManager.checkFsEventMatch(conditions, params)
|
res = eventManager.checkFsEventMatch(conditions, ¶ms)
|
||||||
assert.False(t, res)
|
assert.False(t, res)
|
||||||
params.VirtualPath = "/sub/f.txt"
|
params.VirtualPath = "/sub/f.txt"
|
||||||
params.ObjectName = path.Base(params.VirtualPath)
|
params.ObjectName = path.Base(params.VirtualPath)
|
||||||
res = eventManager.checkFsEventMatch(conditions, params)
|
res = eventManager.checkFsEventMatch(conditions, ¶ms)
|
||||||
assert.True(t, res)
|
assert.True(t, res)
|
||||||
params.Protocol = ProtocolHTTP
|
params.Protocol = ProtocolHTTP
|
||||||
res = eventManager.checkFsEventMatch(conditions, params)
|
res = eventManager.checkFsEventMatch(conditions, ¶ms)
|
||||||
assert.False(t, res)
|
assert.False(t, res)
|
||||||
params.Protocol = ProtocolSFTP
|
params.Protocol = ProtocolSFTP
|
||||||
params.FileSize = 5
|
params.FileSize = 5
|
||||||
res = eventManager.checkFsEventMatch(conditions, params)
|
res = eventManager.checkFsEventMatch(conditions, ¶ms)
|
||||||
assert.False(t, res)
|
assert.False(t, res)
|
||||||
params.FileSize = 50
|
params.FileSize = 50
|
||||||
res = eventManager.checkFsEventMatch(conditions, params)
|
res = eventManager.checkFsEventMatch(conditions, ¶ms)
|
||||||
assert.False(t, res)
|
assert.False(t, res)
|
||||||
params.FileSize = 25
|
params.FileSize = 25
|
||||||
res = eventManager.checkFsEventMatch(conditions, params)
|
res = eventManager.checkFsEventMatch(conditions, ¶ms)
|
||||||
assert.True(t, res)
|
assert.True(t, res)
|
||||||
// bad pattern
|
// bad pattern
|
||||||
conditions.Options.Names = []dataprovider.ConditionPattern{
|
conditions.Options.Names = []dataprovider.ConditionPattern{
|
||||||
|
@ -180,10 +180,10 @@ func TestEventRuleMatch(t *testing.T) {
|
||||||
Pattern: "[-]",
|
Pattern: "[-]",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
res = eventManager.checkFsEventMatch(conditions, params)
|
res = eventManager.checkFsEventMatch(conditions, ¶ms)
|
||||||
assert.False(t, res)
|
assert.False(t, res)
|
||||||
// check fs events with group name filters
|
// check fs events with group name filters
|
||||||
conditions = dataprovider.EventConditions{
|
conditions = &dataprovider.EventConditions{
|
||||||
FsEvents: []string{operationUpload, operationDownload},
|
FsEvents: []string{operationUpload, operationDownload},
|
||||||
Options: dataprovider.ConditionOptions{
|
Options: dataprovider.ConditionOptions{
|
||||||
GroupNames: []dataprovider.ConditionPattern{
|
GroupNames: []dataprovider.ConditionPattern{
|
||||||
|
@ -200,7 +200,7 @@ func TestEventRuleMatch(t *testing.T) {
|
||||||
Name: "user1",
|
Name: "user1",
|
||||||
Event: operationUpload,
|
Event: operationUpload,
|
||||||
}
|
}
|
||||||
res = eventManager.checkFsEventMatch(conditions, params)
|
res = eventManager.checkFsEventMatch(conditions, ¶ms)
|
||||||
assert.False(t, res)
|
assert.False(t, res)
|
||||||
params.Groups = []sdk.GroupMapping{
|
params.Groups = []sdk.GroupMapping{
|
||||||
{
|
{
|
||||||
|
@ -212,7 +212,7 @@ func TestEventRuleMatch(t *testing.T) {
|
||||||
Type: sdk.GroupTypeSecondary,
|
Type: sdk.GroupTypeSecondary,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
res = eventManager.checkFsEventMatch(conditions, params)
|
res = eventManager.checkFsEventMatch(conditions, ¶ms)
|
||||||
assert.False(t, res)
|
assert.False(t, res)
|
||||||
params.Groups = []sdk.GroupMapping{
|
params.Groups = []sdk.GroupMapping{
|
||||||
{
|
{
|
||||||
|
@ -224,7 +224,7 @@ func TestEventRuleMatch(t *testing.T) {
|
||||||
Type: sdk.GroupTypeSecondary,
|
Type: sdk.GroupTypeSecondary,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
res = eventManager.checkFsEventMatch(conditions, params)
|
res = eventManager.checkFsEventMatch(conditions, ¶ms)
|
||||||
assert.True(t, res)
|
assert.True(t, res)
|
||||||
// check user conditions
|
// check user conditions
|
||||||
user := dataprovider.User{}
|
user := dataprovider.User{}
|
||||||
|
@ -269,6 +269,58 @@ func TestEventRuleMatch(t *testing.T) {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
assert.False(t, res)
|
assert.False(t, res)
|
||||||
|
res = eventManager.checkIPDLoginEventMatch(&dataprovider.EventConditions{
|
||||||
|
IDPLoginEvent: 0,
|
||||||
|
}, &EventParams{
|
||||||
|
Event: IDPLoginAdmin,
|
||||||
|
})
|
||||||
|
assert.True(t, res)
|
||||||
|
res = eventManager.checkIPDLoginEventMatch(&dataprovider.EventConditions{
|
||||||
|
IDPLoginEvent: 2,
|
||||||
|
}, &EventParams{
|
||||||
|
Event: IDPLoginAdmin,
|
||||||
|
})
|
||||||
|
assert.True(t, res)
|
||||||
|
res = eventManager.checkIPDLoginEventMatch(&dataprovider.EventConditions{
|
||||||
|
IDPLoginEvent: 1,
|
||||||
|
}, &EventParams{
|
||||||
|
Event: IDPLoginAdmin,
|
||||||
|
})
|
||||||
|
assert.False(t, res)
|
||||||
|
res = eventManager.checkIPDLoginEventMatch(&dataprovider.EventConditions{
|
||||||
|
IDPLoginEvent: 1,
|
||||||
|
}, &EventParams{
|
||||||
|
Event: IDPLoginUser,
|
||||||
|
})
|
||||||
|
assert.True(t, res)
|
||||||
|
res = eventManager.checkIPDLoginEventMatch(&dataprovider.EventConditions{
|
||||||
|
IDPLoginEvent: 1,
|
||||||
|
}, &EventParams{
|
||||||
|
Name: "user",
|
||||||
|
Event: IDPLoginUser,
|
||||||
|
})
|
||||||
|
assert.True(t, res)
|
||||||
|
res = eventManager.checkIPDLoginEventMatch(&dataprovider.EventConditions{
|
||||||
|
IDPLoginEvent: 1,
|
||||||
|
Options: dataprovider.ConditionOptions{
|
||||||
|
Names: []dataprovider.ConditionPattern{
|
||||||
|
{
|
||||||
|
Pattern: "abc",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, &EventParams{
|
||||||
|
Name: "user",
|
||||||
|
Event: IDPLoginUser,
|
||||||
|
})
|
||||||
|
assert.False(t, res)
|
||||||
|
res = eventManager.checkIPDLoginEventMatch(&dataprovider.EventConditions{
|
||||||
|
IDPLoginEvent: 2,
|
||||||
|
}, &EventParams{
|
||||||
|
Name: "user",
|
||||||
|
Event: IDPLoginUser,
|
||||||
|
})
|
||||||
|
assert.False(t, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDoubleStarMatching(t *testing.T) {
|
func TestDoubleStarMatching(t *testing.T) {
|
||||||
|
@ -453,6 +505,10 @@ func TestEventManagerErrors(t *testing.T) {
|
||||||
err = executePwdExpirationCheckRuleAction(dataprovider.EventActionPasswordExpiration{},
|
err = executePwdExpirationCheckRuleAction(dataprovider.EventActionPasswordExpiration{},
|
||||||
dataprovider.ConditionOptions{}, &EventParams{})
|
dataprovider.ConditionOptions{}, &EventParams{})
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
_, err = executeAdminCheckAction(&dataprovider.EventActionIDPAccountCheck{}, &EventParams{})
|
||||||
|
assert.Error(t, err)
|
||||||
|
_, err = executeUserCheckAction(&dataprovider.EventActionIDPAccountCheck{}, &EventParams{})
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
groupName := "agroup"
|
groupName := "agroup"
|
||||||
err = executeQuotaResetForUser(&dataprovider.User{
|
err = executeQuotaResetForUser(&dataprovider.User{
|
||||||
|
@ -545,7 +601,7 @@ func TestEventManagerErrors(t *testing.T) {
|
||||||
}}, dataprovider.EventActionPasswordExpiration{})
|
}}, dataprovider.EventActionPasswordExpiration{})
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
_, _, err = getHTTPRuleActionBody(dataprovider.EventActionHTTPConfig{
|
_, _, err = getHTTPRuleActionBody(&dataprovider.EventActionHTTPConfig{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
Parts: []dataprovider.HTTPPart{
|
Parts: []dataprovider.HTTPPart{
|
||||||
{
|
{
|
||||||
|
@ -562,7 +618,7 @@ func TestEventManagerErrors(t *testing.T) {
|
||||||
Type: sdk.GroupTypePrimary,
|
Type: sdk.GroupTypePrimary,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, &EventParams{})
|
}, &EventParams{}, false)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
dataRetentionAction := dataprovider.BaseEventAction{
|
dataRetentionAction := dataprovider.BaseEventAction{
|
||||||
|
@ -1181,11 +1237,17 @@ func TestEventRuleActions(t *testing.T) {
|
||||||
assert.Contains(t, err.Error(), "no folder quota reset executed")
|
assert.Contains(t, err.Error(), "no folder quota reset executed")
|
||||||
}
|
}
|
||||||
|
|
||||||
body, _, err := getHTTPRuleActionBody(dataprovider.EventActionHTTPConfig{
|
body, _, err := getHTTPRuleActionBody(&dataprovider.EventActionHTTPConfig{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
}, nil, nil, dataprovider.User{}, &EventParams{})
|
}, nil, nil, dataprovider.User{}, &EventParams{}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Nil(t, body)
|
assert.Nil(t, body)
|
||||||
|
body, _, err = getHTTPRuleActionBody(&dataprovider.EventActionHTTPConfig{
|
||||||
|
Method: http.MethodPost,
|
||||||
|
Body: "test body",
|
||||||
|
}, nil, nil, dataprovider.User{}, &EventParams{}, false)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, body)
|
||||||
|
|
||||||
err = os.RemoveAll(folder1.MappedPath)
|
err = os.RemoveAll(folder1.MappedPath)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -1195,6 +1257,99 @@ func TestEventRuleActions(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIDPAccountCheckRule(t *testing.T) {
|
||||||
|
_, _, err := executeIDPAccountCheckRule(dataprovider.EventRule{}, EventParams{})
|
||||||
|
if assert.Error(t, err) {
|
||||||
|
assert.Contains(t, err.Error(), "no action executed")
|
||||||
|
}
|
||||||
|
_, _, err = executeIDPAccountCheckRule(dataprovider.EventRule{
|
||||||
|
Actions: []dataprovider.EventAction{
|
||||||
|
{
|
||||||
|
BaseEventAction: dataprovider.BaseEventAction{
|
||||||
|
Name: "n",
|
||||||
|
Type: dataprovider.ActionTypeIDPAccountCheck,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, EventParams{Event: "invalid"})
|
||||||
|
if assert.Error(t, err) {
|
||||||
|
assert.Contains(t, err.Error(), "unsupported IDP login event")
|
||||||
|
}
|
||||||
|
// invalid json
|
||||||
|
_, err = executeAdminCheckAction(&dataprovider.EventActionIDPAccountCheck{TemplateAdmin: "{"}, &EventParams{Name: "missing admin"})
|
||||||
|
assert.Error(t, err)
|
||||||
|
_, err = executeUserCheckAction(&dataprovider.EventActionIDPAccountCheck{TemplateUser: "["}, &EventParams{Name: "missing user"})
|
||||||
|
assert.Error(t, err)
|
||||||
|
_, err = executeUserCheckAction(&dataprovider.EventActionIDPAccountCheck{TemplateUser: "{}"}, &EventParams{Name: "invalid user template"})
|
||||||
|
assert.ErrorIs(t, err, util.ErrValidation)
|
||||||
|
username := "u"
|
||||||
|
c := &dataprovider.EventActionIDPAccountCheck{
|
||||||
|
Mode: 1,
|
||||||
|
TemplateUser: `{"username":"` + username + `","status":1,"home_dir":"` + util.JSONEscape(filepath.Join(os.TempDir())) + `","permissions":{"/":["*"]}}`,
|
||||||
|
}
|
||||||
|
params := &EventParams{
|
||||||
|
Name: username,
|
||||||
|
Event: IDPLoginUser,
|
||||||
|
}
|
||||||
|
user, err := executeUserCheckAction(c, params)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, username, user.Username)
|
||||||
|
assert.Equal(t, 1, user.Status)
|
||||||
|
user.Status = 0
|
||||||
|
err = dataprovider.UpdateUser(user, "", "", "")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
// the user is not changed
|
||||||
|
user, err = executeUserCheckAction(c, params)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, username, user.Username)
|
||||||
|
assert.Equal(t, 0, user.Status)
|
||||||
|
// change the mode, the user is now updated
|
||||||
|
c.Mode = 0
|
||||||
|
user, err = executeUserCheckAction(c, params)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, username, user.Username)
|
||||||
|
assert.Equal(t, 1, user.Status)
|
||||||
|
|
||||||
|
err = dataprovider.DeleteUser(username, "", "", "")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
// check rule consistency
|
||||||
|
r := dataprovider.EventRule{
|
||||||
|
Actions: []dataprovider.EventAction{
|
||||||
|
{
|
||||||
|
BaseEventAction: dataprovider.BaseEventAction{
|
||||||
|
Type: dataprovider.ActionTypeIDPAccountCheck,
|
||||||
|
},
|
||||||
|
Order: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err = r.CheckActionsConsistency("")
|
||||||
|
if assert.Error(t, err) {
|
||||||
|
assert.Contains(t, err.Error(), "IDP account check action is only supported for IDP login trigger")
|
||||||
|
}
|
||||||
|
r.Trigger = dataprovider.EventTriggerIDPLogin
|
||||||
|
err = r.CheckActionsConsistency("")
|
||||||
|
if assert.Error(t, err) {
|
||||||
|
assert.Contains(t, err.Error(), "IDP account check must be a sync action")
|
||||||
|
}
|
||||||
|
r.Actions[0].Options.ExecuteSync = true
|
||||||
|
err = r.CheckActionsConsistency("")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
r.Actions = append(r.Actions, dataprovider.EventAction{
|
||||||
|
BaseEventAction: dataprovider.BaseEventAction{
|
||||||
|
Type: dataprovider.ActionTypeCommand,
|
||||||
|
},
|
||||||
|
Options: dataprovider.EventActionOptions{
|
||||||
|
ExecuteSync: true,
|
||||||
|
},
|
||||||
|
Order: 2,
|
||||||
|
})
|
||||||
|
err = r.CheckActionsConsistency("")
|
||||||
|
if assert.Error(t, err) {
|
||||||
|
assert.Contains(t, err.Error(), "IDP account check must be the only sync action")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestUserExpirationCheck(t *testing.T) {
|
func TestUserExpirationCheck(t *testing.T) {
|
||||||
username := "test_user_expiration_check"
|
username := "test_user_expiration_check"
|
||||||
user := dataprovider.User{
|
user := dataprovider.User{
|
||||||
|
@ -1778,6 +1933,22 @@ func TestEventParamsCopy(t *testing.T) {
|
||||||
assert.Equal(t, "a_copy", paramsCopy.retentionChecks[0].ActionName)
|
assert.Equal(t, "a_copy", paramsCopy.retentionChecks[0].ActionName)
|
||||||
assert.Equal(t, "p_copy", paramsCopy.retentionChecks[0].Results[0].Path)
|
assert.Equal(t, "p_copy", paramsCopy.retentionChecks[0].Results[0].Path)
|
||||||
assert.Equal(t, 2, paramsCopy.retentionChecks[0].Results[0].Retention)
|
assert.Equal(t, 2, paramsCopy.retentionChecks[0].Results[0].Retention)
|
||||||
|
assert.Nil(t, params.IDPCustomFields)
|
||||||
|
params.addIDPCustomFields(nil)
|
||||||
|
assert.Nil(t, params.IDPCustomFields)
|
||||||
|
params.IDPCustomFields = &map[string]string{
|
||||||
|
"field1": "val1",
|
||||||
|
}
|
||||||
|
paramsCopy = params.getACopy()
|
||||||
|
for k, v := range *paramsCopy.IDPCustomFields {
|
||||||
|
assert.Equal(t, "field1", k)
|
||||||
|
assert.Equal(t, "val1", v)
|
||||||
|
}
|
||||||
|
assert.Equal(t, params.IDPCustomFields, paramsCopy.IDPCustomFields)
|
||||||
|
paramsCopy.addIDPCustomFields(&map[string]any{
|
||||||
|
"field2": "val2",
|
||||||
|
})
|
||||||
|
assert.NotEqual(t, params.IDPCustomFields, paramsCopy.IDPCustomFields)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEventParamsStatusFromError(t *testing.T) {
|
func TestEventParamsStatusFromError(t *testing.T) {
|
||||||
|
@ -1810,14 +1981,14 @@ func TestWriteHTTPPartsError(t *testing.T) {
|
||||||
errTest: io.ErrShortWrite,
|
errTest: io.ErrShortWrite,
|
||||||
})
|
})
|
||||||
|
|
||||||
err := writeHTTPPart(m, dataprovider.HTTPPart{}, nil, nil, nil, &EventParams{})
|
err := writeHTTPPart(m, dataprovider.HTTPPart{}, nil, nil, nil, &EventParams{}, false)
|
||||||
assert.ErrorIs(t, err, io.ErrShortWrite)
|
assert.ErrorIs(t, err, io.ErrShortWrite)
|
||||||
|
|
||||||
body := "test body"
|
body := "test body"
|
||||||
m = multipart.NewWriter(&testWriter{sentinel: body})
|
m = multipart.NewWriter(&testWriter{sentinel: body})
|
||||||
err = writeHTTPPart(m, dataprovider.HTTPPart{
|
err = writeHTTPPart(m, dataprovider.HTTPPart{
|
||||||
Body: body,
|
Body: body,
|
||||||
}, nil, nil, nil, &EventParams{})
|
}, nil, nil, nil, &EventParams{}, false)
|
||||||
assert.ErrorIs(t, err, io.ErrUnexpectedEOF)
|
assert.ErrorIs(t, err, io.ErrUnexpectedEOF)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6033,6 +6033,286 @@ func TestEventRuleRenameEvent(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEventRuleIDPLogin(t *testing.T) {
|
||||||
|
smtpCfg := smtp.Config{
|
||||||
|
Host: "127.0.0.1",
|
||||||
|
Port: 2525,
|
||||||
|
From: "notify@example.com",
|
||||||
|
TemplatesPath: "templates",
|
||||||
|
}
|
||||||
|
err := smtpCfg.Initialize(configDir, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
lastReceivedEmail.reset()
|
||||||
|
|
||||||
|
username := `test_"idp_"login`
|
||||||
|
custom1 := `cust"oa"1`
|
||||||
|
u := map[string]any{
|
||||||
|
"username": "{{Name}}",
|
||||||
|
"status": 1,
|
||||||
|
"home_dir": filepath.Join(os.TempDir(), "{{IDPFieldcustom1}}"),
|
||||||
|
"permissions": map[string][]string{
|
||||||
|
"/": {dataprovider.PermAny},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
userTmpl, err := json.Marshal(u)
|
||||||
|
require.NoError(t, err)
|
||||||
|
a := map[string]any{
|
||||||
|
"username": "{{Name}}",
|
||||||
|
"status": 1,
|
||||||
|
"permissions": []string{dataprovider.PermAdminAny},
|
||||||
|
}
|
||||||
|
adminTmpl, err := json.Marshal(a)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
a1 := dataprovider.BaseEventAction{
|
||||||
|
Name: "a1",
|
||||||
|
Type: dataprovider.ActionTypeIDPAccountCheck,
|
||||||
|
Options: dataprovider.BaseEventActionOptions{
|
||||||
|
IDPConfig: dataprovider.EventActionIDPAccountCheck{
|
||||||
|
Mode: 1, // create if not exists
|
||||||
|
TemplateUser: string(userTmpl),
|
||||||
|
TemplateAdmin: string(adminTmpl),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
action1, _, err := httpdtest.AddEventAction(a1, http.StatusCreated)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
a2 := dataprovider.BaseEventAction{
|
||||||
|
Name: "a2",
|
||||||
|
Type: dataprovider.ActionTypeEmail,
|
||||||
|
Options: dataprovider.BaseEventActionOptions{
|
||||||
|
EmailConfig: dataprovider.EventActionEmailConfig{
|
||||||
|
Recipients: []string{"test@example.com"},
|
||||||
|
Subject: `"{{Event}} {{StatusString}}"`,
|
||||||
|
Body: "{{Name}} Custom field: {{IDPFieldcustom1}}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
action2, _, err := httpdtest.AddEventAction(a2, http.StatusCreated)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
r1 := dataprovider.EventRule{
|
||||||
|
Name: "test rule IDP login",
|
||||||
|
Status: 1,
|
||||||
|
Trigger: dataprovider.EventTriggerIDPLogin,
|
||||||
|
Conditions: dataprovider.EventConditions{
|
||||||
|
IDPLoginEvent: dataprovider.IDPLoginUser,
|
||||||
|
},
|
||||||
|
Actions: []dataprovider.EventAction{
|
||||||
|
{
|
||||||
|
BaseEventAction: dataprovider.BaseEventAction{
|
||||||
|
Name: action1.Name, // the rule is not sync and will be skipped
|
||||||
|
},
|
||||||
|
Order: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BaseEventAction: dataprovider.BaseEventAction{
|
||||||
|
Name: action2.Name,
|
||||||
|
},
|
||||||
|
Order: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
rule1, resp, err := httpdtest.AddEventRule(r1, http.StatusCreated)
|
||||||
|
assert.NoError(t, err, string(resp))
|
||||||
|
|
||||||
|
customFields := map[string]any{
|
||||||
|
"custom1": custom1,
|
||||||
|
}
|
||||||
|
user, admin, err := common.HandleIDPLoginEvent(common.EventParams{
|
||||||
|
Name: username,
|
||||||
|
Event: common.IDPLoginUser,
|
||||||
|
Status: 1,
|
||||||
|
}, &customFields)
|
||||||
|
assert.Nil(t, user)
|
||||||
|
assert.Nil(t, admin)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
rule1.Actions[0].Options.ExecuteSync = true
|
||||||
|
rule1, resp, err = httpdtest.UpdateEventRule(rule1, http.StatusOK)
|
||||||
|
assert.NoError(t, err, string(resp))
|
||||||
|
user, admin, err = common.HandleIDPLoginEvent(common.EventParams{
|
||||||
|
Name: username,
|
||||||
|
Event: common.IDPLoginUser,
|
||||||
|
Status: 1,
|
||||||
|
}, &customFields)
|
||||||
|
if assert.NotNil(t, user) {
|
||||||
|
assert.Equal(t, filepath.Join(os.TempDir(), custom1), user.GetHomeDir())
|
||||||
|
_, err = httpdtest.RemoveUser(*user, http.StatusOK)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
assert.Nil(t, admin)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Eventually(t, func() bool {
|
||||||
|
return lastReceivedEmail.get().From != ""
|
||||||
|
}, 3000*time.Millisecond, 100*time.Millisecond)
|
||||||
|
email := lastReceivedEmail.get()
|
||||||
|
assert.Len(t, email.To, 1)
|
||||||
|
assert.True(t, util.Contains(email.To, "test@example.com"))
|
||||||
|
assert.Contains(t, email.Data, fmt.Sprintf(`Subject: "%s OK"`, common.IDPLoginUser))
|
||||||
|
assert.Contains(t, email.Data, username)
|
||||||
|
assert.Contains(t, email.Data, custom1)
|
||||||
|
|
||||||
|
user, admin, err = common.HandleIDPLoginEvent(common.EventParams{
|
||||||
|
Name: username,
|
||||||
|
Event: common.IDPLoginAdmin,
|
||||||
|
Status: 1,
|
||||||
|
}, &customFields)
|
||||||
|
assert.Nil(t, user)
|
||||||
|
assert.Nil(t, admin)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
rule1.Conditions.IDPLoginEvent = dataprovider.IDPLoginAny
|
||||||
|
rule1.Actions = []dataprovider.EventAction{
|
||||||
|
{
|
||||||
|
BaseEventAction: dataprovider.BaseEventAction{
|
||||||
|
Name: action1.Name,
|
||||||
|
},
|
||||||
|
Options: dataprovider.EventActionOptions{
|
||||||
|
ExecuteSync: true,
|
||||||
|
},
|
||||||
|
Order: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
rule1, _, err = httpdtest.UpdateEventRule(rule1, http.StatusOK)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
r2 := dataprovider.EventRule{
|
||||||
|
Name: "test email on IDP login",
|
||||||
|
Status: 1,
|
||||||
|
Trigger: dataprovider.EventTriggerIDPLogin,
|
||||||
|
Conditions: dataprovider.EventConditions{
|
||||||
|
IDPLoginEvent: dataprovider.IDPLoginAdmin,
|
||||||
|
},
|
||||||
|
Actions: []dataprovider.EventAction{
|
||||||
|
{
|
||||||
|
BaseEventAction: dataprovider.BaseEventAction{
|
||||||
|
Name: action2.Name,
|
||||||
|
},
|
||||||
|
Order: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
rule2, resp, err := httpdtest.AddEventRule(r2, http.StatusCreated)
|
||||||
|
assert.NoError(t, err, string(resp))
|
||||||
|
|
||||||
|
lastReceivedEmail.reset()
|
||||||
|
user, admin, err = common.HandleIDPLoginEvent(common.EventParams{
|
||||||
|
Name: username,
|
||||||
|
Event: common.IDPLoginAdmin,
|
||||||
|
Status: 1,
|
||||||
|
}, &customFields)
|
||||||
|
assert.Nil(t, user)
|
||||||
|
if assert.NotNil(t, admin) {
|
||||||
|
assert.Equal(t, 1, admin.Status)
|
||||||
|
}
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Eventually(t, func() bool {
|
||||||
|
return lastReceivedEmail.get().From != ""
|
||||||
|
}, 3000*time.Millisecond, 100*time.Millisecond)
|
||||||
|
email = lastReceivedEmail.get()
|
||||||
|
assert.Len(t, email.To, 1)
|
||||||
|
assert.True(t, util.Contains(email.To, "test@example.com"))
|
||||||
|
assert.Contains(t, email.Data, fmt.Sprintf(`Subject: "%s OK"`, common.IDPLoginAdmin))
|
||||||
|
assert.Contains(t, email.Data, username)
|
||||||
|
assert.Contains(t, email.Data, custom1)
|
||||||
|
admin.Status = 0
|
||||||
|
_, _, err = httpdtest.UpdateAdmin(*admin, http.StatusOK)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
user, admin, err = common.HandleIDPLoginEvent(common.EventParams{
|
||||||
|
Name: username,
|
||||||
|
Event: common.IDPLoginAdmin,
|
||||||
|
Status: 1,
|
||||||
|
}, &customFields)
|
||||||
|
assert.Nil(t, user)
|
||||||
|
if assert.NotNil(t, admin) {
|
||||||
|
assert.Equal(t, 0, admin.Status)
|
||||||
|
}
|
||||||
|
assert.NoError(t, err)
|
||||||
|
action1.Options.IDPConfig.Mode = 0
|
||||||
|
action1, _, err = httpdtest.UpdateEventAction(action1, http.StatusOK)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
user, admin, err = common.HandleIDPLoginEvent(common.EventParams{
|
||||||
|
Name: username,
|
||||||
|
Event: common.IDPLoginAdmin,
|
||||||
|
Status: 1,
|
||||||
|
}, &customFields)
|
||||||
|
assert.Nil(t, user)
|
||||||
|
if assert.NotNil(t, admin) {
|
||||||
|
assert.Equal(t, 1, admin.Status)
|
||||||
|
}
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = httpdtest.RemoveAdmin(*admin, http.StatusOK)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
r3 := dataprovider.EventRule{
|
||||||
|
Name: "test rule2 IDP login",
|
||||||
|
Status: 1,
|
||||||
|
Trigger: dataprovider.EventTriggerIDPLogin,
|
||||||
|
Conditions: dataprovider.EventConditions{
|
||||||
|
IDPLoginEvent: dataprovider.IDPLoginAny,
|
||||||
|
},
|
||||||
|
Actions: []dataprovider.EventAction{
|
||||||
|
{
|
||||||
|
BaseEventAction: dataprovider.BaseEventAction{
|
||||||
|
Name: action1.Name,
|
||||||
|
},
|
||||||
|
Order: 1,
|
||||||
|
Options: dataprovider.EventActionOptions{
|
||||||
|
ExecuteSync: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
rule3, resp, err := httpdtest.AddEventRule(r3, http.StatusCreated)
|
||||||
|
assert.NoError(t, err, string(resp))
|
||||||
|
user, admin, err = common.HandleIDPLoginEvent(common.EventParams{
|
||||||
|
Name: username,
|
||||||
|
Event: common.IDPLoginAdmin,
|
||||||
|
Status: 1,
|
||||||
|
}, &customFields)
|
||||||
|
assert.Nil(t, user)
|
||||||
|
assert.Nil(t, admin)
|
||||||
|
if assert.Error(t, err) {
|
||||||
|
assert.Contains(t, err.Error(), "more than one account check action rules matches")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = httpdtest.RemoveEventRule(rule3, http.StatusOK)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
action1.Options.IDPConfig.TemplateAdmin = `{}`
|
||||||
|
action1, _, err = httpdtest.UpdateEventAction(action1, http.StatusOK)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, _, err = common.HandleIDPLoginEvent(common.EventParams{
|
||||||
|
Name: username,
|
||||||
|
Event: common.IDPLoginAdmin,
|
||||||
|
Status: 1,
|
||||||
|
}, &customFields)
|
||||||
|
assert.ErrorIs(t, err, util.ErrValidation)
|
||||||
|
|
||||||
|
_, err = httpdtest.RemoveEventRule(rule1, http.StatusOK)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
user, admin, err = common.HandleIDPLoginEvent(common.EventParams{
|
||||||
|
Name: username,
|
||||||
|
Event: common.IDPLoginAdmin,
|
||||||
|
Status: 1,
|
||||||
|
}, &customFields)
|
||||||
|
assert.Nil(t, user)
|
||||||
|
assert.Nil(t, admin)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = httpdtest.RemoveEventRule(rule2, http.StatusOK)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = httpdtest.RemoveEventAction(action1, http.StatusOK)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = httpdtest.RemoveEventAction(action2, http.StatusOK)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
smtpCfg = smtp.Config{}
|
||||||
|
err = smtpCfg.Initialize(configDir, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestEventRuleCertificate(t *testing.T) {
|
func TestEventRuleCertificate(t *testing.T) {
|
||||||
smtpCfg := smtp.Config{
|
smtpCfg := smtp.Config{
|
||||||
Host: "127.0.0.1",
|
Host: "127.0.0.1",
|
||||||
|
|
|
@ -729,7 +729,7 @@ func (p *BoltProvider) updateUser(user *User) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) deleteUser(user User, softDelete bool) error {
|
func (p *BoltProvider) deleteUser(user User, _ bool) error {
|
||||||
return p.dbHandle.Update(func(tx *bolt.Tx) error {
|
return p.dbHandle.Update(func(tx *bolt.Tx) error {
|
||||||
bucket, err := p.getUsersBucket(tx)
|
bucket, err := p.getUsersBucket(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1031,7 +1031,7 @@ func (p *BoltProvider) dumpFolders() ([]vfs.BaseVirtualFolder, error) {
|
||||||
return folders, err
|
return folders, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) getFolders(limit, offset int, order string, minimal bool) ([]vfs.BaseVirtualFolder, error) {
|
func (p *BoltProvider) getFolders(limit, offset int, order string, _ bool) ([]vfs.BaseVirtualFolder, error) {
|
||||||
folders := make([]vfs.BaseVirtualFolder, 0, limit)
|
folders := make([]vfs.BaseVirtualFolder, 0, limit)
|
||||||
var err error
|
var err error
|
||||||
if limit <= 0 {
|
if limit <= 0 {
|
||||||
|
@ -1279,7 +1279,7 @@ func (p *BoltProvider) getUsedFolderQuota(name string) (int, int64, error) {
|
||||||
return folder.UsedQuotaFiles, folder.UsedQuotaSize, err
|
return folder.UsedQuotaFiles, folder.UsedQuotaSize, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) getGroups(limit, offset int, order string, minimal bool) ([]Group, error) {
|
func (p *BoltProvider) getGroups(limit, offset int, order string, _ bool) ([]Group, error) {
|
||||||
groups := make([]Group, 0, limit)
|
groups := make([]Group, 0, limit)
|
||||||
var err error
|
var err error
|
||||||
if limit <= 0 {
|
if limit <= 0 {
|
||||||
|
@ -2001,75 +2001,75 @@ func (p *BoltProvider) updateShareLastUse(shareID string, numTokens int) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) getDefenderHosts(from int64, limit int) ([]DefenderEntry, error) {
|
func (p *BoltProvider) getDefenderHosts(_ int64, _ int) ([]DefenderEntry, error) {
|
||||||
return nil, ErrNotImplemented
|
return nil, ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) getDefenderHostByIP(ip string, from int64) (DefenderEntry, error) {
|
func (p *BoltProvider) getDefenderHostByIP(_ string, _ int64) (DefenderEntry, error) {
|
||||||
return DefenderEntry{}, ErrNotImplemented
|
return DefenderEntry{}, ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) isDefenderHostBanned(ip string) (DefenderEntry, error) {
|
func (p *BoltProvider) isDefenderHostBanned(_ string) (DefenderEntry, error) {
|
||||||
return DefenderEntry{}, ErrNotImplemented
|
return DefenderEntry{}, ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) updateDefenderBanTime(ip string, minutes int) error {
|
func (p *BoltProvider) updateDefenderBanTime(_ string, _ int) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) deleteDefenderHost(ip string) error {
|
func (p *BoltProvider) deleteDefenderHost(_ string) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) addDefenderEvent(ip string, score int) error {
|
func (p *BoltProvider) addDefenderEvent(_ string, _ int) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) setDefenderBanTime(ip string, banTime int64) error {
|
func (p *BoltProvider) setDefenderBanTime(_ string, _ int64) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) cleanupDefender(from int64) error {
|
func (p *BoltProvider) cleanupDefender(_ int64) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) addActiveTransfer(transfer ActiveTransfer) error {
|
func (p *BoltProvider) addActiveTransfer(_ ActiveTransfer) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) updateActiveTransferSizes(ulSize, dlSize, transferID int64, connectionID string) error {
|
func (p *BoltProvider) updateActiveTransferSizes(_, _, _ int64, _ string) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) removeActiveTransfer(transferID int64, connectionID string) error {
|
func (p *BoltProvider) removeActiveTransfer(_ int64, _ string) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) cleanupActiveTransfers(before time.Time) error {
|
func (p *BoltProvider) cleanupActiveTransfers(_ time.Time) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) getActiveTransfers(from time.Time) ([]ActiveTransfer, error) {
|
func (p *BoltProvider) getActiveTransfers(_ time.Time) ([]ActiveTransfer, error) {
|
||||||
return nil, ErrNotImplemented
|
return nil, ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) addSharedSession(session Session) error {
|
func (p *BoltProvider) addSharedSession(_ Session) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) deleteSharedSession(key string) error {
|
func (p *BoltProvider) deleteSharedSession(_ string) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) getSharedSession(key string) (Session, error) {
|
func (p *BoltProvider) getSharedSession(_ string) (Session, error) {
|
||||||
return Session{}, ErrNotImplemented
|
return Session{}, ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) cleanupSharedSessions(sessionType SessionType, before int64) error {
|
func (p *BoltProvider) cleanupSharedSessions(_ SessionType, _ int64) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) getEventActions(limit, offset int, order string, minimal bool) ([]BaseEventAction, error) {
|
func (p *BoltProvider) getEventActions(limit, offset int, order string, _ bool) ([]BaseEventAction, error) {
|
||||||
if limit <= 0 {
|
if limit <= 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -2508,7 +2508,7 @@ func (p *BoltProvider) updateEventRule(rule *EventRule) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) deleteEventRule(rule EventRule, softDelete bool) error {
|
func (p *BoltProvider) deleteEventRule(rule EventRule, _ bool) error {
|
||||||
return p.dbHandle.Update(func(tx *bolt.Tx) error {
|
return p.dbHandle.Update(func(tx *bolt.Tx) error {
|
||||||
bucket, err := p.getRulesBucket(tx)
|
bucket, err := p.getRulesBucket(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -2537,19 +2537,19 @@ func (p *BoltProvider) deleteEventRule(rule EventRule, softDelete bool) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*BoltProvider) getTaskByName(name string) (Task, error) {
|
func (*BoltProvider) getTaskByName(_ string) (Task, error) {
|
||||||
return Task{}, ErrNotImplemented
|
return Task{}, ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*BoltProvider) addTask(name string) error {
|
func (*BoltProvider) addTask(_ string) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*BoltProvider) updateTask(name string, version int64) error {
|
func (*BoltProvider) updateTask(_ string, _ int64) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*BoltProvider) updateTaskTimestamp(name string) error {
|
func (*BoltProvider) updateTaskTimestamp(_ string) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2557,7 +2557,7 @@ func (*BoltProvider) addNode() error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*BoltProvider) getNodeByName(name string) (Node, error) {
|
func (*BoltProvider) getNodeByName(_ string) (Node, error) {
|
||||||
return Node{}, ErrNotImplemented
|
return Node{}, ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2683,7 +2683,7 @@ func (p *BoltProvider) deleteRole(role Role) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) getRoles(limit int, offset int, order string, minimal bool) ([]Role, error) {
|
func (p *BoltProvider) getRoles(limit int, offset int, order string, _ bool) ([]Role, error) {
|
||||||
roles := make([]Role, 0, limit)
|
roles := make([]Role, 0, limit)
|
||||||
if limit <= 0 {
|
if limit <= 0 {
|
||||||
return roles, nil
|
return roles, nil
|
||||||
|
@ -2827,7 +2827,7 @@ func (p *BoltProvider) updateIPListEntry(entry *IPListEntry) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) deleteIPListEntry(entry IPListEntry, softDelete bool) error {
|
func (p *BoltProvider) deleteIPListEntry(entry IPListEntry, _ bool) error {
|
||||||
return p.dbHandle.Update(func(tx *bolt.Tx) error {
|
return p.dbHandle.Update(func(tx *bolt.Tx) error {
|
||||||
bucket, err := p.getIPListsBucket(tx)
|
bucket, err := p.getIPListsBucket(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -2888,7 +2888,7 @@ func (p *BoltProvider) getIPListEntries(listType IPListType, filter, from, order
|
||||||
return entries, err
|
return entries, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoltProvider) getRecentlyUpdatedIPListEntries(after int64) ([]IPListEntry, error) {
|
func (p *BoltProvider) getRecentlyUpdatedIPListEntries(_ int64) ([]IPListEntry, error) {
|
||||||
return nil, ErrNotImplemented
|
return nil, ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,13 +47,14 @@ const (
|
||||||
ActionTypeMetadataCheck
|
ActionTypeMetadataCheck
|
||||||
ActionTypePasswordExpirationCheck
|
ActionTypePasswordExpirationCheck
|
||||||
ActionTypeUserExpirationCheck
|
ActionTypeUserExpirationCheck
|
||||||
|
ActionTypeIDPAccountCheck
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
supportedEventActions = []int{ActionTypeHTTP, ActionTypeCommand, ActionTypeEmail, ActionTypeFilesystem,
|
supportedEventActions = []int{ActionTypeHTTP, ActionTypeCommand, ActionTypeEmail, ActionTypeFilesystem,
|
||||||
ActionTypeBackup, ActionTypeUserQuotaReset, ActionTypeFolderQuotaReset, ActionTypeTransferQuotaReset,
|
ActionTypeBackup, ActionTypeUserQuotaReset, ActionTypeFolderQuotaReset, ActionTypeTransferQuotaReset,
|
||||||
ActionTypeDataRetentionCheck, ActionTypeMetadataCheck, ActionTypePasswordExpirationCheck,
|
ActionTypeDataRetentionCheck, ActionTypeMetadataCheck, ActionTypePasswordExpirationCheck,
|
||||||
ActionTypeUserExpirationCheck}
|
ActionTypeUserExpirationCheck, ActionTypeIDPAccountCheck}
|
||||||
)
|
)
|
||||||
|
|
||||||
func isActionTypeValid(action int) bool {
|
func isActionTypeValid(action int) bool {
|
||||||
|
@ -84,6 +85,8 @@ func getActionTypeAsString(action int) string {
|
||||||
return "Password expiration check"
|
return "Password expiration check"
|
||||||
case ActionTypeUserExpirationCheck:
|
case ActionTypeUserExpirationCheck:
|
||||||
return "User expiration check"
|
return "User expiration check"
|
||||||
|
case ActionTypeIDPAccountCheck:
|
||||||
|
return "Identity Provider account check"
|
||||||
default:
|
default:
|
||||||
return "Command"
|
return "Command"
|
||||||
}
|
}
|
||||||
|
@ -99,11 +102,12 @@ const (
|
||||||
EventTriggerIPBlocked
|
EventTriggerIPBlocked
|
||||||
EventTriggerCertificate
|
EventTriggerCertificate
|
||||||
EventTriggerOnDemand
|
EventTriggerOnDemand
|
||||||
|
EventTriggerIDPLogin
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
supportedEventTriggers = []int{EventTriggerFsEvent, EventTriggerProviderEvent, EventTriggerSchedule,
|
supportedEventTriggers = []int{EventTriggerFsEvent, EventTriggerProviderEvent, EventTriggerSchedule,
|
||||||
EventTriggerIPBlocked, EventTriggerCertificate, EventTriggerOnDemand}
|
EventTriggerIPBlocked, EventTriggerCertificate, EventTriggerIDPLogin, EventTriggerOnDemand}
|
||||||
)
|
)
|
||||||
|
|
||||||
func isEventTriggerValid(trigger int) bool {
|
func isEventTriggerValid(trigger int) bool {
|
||||||
|
@ -122,11 +126,24 @@ func getTriggerTypeAsString(trigger int) string {
|
||||||
return "Certificate renewal"
|
return "Certificate renewal"
|
||||||
case EventTriggerOnDemand:
|
case EventTriggerOnDemand:
|
||||||
return "On demand"
|
return "On demand"
|
||||||
|
case EventTriggerIDPLogin:
|
||||||
|
return "Identity Provider login"
|
||||||
default:
|
default:
|
||||||
return "Schedule"
|
return "Schedule"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Supported IDP login events
|
||||||
|
const (
|
||||||
|
IDPLoginAny = iota
|
||||||
|
IDPLoginUser
|
||||||
|
IDPLoginAdmin
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
supportedIDPLoginEvents = []int{IDPLoginAny, IDPLoginUser, IDPLoginAdmin}
|
||||||
|
)
|
||||||
|
|
||||||
// Supported filesystem actions
|
// Supported filesystem actions
|
||||||
const (
|
const (
|
||||||
FilesystemActionRename = iota + 1
|
FilesystemActionRename = iota + 1
|
||||||
|
@ -276,6 +293,16 @@ type EventActionHTTPConfig struct {
|
||||||
Parts []HTTPPart `json:"parts,omitempty"`
|
Parts []HTTPPart `json:"parts,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasJSONBody returns true if the content type header indicates a JSON body
|
||||||
|
func (c *EventActionHTTPConfig) HasJSONBody() bool {
|
||||||
|
for _, h := range c.Headers {
|
||||||
|
if http.CanonicalHeaderKey(h.Key) == "Content-Type" {
|
||||||
|
return strings.Contains(strings.ToLower(h.Value), "application/json")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (c *EventActionHTTPConfig) isTimeoutNotValid() bool {
|
func (c *EventActionHTTPConfig) isTimeoutNotValid() bool {
|
||||||
if c.HasMultipartFiles() {
|
if c.HasMultipartFiles() {
|
||||||
return false
|
return false
|
||||||
|
@ -833,6 +860,24 @@ func (c *EventActionPasswordExpiration) validate() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EventActionIDPAccountCheck defines the check to execute after a successful IDP login
|
||||||
|
type EventActionIDPAccountCheck struct {
|
||||||
|
// 0 create/update, 1 create the account if it doesn't exist
|
||||||
|
Mode int `json:"mode,omitempty"`
|
||||||
|
TemplateUser string `json:"template_user,omitempty"`
|
||||||
|
TemplateAdmin string `json:"template_admin,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *EventActionIDPAccountCheck) validate() error {
|
||||||
|
if c.TemplateAdmin == "" && c.TemplateUser == "" {
|
||||||
|
return util.NewValidationError("at least a template must be set")
|
||||||
|
}
|
||||||
|
if c.Mode < 0 || c.Mode > 1 {
|
||||||
|
return util.NewValidationError(fmt.Sprintf("invalid account check mode: %d", c.Mode))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// BaseEventActionOptions defines the supported configuration options for a base event actions
|
// BaseEventActionOptions defines the supported configuration options for a base event actions
|
||||||
type BaseEventActionOptions struct {
|
type BaseEventActionOptions struct {
|
||||||
HTTPConfig EventActionHTTPConfig `json:"http_config"`
|
HTTPConfig EventActionHTTPConfig `json:"http_config"`
|
||||||
|
@ -841,6 +886,7 @@ type BaseEventActionOptions struct {
|
||||||
RetentionConfig EventActionDataRetentionConfig `json:"retention_config"`
|
RetentionConfig EventActionDataRetentionConfig `json:"retention_config"`
|
||||||
FsConfig EventActionFilesystemConfig `json:"fs_config"`
|
FsConfig EventActionFilesystemConfig `json:"fs_config"`
|
||||||
PwdExpirationConfig EventActionPasswordExpiration `json:"pwd_expiration_config"`
|
PwdExpirationConfig EventActionPasswordExpiration `json:"pwd_expiration_config"`
|
||||||
|
IDPConfig EventActionIDPAccountCheck `json:"idp_config"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *BaseEventActionOptions) getACopy() BaseEventActionOptions {
|
func (o *BaseEventActionOptions) getACopy() BaseEventActionOptions {
|
||||||
|
@ -901,6 +947,11 @@ func (o *BaseEventActionOptions) getACopy() BaseEventActionOptions {
|
||||||
PwdExpirationConfig: EventActionPasswordExpiration{
|
PwdExpirationConfig: EventActionPasswordExpiration{
|
||||||
Threshold: o.PwdExpirationConfig.Threshold,
|
Threshold: o.PwdExpirationConfig.Threshold,
|
||||||
},
|
},
|
||||||
|
IDPConfig: EventActionIDPAccountCheck{
|
||||||
|
Mode: o.IDPConfig.Mode,
|
||||||
|
TemplateUser: o.IDPConfig.TemplateUser,
|
||||||
|
TemplateAdmin: o.IDPConfig.TemplateAdmin,
|
||||||
|
},
|
||||||
FsConfig: o.FsConfig.getACopy(),
|
FsConfig: o.FsConfig.getACopy(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -933,6 +984,7 @@ func (o *BaseEventActionOptions) validate(action int, name string) error {
|
||||||
o.RetentionConfig = EventActionDataRetentionConfig{}
|
o.RetentionConfig = EventActionDataRetentionConfig{}
|
||||||
o.FsConfig = EventActionFilesystemConfig{}
|
o.FsConfig = EventActionFilesystemConfig{}
|
||||||
o.PwdExpirationConfig = EventActionPasswordExpiration{}
|
o.PwdExpirationConfig = EventActionPasswordExpiration{}
|
||||||
|
o.IDPConfig = EventActionIDPAccountCheck{}
|
||||||
return o.HTTPConfig.validate(name)
|
return o.HTTPConfig.validate(name)
|
||||||
case ActionTypeCommand:
|
case ActionTypeCommand:
|
||||||
o.HTTPConfig = EventActionHTTPConfig{}
|
o.HTTPConfig = EventActionHTTPConfig{}
|
||||||
|
@ -940,6 +992,7 @@ func (o *BaseEventActionOptions) validate(action int, name string) error {
|
||||||
o.RetentionConfig = EventActionDataRetentionConfig{}
|
o.RetentionConfig = EventActionDataRetentionConfig{}
|
||||||
o.FsConfig = EventActionFilesystemConfig{}
|
o.FsConfig = EventActionFilesystemConfig{}
|
||||||
o.PwdExpirationConfig = EventActionPasswordExpiration{}
|
o.PwdExpirationConfig = EventActionPasswordExpiration{}
|
||||||
|
o.IDPConfig = EventActionIDPAccountCheck{}
|
||||||
return o.CmdConfig.validate()
|
return o.CmdConfig.validate()
|
||||||
case ActionTypeEmail:
|
case ActionTypeEmail:
|
||||||
o.HTTPConfig = EventActionHTTPConfig{}
|
o.HTTPConfig = EventActionHTTPConfig{}
|
||||||
|
@ -947,6 +1000,7 @@ func (o *BaseEventActionOptions) validate(action int, name string) error {
|
||||||
o.RetentionConfig = EventActionDataRetentionConfig{}
|
o.RetentionConfig = EventActionDataRetentionConfig{}
|
||||||
o.FsConfig = EventActionFilesystemConfig{}
|
o.FsConfig = EventActionFilesystemConfig{}
|
||||||
o.PwdExpirationConfig = EventActionPasswordExpiration{}
|
o.PwdExpirationConfig = EventActionPasswordExpiration{}
|
||||||
|
o.IDPConfig = EventActionIDPAccountCheck{}
|
||||||
return o.EmailConfig.validate()
|
return o.EmailConfig.validate()
|
||||||
case ActionTypeDataRetentionCheck:
|
case ActionTypeDataRetentionCheck:
|
||||||
o.HTTPConfig = EventActionHTTPConfig{}
|
o.HTTPConfig = EventActionHTTPConfig{}
|
||||||
|
@ -954,6 +1008,7 @@ func (o *BaseEventActionOptions) validate(action int, name string) error {
|
||||||
o.EmailConfig = EventActionEmailConfig{}
|
o.EmailConfig = EventActionEmailConfig{}
|
||||||
o.FsConfig = EventActionFilesystemConfig{}
|
o.FsConfig = EventActionFilesystemConfig{}
|
||||||
o.PwdExpirationConfig = EventActionPasswordExpiration{}
|
o.PwdExpirationConfig = EventActionPasswordExpiration{}
|
||||||
|
o.IDPConfig = EventActionIDPAccountCheck{}
|
||||||
return o.RetentionConfig.validate()
|
return o.RetentionConfig.validate()
|
||||||
case ActionTypeFilesystem:
|
case ActionTypeFilesystem:
|
||||||
o.HTTPConfig = EventActionHTTPConfig{}
|
o.HTTPConfig = EventActionHTTPConfig{}
|
||||||
|
@ -961,6 +1016,7 @@ func (o *BaseEventActionOptions) validate(action int, name string) error {
|
||||||
o.EmailConfig = EventActionEmailConfig{}
|
o.EmailConfig = EventActionEmailConfig{}
|
||||||
o.RetentionConfig = EventActionDataRetentionConfig{}
|
o.RetentionConfig = EventActionDataRetentionConfig{}
|
||||||
o.PwdExpirationConfig = EventActionPasswordExpiration{}
|
o.PwdExpirationConfig = EventActionPasswordExpiration{}
|
||||||
|
o.IDPConfig = EventActionIDPAccountCheck{}
|
||||||
return o.FsConfig.validate()
|
return o.FsConfig.validate()
|
||||||
case ActionTypePasswordExpirationCheck:
|
case ActionTypePasswordExpirationCheck:
|
||||||
o.HTTPConfig = EventActionHTTPConfig{}
|
o.HTTPConfig = EventActionHTTPConfig{}
|
||||||
|
@ -968,7 +1024,16 @@ func (o *BaseEventActionOptions) validate(action int, name string) error {
|
||||||
o.EmailConfig = EventActionEmailConfig{}
|
o.EmailConfig = EventActionEmailConfig{}
|
||||||
o.RetentionConfig = EventActionDataRetentionConfig{}
|
o.RetentionConfig = EventActionDataRetentionConfig{}
|
||||||
o.FsConfig = EventActionFilesystemConfig{}
|
o.FsConfig = EventActionFilesystemConfig{}
|
||||||
|
o.IDPConfig = EventActionIDPAccountCheck{}
|
||||||
return o.PwdExpirationConfig.validate()
|
return o.PwdExpirationConfig.validate()
|
||||||
|
case ActionTypeIDPAccountCheck:
|
||||||
|
o.HTTPConfig = EventActionHTTPConfig{}
|
||||||
|
o.CmdConfig = EventActionCommandConfig{}
|
||||||
|
o.EmailConfig = EventActionEmailConfig{}
|
||||||
|
o.RetentionConfig = EventActionDataRetentionConfig{}
|
||||||
|
o.FsConfig = EventActionFilesystemConfig{}
|
||||||
|
o.PwdExpirationConfig = EventActionPasswordExpiration{}
|
||||||
|
return o.IDPConfig.validate()
|
||||||
default:
|
default:
|
||||||
o.HTTPConfig = EventActionHTTPConfig{}
|
o.HTTPConfig = EventActionHTTPConfig{}
|
||||||
o.CmdConfig = EventActionCommandConfig{}
|
o.CmdConfig = EventActionCommandConfig{}
|
||||||
|
@ -976,6 +1041,7 @@ func (o *BaseEventActionOptions) validate(action int, name string) error {
|
||||||
o.RetentionConfig = EventActionDataRetentionConfig{}
|
o.RetentionConfig = EventActionDataRetentionConfig{}
|
||||||
o.FsConfig = EventActionFilesystemConfig{}
|
o.FsConfig = EventActionFilesystemConfig{}
|
||||||
o.PwdExpirationConfig = EventActionPasswordExpiration{}
|
o.PwdExpirationConfig = EventActionPasswordExpiration{}
|
||||||
|
o.IDPConfig = EventActionIDPAccountCheck{}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1086,12 +1152,14 @@ func (a *EventAction) validateAssociation(trigger int, fsEvents []string) error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if a.Options.ExecuteSync {
|
if a.Options.ExecuteSync {
|
||||||
if trigger != EventTriggerFsEvent {
|
if trigger != EventTriggerFsEvent && trigger != EventTriggerIDPLogin {
|
||||||
return util.NewValidationError("sync execution is only supported for some filesystem events")
|
return util.NewValidationError("sync execution is only supported for some filesystem events and Identity Provider logins")
|
||||||
}
|
}
|
||||||
for _, ev := range fsEvents {
|
if trigger == EventTriggerFsEvent {
|
||||||
if !util.Contains(allowedSyncFsEvents, ev) {
|
for _, ev := range fsEvents {
|
||||||
return util.NewValidationError("sync execution is only supported for upload and pre-* events")
|
if !util.Contains(allowedSyncFsEvents, ev) {
|
||||||
|
return util.NewValidationError("sync execution is only supported for upload and pre-* events")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1213,10 +1281,12 @@ func (s *Schedule) validate() error {
|
||||||
// EventConditions defines the conditions for an event rule
|
// EventConditions defines the conditions for an event rule
|
||||||
type EventConditions struct {
|
type EventConditions struct {
|
||||||
// Only one between FsEvents, ProviderEvents and Schedule is allowed
|
// Only one between FsEvents, ProviderEvents and Schedule is allowed
|
||||||
FsEvents []string `json:"fs_events,omitempty"`
|
FsEvents []string `json:"fs_events,omitempty"`
|
||||||
ProviderEvents []string `json:"provider_events,omitempty"`
|
ProviderEvents []string `json:"provider_events,omitempty"`
|
||||||
Schedules []Schedule `json:"schedules,omitempty"`
|
Schedules []Schedule `json:"schedules,omitempty"`
|
||||||
Options ConditionOptions `json:"options"`
|
// 0 any, 1 user, 2 admin
|
||||||
|
IDPLoginEvent int `json:"idp_login_event,omitempty"`
|
||||||
|
Options ConditionOptions `json:"options"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *EventConditions) getACopy() EventConditions {
|
func (c *EventConditions) getACopy() EventConditions {
|
||||||
|
@ -1238,16 +1308,30 @@ func (c *EventConditions) getACopy() EventConditions {
|
||||||
FsEvents: fsEvents,
|
FsEvents: fsEvents,
|
||||||
ProviderEvents: providerEvents,
|
ProviderEvents: providerEvents,
|
||||||
Schedules: schedules,
|
Schedules: schedules,
|
||||||
|
IDPLoginEvent: c.IDPLoginEvent,
|
||||||
Options: c.Options.getACopy(),
|
Options: c.Options.getACopy(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *EventConditions) validateSchedules() error {
|
||||||
|
if len(c.Schedules) == 0 {
|
||||||
|
return util.NewValidationError("at least one schedule is required")
|
||||||
|
}
|
||||||
|
for _, schedule := range c.Schedules {
|
||||||
|
if err := schedule.validate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *EventConditions) validate(trigger int) error {
|
func (c *EventConditions) validate(trigger int) error {
|
||||||
switch trigger {
|
switch trigger {
|
||||||
case EventTriggerFsEvent:
|
case EventTriggerFsEvent:
|
||||||
c.ProviderEvents = nil
|
c.ProviderEvents = nil
|
||||||
c.Schedules = nil
|
c.Schedules = nil
|
||||||
c.Options.ProviderObjects = nil
|
c.Options.ProviderObjects = nil
|
||||||
|
c.IDPLoginEvent = 0
|
||||||
if len(c.FsEvents) == 0 {
|
if len(c.FsEvents) == 0 {
|
||||||
return util.NewValidationError("at least one filesystem event is required")
|
return util.NewValidationError("at least one filesystem event is required")
|
||||||
}
|
}
|
||||||
|
@ -1264,6 +1348,7 @@ func (c *EventConditions) validate(trigger int) error {
|
||||||
c.Options.Protocols = nil
|
c.Options.Protocols = nil
|
||||||
c.Options.MinFileSize = 0
|
c.Options.MinFileSize = 0
|
||||||
c.Options.MaxFileSize = 0
|
c.Options.MaxFileSize = 0
|
||||||
|
c.IDPLoginEvent = 0
|
||||||
if len(c.ProviderEvents) == 0 {
|
if len(c.ProviderEvents) == 0 {
|
||||||
return util.NewValidationError("at least one provider event is required")
|
return util.NewValidationError("at least one provider event is required")
|
||||||
}
|
}
|
||||||
|
@ -1280,13 +1365,9 @@ func (c *EventConditions) validate(trigger int) error {
|
||||||
c.Options.MinFileSize = 0
|
c.Options.MinFileSize = 0
|
||||||
c.Options.MaxFileSize = 0
|
c.Options.MaxFileSize = 0
|
||||||
c.Options.ProviderObjects = nil
|
c.Options.ProviderObjects = nil
|
||||||
if len(c.Schedules) == 0 {
|
c.IDPLoginEvent = 0
|
||||||
return util.NewValidationError("at least one schedule is required")
|
if err := c.validateSchedules(); err != nil {
|
||||||
}
|
return err
|
||||||
for _, schedule := range c.Schedules {
|
|
||||||
if err := schedule.validate(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
case EventTriggerIPBlocked, EventTriggerCertificate:
|
case EventTriggerIPBlocked, EventTriggerCertificate:
|
||||||
c.FsEvents = nil
|
c.FsEvents = nil
|
||||||
|
@ -1299,6 +1380,7 @@ func (c *EventConditions) validate(trigger int) error {
|
||||||
c.Options.MinFileSize = 0
|
c.Options.MinFileSize = 0
|
||||||
c.Options.MaxFileSize = 0
|
c.Options.MaxFileSize = 0
|
||||||
c.Schedules = nil
|
c.Schedules = nil
|
||||||
|
c.IDPLoginEvent = 0
|
||||||
case EventTriggerOnDemand:
|
case EventTriggerOnDemand:
|
||||||
c.FsEvents = nil
|
c.FsEvents = nil
|
||||||
c.ProviderEvents = nil
|
c.ProviderEvents = nil
|
||||||
|
@ -1308,7 +1390,21 @@ func (c *EventConditions) validate(trigger int) error {
|
||||||
c.Options.MaxFileSize = 0
|
c.Options.MaxFileSize = 0
|
||||||
c.Options.ProviderObjects = nil
|
c.Options.ProviderObjects = nil
|
||||||
c.Schedules = nil
|
c.Schedules = nil
|
||||||
|
c.IDPLoginEvent = 0
|
||||||
c.Options.ConcurrentExecution = false
|
c.Options.ConcurrentExecution = false
|
||||||
|
case EventTriggerIDPLogin:
|
||||||
|
c.FsEvents = nil
|
||||||
|
c.ProviderEvents = nil
|
||||||
|
c.Options.GroupNames = nil
|
||||||
|
c.Options.RoleNames = nil
|
||||||
|
c.Options.FsPaths = nil
|
||||||
|
c.Options.Protocols = nil
|
||||||
|
c.Options.MinFileSize = 0
|
||||||
|
c.Options.MaxFileSize = 0
|
||||||
|
c.Schedules = nil
|
||||||
|
if !util.Contains(supportedIDPLoginEvents, c.IDPLoginEvent) {
|
||||||
|
return util.NewValidationError(fmt.Sprintf("invalid Identity Provider login event %d", c.IDPLoginEvent))
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
c.FsEvents = nil
|
c.FsEvents = nil
|
||||||
c.ProviderEvents = nil
|
c.ProviderEvents = nil
|
||||||
|
@ -1319,6 +1415,7 @@ func (c *EventConditions) validate(trigger int) error {
|
||||||
c.Options.MinFileSize = 0
|
c.Options.MinFileSize = 0
|
||||||
c.Options.MaxFileSize = 0
|
c.Options.MaxFileSize = 0
|
||||||
c.Schedules = nil
|
c.Schedules = nil
|
||||||
|
c.IDPLoginEvent = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Options.validate()
|
return c.Options.validate()
|
||||||
|
@ -1453,7 +1550,7 @@ func (r *EventRule) validateMandatorySyncActions() error {
|
||||||
}
|
}
|
||||||
for _, ev := range r.Conditions.FsEvents {
|
for _, ev := range r.Conditions.FsEvents {
|
||||||
if util.Contains(mandatorySyncFsEvents, ev) {
|
if util.Contains(mandatorySyncFsEvents, ev) {
|
||||||
return util.NewValidationError(fmt.Sprintf("event %s requires at least a sync action", ev))
|
return util.NewValidationError(fmt.Sprintf("event %q requires at least a sync action", ev))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -1508,6 +1605,39 @@ func (r *EventRule) hasUserAssociated(providerObjectType string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *EventRule) checkActions(providerObjectType string) error {
|
||||||
|
numSyncAction := 0
|
||||||
|
hasIDPAccountCheck := false
|
||||||
|
for _, action := range r.Actions {
|
||||||
|
if action.Options.ExecuteSync {
|
||||||
|
numSyncAction++
|
||||||
|
}
|
||||||
|
if action.Type == ActionTypeEmail && action.BaseEventAction.Options.EmailConfig.hasFilesAttachments() {
|
||||||
|
if !r.hasUserAssociated(providerObjectType) {
|
||||||
|
return errors.New("cannot send an email with attachments for a rule with no user associated")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if action.Type == ActionTypeHTTP && action.BaseEventAction.Options.HTTPConfig.HasMultipartFiles() {
|
||||||
|
if !r.hasUserAssociated(providerObjectType) {
|
||||||
|
return errors.New("cannot upload file/s for a rule with no user associated")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if action.Type == ActionTypeIDPAccountCheck {
|
||||||
|
if r.Trigger != EventTriggerIDPLogin {
|
||||||
|
return errors.New("IDP account check action is only supported for IDP login trigger")
|
||||||
|
}
|
||||||
|
if !action.Options.ExecuteSync {
|
||||||
|
return errors.New("IDP account check must be a sync action")
|
||||||
|
}
|
||||||
|
hasIDPAccountCheck = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if hasIDPAccountCheck && numSyncAction != 1 {
|
||||||
|
return errors.New("IDP account check must be the only sync action")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// CheckActionsConsistency returns an error if the actions cannot be executed
|
// CheckActionsConsistency returns an error if the actions cannot be executed
|
||||||
func (r *EventRule) CheckActionsConsistency(providerObjectType string) error {
|
func (r *EventRule) CheckActionsConsistency(providerObjectType string) error {
|
||||||
switch r.Trigger {
|
switch r.Trigger {
|
||||||
|
@ -1528,19 +1658,7 @@ func (r *EventRule) CheckActionsConsistency(providerObjectType string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, action := range r.Actions {
|
return r.checkActions(providerObjectType)
|
||||||
if action.Type == ActionTypeEmail && action.BaseEventAction.Options.EmailConfig.hasFilesAttachments() {
|
|
||||||
if !r.hasUserAssociated(providerObjectType) {
|
|
||||||
return errors.New("cannot send an email with attachments for a rule with no user associated")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if action.Type == ActionTypeHTTP && action.BaseEventAction.Options.HTTPConfig.HasMultipartFiles() {
|
|
||||||
if !r.hasUserAssociated(providerObjectType) {
|
|
||||||
return errors.New("cannot upload file/s for a rule with no user associated")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrepareForRendering prepares an EventRule for rendering.
|
// PrepareForRendering prepares an EventRule for rendering.
|
||||||
|
|
|
@ -431,7 +431,7 @@ func (p *MemoryProvider) updateUser(user *User) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) deleteUser(user User, softDelete bool) error {
|
func (p *MemoryProvider) deleteUser(user User, _ bool) error {
|
||||||
p.dbHandle.Lock()
|
p.dbHandle.Lock()
|
||||||
defer p.dbHandle.Unlock()
|
defer p.dbHandle.Unlock()
|
||||||
if p.dbHandle.isClosed {
|
if p.dbHandle.isClosed {
|
||||||
|
@ -898,7 +898,7 @@ func (p *MemoryProvider) updateFolderQuota(name string, filesAdd int, sizeAdd in
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) getGroups(limit, offset int, order string, minimal bool) ([]Group, error) {
|
func (p *MemoryProvider) getGroups(limit, offset int, order string, _ bool) ([]Group, error) {
|
||||||
p.dbHandle.Lock()
|
p.dbHandle.Lock()
|
||||||
defer p.dbHandle.Unlock()
|
defer p.dbHandle.Unlock()
|
||||||
if p.dbHandle.isClosed {
|
if p.dbHandle.isClosed {
|
||||||
|
@ -1422,7 +1422,7 @@ func (p *MemoryProvider) folderExistsInternal(name string) (vfs.BaseVirtualFolde
|
||||||
return vfs.BaseVirtualFolder{}, util.NewRecordNotFoundError(fmt.Sprintf("folder %q does not exist", name))
|
return vfs.BaseVirtualFolder{}, util.NewRecordNotFoundError(fmt.Sprintf("folder %q does not exist", name))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) getFolders(limit, offset int, order string, minimal bool) ([]vfs.BaseVirtualFolder, error) {
|
func (p *MemoryProvider) getFolders(limit, offset int, order string, _ bool) ([]vfs.BaseVirtualFolder, error) {
|
||||||
folders := make([]vfs.BaseVirtualFolder, 0, limit)
|
folders := make([]vfs.BaseVirtualFolder, 0, limit)
|
||||||
var err error
|
var err error
|
||||||
p.dbHandle.Lock()
|
p.dbHandle.Lock()
|
||||||
|
@ -2006,75 +2006,75 @@ func (p *MemoryProvider) updateShareLastUse(shareID string, numTokens int) error
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) getDefenderHosts(from int64, limit int) ([]DefenderEntry, error) {
|
func (p *MemoryProvider) getDefenderHosts(_ int64, _ int) ([]DefenderEntry, error) {
|
||||||
return nil, ErrNotImplemented
|
return nil, ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) getDefenderHostByIP(ip string, from int64) (DefenderEntry, error) {
|
func (p *MemoryProvider) getDefenderHostByIP(_ string, _ int64) (DefenderEntry, error) {
|
||||||
return DefenderEntry{}, ErrNotImplemented
|
return DefenderEntry{}, ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) isDefenderHostBanned(ip string) (DefenderEntry, error) {
|
func (p *MemoryProvider) isDefenderHostBanned(_ string) (DefenderEntry, error) {
|
||||||
return DefenderEntry{}, ErrNotImplemented
|
return DefenderEntry{}, ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) updateDefenderBanTime(ip string, minutes int) error {
|
func (p *MemoryProvider) updateDefenderBanTime(_ string, _ int) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) deleteDefenderHost(ip string) error {
|
func (p *MemoryProvider) deleteDefenderHost(_ string) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) addDefenderEvent(ip string, score int) error {
|
func (p *MemoryProvider) addDefenderEvent(_ string, _ int) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) setDefenderBanTime(ip string, banTime int64) error {
|
func (p *MemoryProvider) setDefenderBanTime(_ string, _ int64) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) cleanupDefender(from int64) error {
|
func (p *MemoryProvider) cleanupDefender(_ int64) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) addActiveTransfer(transfer ActiveTransfer) error {
|
func (p *MemoryProvider) addActiveTransfer(_ ActiveTransfer) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) updateActiveTransferSizes(ulSize, dlSize, transferID int64, connectionID string) error {
|
func (p *MemoryProvider) updateActiveTransferSizes(_, _, _ int64, _ string) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) removeActiveTransfer(transferID int64, connectionID string) error {
|
func (p *MemoryProvider) removeActiveTransfer(_ int64, _ string) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) cleanupActiveTransfers(before time.Time) error {
|
func (p *MemoryProvider) cleanupActiveTransfers(_ time.Time) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) getActiveTransfers(from time.Time) ([]ActiveTransfer, error) {
|
func (p *MemoryProvider) getActiveTransfers(_ time.Time) ([]ActiveTransfer, error) {
|
||||||
return nil, ErrNotImplemented
|
return nil, ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) addSharedSession(session Session) error {
|
func (p *MemoryProvider) addSharedSession(_ Session) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) deleteSharedSession(key string) error {
|
func (p *MemoryProvider) deleteSharedSession(_ string) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) getSharedSession(key string) (Session, error) {
|
func (p *MemoryProvider) getSharedSession(_ string) (Session, error) {
|
||||||
return Session{}, ErrNotImplemented
|
return Session{}, ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) cleanupSharedSessions(sessionType SessionType, before int64) error {
|
func (p *MemoryProvider) cleanupSharedSessions(_ SessionType, _ int64) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) getEventActions(limit, offset int, order string, minimal bool) ([]BaseEventAction, error) {
|
func (p *MemoryProvider) getEventActions(limit, offset int, order string, _ bool) ([]BaseEventAction, error) {
|
||||||
p.dbHandle.Lock()
|
p.dbHandle.Lock()
|
||||||
defer p.dbHandle.Unlock()
|
defer p.dbHandle.Unlock()
|
||||||
if p.dbHandle.isClosed {
|
if p.dbHandle.isClosed {
|
||||||
|
@ -2395,7 +2395,7 @@ func (p *MemoryProvider) updateEventRule(rule *EventRule) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) deleteEventRule(rule EventRule, softDelete bool) error {
|
func (p *MemoryProvider) deleteEventRule(rule EventRule, _ bool) error {
|
||||||
p.dbHandle.Lock()
|
p.dbHandle.Lock()
|
||||||
defer p.dbHandle.Unlock()
|
defer p.dbHandle.Unlock()
|
||||||
if p.dbHandle.isClosed {
|
if p.dbHandle.isClosed {
|
||||||
|
@ -2420,19 +2420,19 @@ func (p *MemoryProvider) deleteEventRule(rule EventRule, softDelete bool) error
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*MemoryProvider) getTaskByName(name string) (Task, error) {
|
func (*MemoryProvider) getTaskByName(_ string) (Task, error) {
|
||||||
return Task{}, ErrNotImplemented
|
return Task{}, ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*MemoryProvider) addTask(name string) error {
|
func (*MemoryProvider) addTask(_ string) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*MemoryProvider) updateTask(name string, version int64) error {
|
func (*MemoryProvider) updateTask(_ string, _ int64) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*MemoryProvider) updateTaskTimestamp(name string) error {
|
func (*MemoryProvider) updateTaskTimestamp(_ string) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2440,7 +2440,7 @@ func (*MemoryProvider) addNode() error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*MemoryProvider) getNodeByName(name string) (Node, error) {
|
func (*MemoryProvider) getNodeByName(_ string) (Node, error) {
|
||||||
return Node{}, ErrNotImplemented
|
return Node{}, ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2550,7 +2550,7 @@ func (p *MemoryProvider) deleteRole(role Role) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) getRoles(limit int, offset int, order string, minimal bool) ([]Role, error) {
|
func (p *MemoryProvider) getRoles(limit int, offset int, order string, _ bool) ([]Role, error) {
|
||||||
p.dbHandle.Lock()
|
p.dbHandle.Lock()
|
||||||
defer p.dbHandle.Unlock()
|
defer p.dbHandle.Unlock()
|
||||||
|
|
||||||
|
@ -2662,7 +2662,7 @@ func (p *MemoryProvider) updateIPListEntry(entry *IPListEntry) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) deleteIPListEntry(entry IPListEntry, softDelete bool) error {
|
func (p *MemoryProvider) deleteIPListEntry(entry IPListEntry, _ bool) error {
|
||||||
if err := entry.validate(); err != nil {
|
if err := entry.validate(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -2721,7 +2721,7 @@ func (p *MemoryProvider) getIPListEntries(listType IPListType, filter, from, ord
|
||||||
return entries, nil
|
return entries, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) getRecentlyUpdatedIPListEntries(after int64) ([]IPListEntry, error) {
|
func (p *MemoryProvider) getRecentlyUpdatedIPListEntries(_ int64) ([]IPListEntry, error) {
|
||||||
return nil, ErrNotImplemented
|
return nil, ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3293,7 +3293,7 @@ func (p *MemoryProvider) migrateDatabase() error {
|
||||||
return ErrNoInitRequired
|
return ErrNoInitRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MemoryProvider) revertDatabase(targetVersion int) error {
|
func (p *MemoryProvider) revertDatabase(_ int) error {
|
||||||
return errors.New("memory provider does not store data, revert not possible")
|
return errors.New("memory provider does not store data, revert not possible")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3491,7 +3491,7 @@ func sqlCommonUpdateEventAction(action *BaseEventAction, dbHandle *sql.DB) error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
q = getUpdateRulesTimestampQuery()
|
q = getUpdateRulesTimestampQuery()
|
||||||
_, err = tx.ExecContext(ctx, q, util.GetTimeAsMsSinceEpoch(time.Now()), action.ID)
|
_, err = tx.ExecContext(ctx, q, util.GetTimeAsMsSinceEpoch(time.Now()), action.Name)
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -603,7 +603,7 @@ func (*SQLiteProvider) addNode() error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*SQLiteProvider) getNodeByName(name string) (Node, error) {
|
func (*SQLiteProvider) getNodeByName(_ string) (Node, error) {
|
||||||
return Node{}, ErrNotImplemented
|
return Node{}, ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1106,8 +1106,8 @@ func getClearRuleActionMappingQuery() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUpdateRulesTimestampQuery() string {
|
func getUpdateRulesTimestampQuery() string {
|
||||||
return fmt.Sprintf(`UPDATE %s SET updated_at=%s WHERE id IN (SELECT rule_id FROM %s WHERE action_id = %s)`,
|
return fmt.Sprintf(`UPDATE %s SET updated_at=%s WHERE id IN (SELECT rule_id FROM %s WHERE action_id = (SELECT id from %s WHERE name = %s))`,
|
||||||
sqlTableEventsRules, sqlPlaceholders[0], sqlTableRulesActionsMapping, sqlPlaceholders[1])
|
sqlTableEventsRules, sqlPlaceholders[0], sqlTableRulesActionsMapping, sqlTableEventsActions, sqlPlaceholders[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRelatedActionsForRulesQuery(rules []EventRule) string {
|
func getRelatedActionsForRulesQuery(rules []EventRule) string {
|
||||||
|
|
|
@ -90,29 +90,29 @@ func (c *Connection) GetCommand() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create is not implemented we use ClientDriverExtentionFileTransfer
|
// Create is not implemented we use ClientDriverExtentionFileTransfer
|
||||||
func (c *Connection) Create(name string) (afero.File, error) {
|
func (c *Connection) Create(_ string) (afero.File, error) {
|
||||||
return nil, errNotImplemented
|
return nil, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mkdir creates a directory using the connection filesystem
|
// Mkdir creates a directory using the connection filesystem
|
||||||
func (c *Connection) Mkdir(name string, perm os.FileMode) error {
|
func (c *Connection) Mkdir(name string, _ os.FileMode) error {
|
||||||
c.UpdateLastActivity()
|
c.UpdateLastActivity()
|
||||||
|
|
||||||
return c.CreateDir(name, true)
|
return c.CreateDir(name, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MkdirAll is not implemented, we don't need it
|
// MkdirAll is not implemented, we don't need it
|
||||||
func (c *Connection) MkdirAll(path string, perm os.FileMode) error {
|
func (c *Connection) MkdirAll(_ string, _ os.FileMode) error {
|
||||||
return errNotImplemented
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open is not implemented we use ClientDriverExtentionFileTransfer and ClientDriverExtensionFileList
|
// Open is not implemented we use ClientDriverExtentionFileTransfer and ClientDriverExtensionFileList
|
||||||
func (c *Connection) Open(name string) (afero.File, error) {
|
func (c *Connection) Open(_ string) (afero.File, error) {
|
||||||
return nil, errNotImplemented
|
return nil, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenFile is not implemented we use ClientDriverExtentionFileTransfer
|
// OpenFile is not implemented we use ClientDriverExtentionFileTransfer
|
||||||
func (c *Connection) OpenFile(name string, flag int, perm os.FileMode) (afero.File, error) {
|
func (c *Connection) OpenFile(_ string, _ int, _ os.FileMode) (afero.File, error) {
|
||||||
return nil, errNotImplemented
|
return nil, errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ func (c *Connection) Remove(name string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveAll is not implemented, we don't need it
|
// RemoveAll is not implemented, we don't need it
|
||||||
func (c *Connection) RemoveAll(path string) error {
|
func (c *Connection) RemoveAll(_ string) error {
|
||||||
return errNotImplemented
|
return errNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +178,7 @@ func (c *Connection) Name() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chown changes the uid and gid of the named file
|
// Chown changes the uid and gid of the named file
|
||||||
func (c *Connection) Chown(name string, uid, gid int) error {
|
func (c *Connection) Chown(_ string, _, _ int) error {
|
||||||
c.UpdateLastActivity()
|
c.UpdateLastActivity()
|
||||||
|
|
||||||
return common.ErrOpUnsupported
|
return common.ErrOpUnsupported
|
||||||
|
@ -270,7 +270,7 @@ func (c *Connection) GetAvailableSpace(dirName string) (int64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllocateSpace implements ClientDriverExtensionAllocate interface
|
// AllocateSpace implements ClientDriverExtensionAllocate interface
|
||||||
func (c *Connection) AllocateSpace(size int) error {
|
func (c *Connection) AllocateSpace(_ int) error {
|
||||||
c.UpdateLastActivity()
|
c.UpdateLastActivity()
|
||||||
// we treat ALLO as NOOP see RFC 959
|
// we treat ALLO as NOOP see RFC 959
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -282,11 +282,11 @@ func (cc mockFTPClientContext) Path() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cc mockFTPClientContext) SetPath(name string) {}
|
func (cc mockFTPClientContext) SetPath(_ string) {}
|
||||||
|
|
||||||
func (cc mockFTPClientContext) SetListPath(name string) {}
|
func (cc mockFTPClientContext) SetListPath(_ string) {}
|
||||||
|
|
||||||
func (cc mockFTPClientContext) SetDebug(debug bool) {}
|
func (cc mockFTPClientContext) SetDebug(_ bool) {}
|
||||||
|
|
||||||
func (cc mockFTPClientContext) Debug() bool {
|
func (cc mockFTPClientContext) Debug() bool {
|
||||||
return false
|
return false
|
||||||
|
@ -328,7 +328,7 @@ func (cc mockFTPClientContext) HasTLSForTransfers() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cc mockFTPClientContext) SetTLSRequirement(requirement ftpserver.TLSRequirement) error {
|
func (cc mockFTPClientContext) SetTLSRequirement(_ ftpserver.TLSRequirement) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -380,7 +380,7 @@ func (fs MockOsFs) Lstat(name string) (os.FileInfo, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove removes the named file or (empty) directory.
|
// Remove removes the named file or (empty) directory.
|
||||||
func (fs MockOsFs) Remove(name string, isDir bool) error {
|
func (fs MockOsFs) Remove(name string, _ bool) error {
|
||||||
if fs.err != nil {
|
if fs.err != nil {
|
||||||
return fs.err
|
return fs.err
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,7 +183,7 @@ func restoreBackup(content []byte, inputFile string, scanQuota, mode int, execut
|
||||||
return util.NewValidationError(fmt.Sprintf("unable to parse backup content: %v", err))
|
return util.NewValidationError(fmt.Sprintf("unable to parse backup content: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = RestoreConfigs(dump.Configs, inputFile, mode, executor, ipAddress, role); err != nil {
|
if err = RestoreConfigs(dump.Configs, mode, executor, ipAddress, role); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,7 +423,7 @@ func RestoreAdmins(admins []dataprovider.Admin, inputFile string, mode int, exec
|
||||||
}
|
}
|
||||||
|
|
||||||
// RestoreConfigs restores the specified provider configs
|
// RestoreConfigs restores the specified provider configs
|
||||||
func RestoreConfigs(configs *dataprovider.Configs, inputFile string, mode int, executor, ipAddress,
|
func RestoreConfigs(configs *dataprovider.Configs, mode int, executor, ipAddress,
|
||||||
executorRole string,
|
executorRole string,
|
||||||
) error {
|
) error {
|
||||||
if configs == nil {
|
if configs == nil {
|
||||||
|
|
|
@ -298,6 +298,7 @@ func (c *jwtTokenClaims) removeCookie(w http.ResponseWriter, r *http.Request, co
|
||||||
Secure: isTLS(r),
|
Secure: isTLS(r),
|
||||||
SameSite: http.SameSiteStrictMode,
|
SameSite: http.SameSiteStrictMode,
|
||||||
})
|
})
|
||||||
|
w.Header().Add("Cache-Control", `no-cache="Set-Cookie"`)
|
||||||
invalidateToken(r)
|
invalidateToken(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ func setFlashMessage(w http.ResponseWriter, r *http.Request, value string) {
|
||||||
Secure: isTLS(r),
|
Secure: isTLS(r),
|
||||||
SameSite: http.SameSiteLaxMode,
|
SameSite: http.SameSiteLaxMode,
|
||||||
})
|
})
|
||||||
|
w.Header().Add("Cache-Control", `no-cache="Set-Cookie"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFlashMessage(w http.ResponseWriter, r *http.Request) string {
|
func getFlashMessage(w http.ResponseWriter, r *http.Request) string {
|
||||||
|
|
|
@ -315,15 +315,15 @@ func (t *throttledReader) HasSizeLimit() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *throttledReader) Truncate(fsPath string, size int64) (int64, error) {
|
func (t *throttledReader) Truncate(_ string, _ int64) (int64, error) {
|
||||||
return 0, vfs.ErrVfsUnsupported
|
return 0, vfs.ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *throttledReader) GetRealFsPath(fsPath string) string {
|
func (t *throttledReader) GetRealFsPath(_ string) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *throttledReader) SetTimes(fsPath string, atime time.Time, mtime time.Time) bool {
|
func (t *throttledReader) SetTimes(_ string, _ time.Time, _ time.Time) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1973,6 +1973,58 @@ func TestOnDemandEventRules(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIDPLoginEventRule(t *testing.T) {
|
||||||
|
ruleName := "test IDP login rule"
|
||||||
|
a := dataprovider.BaseEventAction{
|
||||||
|
Name: "a",
|
||||||
|
Type: dataprovider.ActionTypeIDPAccountCheck,
|
||||||
|
Options: dataprovider.BaseEventActionOptions{
|
||||||
|
IDPConfig: dataprovider.EventActionIDPAccountCheck{
|
||||||
|
Mode: 1,
|
||||||
|
TemplateUser: `{"username": "user"}`,
|
||||||
|
TemplateAdmin: `{"username": "admin"}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
action, resp, err := httpdtest.AddEventAction(a, http.StatusCreated)
|
||||||
|
assert.NoError(t, err, string(resp))
|
||||||
|
r := dataprovider.EventRule{
|
||||||
|
Name: ruleName,
|
||||||
|
Status: 1,
|
||||||
|
Trigger: dataprovider.EventTriggerIDPLogin,
|
||||||
|
Conditions: dataprovider.EventConditions{
|
||||||
|
IDPLoginEvent: 1,
|
||||||
|
Options: dataprovider.ConditionOptions{
|
||||||
|
Names: []dataprovider.ConditionPattern{
|
||||||
|
{
|
||||||
|
Pattern: "username",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Actions: []dataprovider.EventAction{
|
||||||
|
{
|
||||||
|
BaseEventAction: dataprovider.BaseEventAction{
|
||||||
|
Name: a.Name,
|
||||||
|
},
|
||||||
|
Options: dataprovider.EventActionOptions{
|
||||||
|
ExecuteSync: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
rule, _, err := httpdtest.AddEventRule(r, http.StatusCreated)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
rule.Status = 0
|
||||||
|
_, _, err = httpdtest.UpdateEventRule(rule, http.StatusOK)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = httpdtest.RemoveEventRule(rule, http.StatusOK)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = httpdtest.RemoveEventAction(action, http.StatusOK)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestEventActionValidation(t *testing.T) {
|
func TestEventActionValidation(t *testing.T) {
|
||||||
action := dataprovider.BaseEventAction{
|
action := dataprovider.BaseEventAction{
|
||||||
Name: "",
|
Name: "",
|
||||||
|
@ -2235,6 +2287,15 @@ func TestEventActionValidation(t *testing.T) {
|
||||||
_, resp, err = httpdtest.AddEventAction(action, http.StatusBadRequest)
|
_, resp, err = httpdtest.AddEventAction(action, http.StatusBadRequest)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, string(resp), "threshold must be greater than 0")
|
assert.Contains(t, string(resp), "threshold must be greater than 0")
|
||||||
|
action.Type = dataprovider.ActionTypeIDPAccountCheck
|
||||||
|
_, resp, err = httpdtest.AddEventAction(action, http.StatusBadRequest)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Contains(t, string(resp), "at least a template must be set")
|
||||||
|
action.Options.IDPConfig.TemplateAdmin = "{}"
|
||||||
|
action.Options.IDPConfig.Mode = 100
|
||||||
|
_, resp, err = httpdtest.AddEventAction(action, http.StatusBadRequest)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Contains(t, string(resp), "invalid account check mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEventRuleValidation(t *testing.T) {
|
func TestEventRuleValidation(t *testing.T) {
|
||||||
|
@ -2367,7 +2428,7 @@ func TestEventRuleValidation(t *testing.T) {
|
||||||
}
|
}
|
||||||
_, resp, err = httpdtest.AddEventRule(rule, http.StatusBadRequest)
|
_, resp, err = httpdtest.AddEventRule(rule, http.StatusBadRequest)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, string(resp), "event pre-upload requires at least a sync action")
|
assert.Contains(t, string(resp), "requires at least a sync action")
|
||||||
rule.Actions = []dataprovider.EventAction{
|
rule.Actions = []dataprovider.EventAction{
|
||||||
{
|
{
|
||||||
BaseEventAction: dataprovider.BaseEventAction{
|
BaseEventAction: dataprovider.BaseEventAction{
|
||||||
|
@ -2431,6 +2492,11 @@ func TestEventRuleValidation(t *testing.T) {
|
||||||
}
|
}
|
||||||
_, resp, err = httpdtest.AddEventRule(rule, http.StatusInternalServerError)
|
_, resp, err = httpdtest.AddEventRule(rule, http.StatusInternalServerError)
|
||||||
assert.NoError(t, err, string(resp))
|
assert.NoError(t, err, string(resp))
|
||||||
|
rule.Trigger = dataprovider.EventTriggerIDPLogin
|
||||||
|
rule.Conditions.IDPLoginEvent = 100
|
||||||
|
_, resp, err = httpdtest.AddEventRule(rule, http.StatusBadRequest)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Contains(t, string(resp), "invalid Identity Provider login event")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUserTransferLimits(t *testing.T) {
|
func TestUserTransferLimits(t *testing.T) {
|
||||||
|
@ -21532,6 +21598,26 @@ func TestWebEventAction(t *testing.T) {
|
||||||
assert.Equal(t, 0, actionGet.Options.CmdConfig.Timeout)
|
assert.Equal(t, 0, actionGet.Options.CmdConfig.Timeout)
|
||||||
assert.Len(t, actionGet.Options.CmdConfig.EnvVars, 0)
|
assert.Len(t, actionGet.Options.CmdConfig.EnvVars, 0)
|
||||||
|
|
||||||
|
action.Type = dataprovider.ActionTypeIDPAccountCheck
|
||||||
|
form.Set("type", fmt.Sprintf("%d", action.Type))
|
||||||
|
form.Set("idp_mode", "1")
|
||||||
|
form.Set("idp_user", `{"username":"user"}`)
|
||||||
|
form.Set("idp_admin", `{"username":"admin"}`)
|
||||||
|
form.Set("pwd_expiration_threshold", strconv.Itoa(action.Options.PwdExpirationConfig.Threshold))
|
||||||
|
req, err = http.NewRequest(http.MethodPost, path.Join(webAdminEventActionPath, action.Name),
|
||||||
|
bytes.NewBuffer([]byte(form.Encode())))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
setJWTCookieForReq(req, webToken)
|
||||||
|
rr = executeRequest(req)
|
||||||
|
checkResponseCode(t, http.StatusSeeOther, rr)
|
||||||
|
actionGet, _, err = httpdtest.GetEventActionByName(action.Name, http.StatusOK)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, action.Type, actionGet.Type)
|
||||||
|
assert.Equal(t, 1, actionGet.Options.IDPConfig.Mode)
|
||||||
|
assert.Contains(t, actionGet.Options.IDPConfig.TemplateUser, `"user"`)
|
||||||
|
assert.Contains(t, actionGet.Options.IDPConfig.TemplateAdmin, `"admin"`)
|
||||||
|
|
||||||
req, err = http.NewRequest(http.MethodDelete, path.Join(webAdminEventActionPath, action.Name), nil)
|
req, err = http.NewRequest(http.MethodDelete, path.Join(webAdminEventActionPath, action.Name), nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, apiToken)
|
setBearerForReq(req, apiToken)
|
||||||
|
@ -21785,6 +21871,36 @@ func TestWebEventRule(t *testing.T) {
|
||||||
assert.Equal(t, rule.Actions[0].Name, ruleGet.Actions[0].Name)
|
assert.Equal(t, rule.Actions[0].Name, ruleGet.Actions[0].Name)
|
||||||
assert.Equal(t, rule.Actions[0].Order, ruleGet.Actions[0].Order)
|
assert.Equal(t, rule.Actions[0].Order, ruleGet.Actions[0].Order)
|
||||||
}
|
}
|
||||||
|
rule.Trigger = dataprovider.EventTriggerIDPLogin
|
||||||
|
form.Set("trigger", fmt.Sprintf("%d", rule.Trigger))
|
||||||
|
form.Set("idp_login_event", "1")
|
||||||
|
req, err = http.NewRequest(http.MethodPost, path.Join(webAdminEventRulePath, rule.Name),
|
||||||
|
bytes.NewBuffer([]byte(form.Encode())))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
setJWTCookieForReq(req, webToken)
|
||||||
|
rr = executeRequest(req)
|
||||||
|
checkResponseCode(t, http.StatusSeeOther, rr)
|
||||||
|
// check the rule
|
||||||
|
ruleGet, _, err = httpdtest.GetEventRuleByName(rule.Name, http.StatusOK)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, rule.Trigger, ruleGet.Trigger)
|
||||||
|
assert.Equal(t, 1, ruleGet.Conditions.IDPLoginEvent)
|
||||||
|
|
||||||
|
form.Set("idp_login_event", "2")
|
||||||
|
req, err = http.NewRequest(http.MethodPost, path.Join(webAdminEventRulePath, rule.Name),
|
||||||
|
bytes.NewBuffer([]byte(form.Encode())))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
setJWTCookieForReq(req, webToken)
|
||||||
|
rr = executeRequest(req)
|
||||||
|
checkResponseCode(t, http.StatusSeeOther, rr)
|
||||||
|
// check the rule
|
||||||
|
ruleGet, _, err = httpdtest.GetEventRuleByName(rule.Name, http.StatusOK)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, rule.Trigger, ruleGet.Trigger)
|
||||||
|
assert.Equal(t, 2, ruleGet.Conditions.IDPLoginEvent)
|
||||||
|
|
||||||
// update a missing rule
|
// update a missing rule
|
||||||
req, err = http.NewRequest(http.MethodPost, path.Join(webAdminEventRulePath, rule.Name+"1"),
|
req, err = http.NewRequest(http.MethodPost, path.Join(webAdminEventRulePath, rule.Name+"1"),
|
||||||
bytes.NewBuffer([]byte(form.Encode())))
|
bytes.NewBuffer([]byte(form.Encode())))
|
||||||
|
|
|
@ -292,11 +292,11 @@ var (
|
||||||
type failingWriter struct {
|
type failingWriter struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *failingWriter) Write(p []byte) (n int, err error) {
|
func (r *failingWriter) Write(_ []byte) (n int, err error) {
|
||||||
return 0, errors.New("write error")
|
return 0, errors.New("write error")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *failingWriter) WriteHeader(statusCode int) {}
|
func (r *failingWriter) WriteHeader(_ int) {}
|
||||||
|
|
||||||
func (r *failingWriter) Header() http.Header {
|
func (r *failingWriter) Header() http.Header {
|
||||||
return make(http.Header)
|
return make(http.Header)
|
||||||
|
|
|
@ -410,47 +410,70 @@ func (t *oidcToken) refreshUser(r *http.Request) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *oidcToken) getUser(r *http.Request) error {
|
func (t *oidcToken) getUser(r *http.Request) error {
|
||||||
|
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
|
||||||
|
params := common.EventParams{
|
||||||
|
Name: t.Username,
|
||||||
|
IP: ipAddr,
|
||||||
|
Protocol: common.ProtocolOIDC,
|
||||||
|
Timestamp: time.Now().UnixNano(),
|
||||||
|
Status: 1,
|
||||||
|
}
|
||||||
if t.isAdmin() {
|
if t.isAdmin() {
|
||||||
admin, err := dataprovider.AdminExists(t.Username)
|
params.Event = common.IDPLoginAdmin
|
||||||
|
_, admin, err := common.HandleIDPLoginEvent(params, t.CustomFields)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := admin.CanLogin(util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil {
|
if admin == nil {
|
||||||
|
a, err := dataprovider.AdminExists(t.Username)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
admin = &a
|
||||||
|
}
|
||||||
|
if err := admin.CanLogin(ipAddr); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
t.Permissions = admin.Permissions
|
t.Permissions = admin.Permissions
|
||||||
t.TokenRole = admin.Role
|
t.TokenRole = admin.Role
|
||||||
t.HideUserPageSections = admin.Filters.Preferences.HideUserPageSections
|
t.HideUserPageSections = admin.Filters.Preferences.HideUserPageSections
|
||||||
dataprovider.UpdateAdminLastLogin(&admin)
|
dataprovider.UpdateAdminLastLogin(admin)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
|
params.Event = common.IDPLoginUser
|
||||||
user, err := dataprovider.GetUserAfterIDPAuth(t.Username, ipAddr, common.ProtocolOIDC, t.CustomFields)
|
user, _, err := common.HandleIDPLoginEvent(params, t.CustomFields)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if user == nil {
|
||||||
|
u, err := dataprovider.GetUserAfterIDPAuth(t.Username, ipAddr, common.ProtocolOIDC, t.CustomFields)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
user = &u
|
||||||
|
}
|
||||||
if err := common.Config.ExecutePostConnectHook(ipAddr, common.ProtocolOIDC); err != nil {
|
if err := common.Config.ExecutePostConnectHook(ipAddr, common.ProtocolOIDC); err != nil {
|
||||||
updateLoginMetrics(&user, dataprovider.LoginMethodIDP, ipAddr, err)
|
updateLoginMetrics(user, dataprovider.LoginMethodIDP, ipAddr, err)
|
||||||
return fmt.Errorf("access denied: %w", err)
|
return fmt.Errorf("access denied: %w", err)
|
||||||
}
|
}
|
||||||
if err := user.CheckLoginConditions(); err != nil {
|
if err := user.CheckLoginConditions(); err != nil {
|
||||||
updateLoginMetrics(&user, dataprovider.LoginMethodIDP, ipAddr, err)
|
updateLoginMetrics(user, dataprovider.LoginMethodIDP, ipAddr, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
connectionID := fmt.Sprintf("%v_%v", common.ProtocolOIDC, xid.New().String())
|
connectionID := fmt.Sprintf("%s_%s", common.ProtocolOIDC, xid.New().String())
|
||||||
if err := checkHTTPClientUser(&user, r, connectionID, true); err != nil {
|
if err := checkHTTPClientUser(user, r, connectionID, true); err != nil {
|
||||||
updateLoginMetrics(&user, dataprovider.LoginMethodIDP, ipAddr, err)
|
updateLoginMetrics(user, dataprovider.LoginMethodIDP, ipAddr, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer user.CloseFs() //nolint:errcheck
|
defer user.CloseFs() //nolint:errcheck
|
||||||
err = user.CheckFsRoot(connectionID)
|
err = user.CheckFsRoot(connectionID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Warn(logSender, connectionID, "unable to check fs root: %v", err)
|
logger.Warn(logSender, connectionID, "unable to check fs root: %v", err)
|
||||||
updateLoginMetrics(&user, dataprovider.LoginMethodIDP, ipAddr, common.ErrInternalFailure)
|
updateLoginMetrics(user, dataprovider.LoginMethodIDP, ipAddr, common.ErrInternalFailure)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
updateLoginMetrics(&user, dataprovider.LoginMethodIDP, ipAddr, nil)
|
updateLoginMetrics(user, dataprovider.LoginMethodIDP, ipAddr, nil)
|
||||||
dataprovider.UpdateLastLogin(&user)
|
dataprovider.UpdateLastLogin(user)
|
||||||
t.Permissions = user.Filters.WebClient
|
t.Permissions = user.Filters.WebClient
|
||||||
t.TokenRole = user.Role
|
t.TokenRole = user.Role
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -66,15 +66,15 @@ type mockOAuth2Config struct {
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *mockOAuth2Config) AuthCodeURL(state string, opts ...oauth2.AuthCodeOption) string {
|
func (c *mockOAuth2Config) AuthCodeURL(_ string, _ ...oauth2.AuthCodeOption) string {
|
||||||
return c.authCodeURL
|
return c.authCodeURL
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *mockOAuth2Config) Exchange(ctx context.Context, code string, opts ...oauth2.AuthCodeOption) (*oauth2.Token, error) {
|
func (c *mockOAuth2Config) Exchange(_ context.Context, _ string, _ ...oauth2.AuthCodeOption) (*oauth2.Token, error) {
|
||||||
return c.token, c.err
|
return c.token, c.err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *mockOAuth2Config) TokenSource(ctx context.Context, t *oauth2.Token) oauth2.TokenSource {
|
func (c *mockOAuth2Config) TokenSource(_ context.Context, _ *oauth2.Token) oauth2.TokenSource {
|
||||||
return c.tokenSource
|
return c.tokenSource
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ type mockOIDCVerifier struct {
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *mockOIDCVerifier) Verify(ctx context.Context, rawIDToken string) (*oidc.IDToken, error) {
|
func (v *mockOIDCVerifier) Verify(_ context.Context, _ string) (*oidc.IDToken, error) {
|
||||||
return v.token, v.err
|
return v.token, v.err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1130,6 +1130,180 @@ func TestMemoryOIDCManager(t *testing.T) {
|
||||||
require.Len(t, oidcMgr.tokens, 0)
|
require.Len(t, oidcMgr.tokens, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOIDCEvMgrIntegration(t *testing.T) {
|
||||||
|
providerConf := dataprovider.GetProviderConfig()
|
||||||
|
err := dataprovider.Close()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
newProviderConf := providerConf
|
||||||
|
newProviderConf.NamingRules = 5
|
||||||
|
err = dataprovider.Initialize(newProviderConf, configDir, true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
// add a special chars to check json replacer
|
||||||
|
username := `test_"oidc_eventmanager`
|
||||||
|
u := map[string]any{
|
||||||
|
"username": "{{Name}}",
|
||||||
|
"status": 1,
|
||||||
|
"home_dir": filepath.Join(os.TempDir(), "{{IDPFieldcustom1}}"),
|
||||||
|
"permissions": map[string][]string{
|
||||||
|
"/": {dataprovider.PermAny},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
userTmpl, err := json.Marshal(u)
|
||||||
|
require.NoError(t, err)
|
||||||
|
a := map[string]any{
|
||||||
|
"username": "{{Name}}",
|
||||||
|
"status": 1,
|
||||||
|
"permissions": []string{dataprovider.PermAdminAny},
|
||||||
|
}
|
||||||
|
adminTmpl, err := json.Marshal(a)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
action := &dataprovider.BaseEventAction{
|
||||||
|
Name: "a",
|
||||||
|
Type: dataprovider.ActionTypeIDPAccountCheck,
|
||||||
|
Options: dataprovider.BaseEventActionOptions{
|
||||||
|
IDPConfig: dataprovider.EventActionIDPAccountCheck{
|
||||||
|
Mode: 0,
|
||||||
|
TemplateUser: string(userTmpl),
|
||||||
|
TemplateAdmin: string(adminTmpl),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err = dataprovider.AddEventAction(action, "", "", "")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
rule := &dataprovider.EventRule{
|
||||||
|
Name: "r",
|
||||||
|
Status: 1,
|
||||||
|
Trigger: dataprovider.EventTriggerIDPLogin,
|
||||||
|
Conditions: dataprovider.EventConditions{
|
||||||
|
IDPLoginEvent: 0,
|
||||||
|
},
|
||||||
|
Actions: []dataprovider.EventAction{
|
||||||
|
{
|
||||||
|
BaseEventAction: dataprovider.BaseEventAction{
|
||||||
|
Name: action.Name,
|
||||||
|
},
|
||||||
|
Options: dataprovider.EventActionOptions{
|
||||||
|
ExecuteSync: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err = dataprovider.AddEventRule(rule, "", "", "")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
oidcMgr, ok := oidcMgr.(*memoryOIDCManager)
|
||||||
|
require.True(t, ok)
|
||||||
|
server := getTestOIDCServer()
|
||||||
|
server.binding.OIDC.ImplicitRoles = true
|
||||||
|
server.binding.OIDC.CustomFields = []string{"custom1", "custom2"}
|
||||||
|
err = server.binding.OIDC.initialize()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
server.initializeRouter()
|
||||||
|
// login a user with OIDC
|
||||||
|
_, err = dataprovider.UserExists(username, "")
|
||||||
|
assert.ErrorIs(t, err, util.ErrNotFound)
|
||||||
|
authReq := newOIDCPendingAuth(tokenAudienceWebClient)
|
||||||
|
oidcMgr.addPendingAuth(authReq)
|
||||||
|
token := &oauth2.Token{
|
||||||
|
AccessToken: "1234",
|
||||||
|
Expiry: time.Now().Add(5 * time.Minute),
|
||||||
|
}
|
||||||
|
token = token.WithExtra(map[string]any{
|
||||||
|
"id_token": "id_token_val",
|
||||||
|
})
|
||||||
|
server.binding.OIDC.oauth2Config = &mockOAuth2Config{
|
||||||
|
tokenSource: &mockTokenSource{},
|
||||||
|
authCodeURL: webOIDCRedirectPath,
|
||||||
|
token: token,
|
||||||
|
}
|
||||||
|
idToken := &oidc.IDToken{
|
||||||
|
Nonce: authReq.Nonce,
|
||||||
|
Expiry: time.Now().Add(5 * time.Minute),
|
||||||
|
}
|
||||||
|
setIDTokenClaims(idToken, []byte(`{"preferred_username":"`+util.JSONEscape(username)+`","custom1":"val1"}`))
|
||||||
|
server.binding.OIDC.verifier = &mockOIDCVerifier{
|
||||||
|
err: nil,
|
||||||
|
token: idToken,
|
||||||
|
}
|
||||||
|
rr := httptest.NewRecorder()
|
||||||
|
r, err := http.NewRequest(http.MethodGet, webOIDCRedirectPath+"?state="+authReq.State, nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
server.router.ServeHTTP(rr, r)
|
||||||
|
assert.Equal(t, http.StatusFound, rr.Code)
|
||||||
|
assert.Equal(t, webClientFilesPath, rr.Header().Get("Location"))
|
||||||
|
user, err := dataprovider.UserExists(username, "")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, filepath.Join(os.TempDir(), "val1"), user.GetHomeDir())
|
||||||
|
|
||||||
|
err = dataprovider.DeleteUser(username, "", "", "")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = os.RemoveAll(user.GetHomeDir())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
// login an admin with OIDC
|
||||||
|
_, err = dataprovider.AdminExists(username)
|
||||||
|
assert.ErrorIs(t, err, util.ErrNotFound)
|
||||||
|
authReq = newOIDCPendingAuth(tokenAudienceWebAdmin)
|
||||||
|
oidcMgr.addPendingAuth(authReq)
|
||||||
|
idToken = &oidc.IDToken{
|
||||||
|
Nonce: authReq.Nonce,
|
||||||
|
Expiry: time.Now().Add(5 * time.Minute),
|
||||||
|
}
|
||||||
|
setIDTokenClaims(idToken, []byte(`{"preferred_username":"`+util.JSONEscape(username)+`"}`))
|
||||||
|
server.binding.OIDC.verifier = &mockOIDCVerifier{
|
||||||
|
err: nil,
|
||||||
|
token: idToken,
|
||||||
|
}
|
||||||
|
rr = httptest.NewRecorder()
|
||||||
|
r, err = http.NewRequest(http.MethodGet, webOIDCRedirectPath+"?state="+authReq.State, nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
server.router.ServeHTTP(rr, r)
|
||||||
|
assert.Equal(t, http.StatusFound, rr.Code)
|
||||||
|
assert.Equal(t, webUsersPath, rr.Header().Get("Location"))
|
||||||
|
|
||||||
|
_, err = dataprovider.AdminExists(username)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = dataprovider.DeleteAdmin(username, "", "", "")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
// set invalid templates and try again
|
||||||
|
action.Options.IDPConfig.TemplateUser = `{}`
|
||||||
|
action.Options.IDPConfig.TemplateAdmin = `{}`
|
||||||
|
err = dataprovider.UpdateEventAction(action, "", "", "")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
for _, audience := range []string{tokenAudienceWebAdmin, tokenAudienceWebClient} {
|
||||||
|
authReq = newOIDCPendingAuth(audience)
|
||||||
|
oidcMgr.addPendingAuth(authReq)
|
||||||
|
idToken = &oidc.IDToken{
|
||||||
|
Nonce: authReq.Nonce,
|
||||||
|
Expiry: time.Now().Add(5 * time.Minute),
|
||||||
|
}
|
||||||
|
setIDTokenClaims(idToken, []byte(`{"preferred_username":"`+util.JSONEscape(username)+`"}`))
|
||||||
|
server.binding.OIDC.verifier = &mockOIDCVerifier{
|
||||||
|
err: nil,
|
||||||
|
token: idToken,
|
||||||
|
}
|
||||||
|
rr = httptest.NewRecorder()
|
||||||
|
r, err = http.NewRequest(http.MethodGet, webOIDCRedirectPath+"?state="+authReq.State, nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
server.router.ServeHTTP(rr, r)
|
||||||
|
assert.Equal(t, http.StatusFound, rr.Code)
|
||||||
|
}
|
||||||
|
for k := range oidcMgr.tokens {
|
||||||
|
oidcMgr.removeToken(k)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = dataprovider.DeleteEventRule(rule.Name, "", "", "")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = dataprovider.DeleteEventAction(action.Name, "", "", "")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = dataprovider.Close()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = dataprovider.Initialize(providerConf, configDir, true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestOIDCPreLoginHook(t *testing.T) {
|
func TestOIDCPreLoginHook(t *testing.T) {
|
||||||
if runtime.GOOS == osWindows {
|
if runtime.GOOS == osWindows {
|
||||||
t.Skip("this test is not available on Windows")
|
t.Skip("this test is not available on Windows")
|
||||||
|
|
|
@ -2280,6 +2280,10 @@ func getEventActionOptionsFromPostFields(r *http.Request) (dataprovider.BaseEven
|
||||||
if r.Form.Get("cmd_arguments") != "" {
|
if r.Form.Get("cmd_arguments") != "" {
|
||||||
cmdArgs = getSliceFromDelimitedValues(r.Form.Get("cmd_arguments"), ",")
|
cmdArgs = getSliceFromDelimitedValues(r.Form.Get("cmd_arguments"), ",")
|
||||||
}
|
}
|
||||||
|
idpMode := 0
|
||||||
|
if r.Form.Get("idp_mode") == "1" {
|
||||||
|
idpMode = 1
|
||||||
|
}
|
||||||
options := dataprovider.BaseEventActionOptions{
|
options := dataprovider.BaseEventActionOptions{
|
||||||
HTTPConfig: dataprovider.EventActionHTTPConfig{
|
HTTPConfig: dataprovider.EventActionHTTPConfig{
|
||||||
Endpoint: r.Form.Get("http_endpoint"),
|
Endpoint: r.Form.Get("http_endpoint"),
|
||||||
|
@ -2323,6 +2327,11 @@ func getEventActionOptionsFromPostFields(r *http.Request) (dataprovider.BaseEven
|
||||||
PwdExpirationConfig: dataprovider.EventActionPasswordExpiration{
|
PwdExpirationConfig: dataprovider.EventActionPasswordExpiration{
|
||||||
Threshold: pwdExpirationThreshold,
|
Threshold: pwdExpirationThreshold,
|
||||||
},
|
},
|
||||||
|
IDPConfig: dataprovider.EventActionIDPAccountCheck{
|
||||||
|
Mode: idpMode,
|
||||||
|
TemplateUser: strings.TrimSpace(r.Form.Get("idp_user")),
|
||||||
|
TemplateAdmin: strings.TrimSpace(r.Form.Get("idp_admin")),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
return options, nil
|
return options, nil
|
||||||
}
|
}
|
||||||
|
@ -2349,6 +2358,17 @@ func getEventActionFromPostFields(r *http.Request) (dataprovider.BaseEventAction
|
||||||
return action, nil
|
return action, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getIDPLoginEventFromPostField(r *http.Request) int {
|
||||||
|
switch r.Form.Get("idp_login_event") {
|
||||||
|
case "1":
|
||||||
|
return 1
|
||||||
|
case "2":
|
||||||
|
return 2
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func getEventRuleConditionsFromPostFields(r *http.Request) (dataprovider.EventConditions, error) {
|
func getEventRuleConditionsFromPostFields(r *http.Request) (dataprovider.EventConditions, error) {
|
||||||
var schedules []dataprovider.Schedule
|
var schedules []dataprovider.Schedule
|
||||||
var names, groupNames, roleNames, fsPaths []dataprovider.ConditionPattern
|
var names, groupNames, roleNames, fsPaths []dataprovider.ConditionPattern
|
||||||
|
@ -2424,6 +2444,7 @@ func getEventRuleConditionsFromPostFields(r *http.Request) (dataprovider.EventCo
|
||||||
conditions := dataprovider.EventConditions{
|
conditions := dataprovider.EventConditions{
|
||||||
FsEvents: r.Form["fs_events"],
|
FsEvents: r.Form["fs_events"],
|
||||||
ProviderEvents: r.Form["provider_events"],
|
ProviderEvents: r.Form["provider_events"],
|
||||||
|
IDPLoginEvent: getIDPLoginEventFromPostField(r),
|
||||||
Schedules: schedules,
|
Schedules: schedules,
|
||||||
Options: dataprovider.ConditionOptions{
|
Options: dataprovider.ConditionOptions{
|
||||||
Names: names,
|
Names: names,
|
||||||
|
|
|
@ -1596,6 +1596,9 @@ func checkEventAction(expected, actual dataprovider.BaseEventAction) error {
|
||||||
if expected.Options.PwdExpirationConfig.Threshold != actual.Options.PwdExpirationConfig.Threshold {
|
if expected.Options.PwdExpirationConfig.Threshold != actual.Options.PwdExpirationConfig.Threshold {
|
||||||
return errors.New("password expiration threshold mismatch")
|
return errors.New("password expiration threshold mismatch")
|
||||||
}
|
}
|
||||||
|
if err := compareEventActionIDPConfigFields(expected.Options.IDPConfig, actual.Options.IDPConfig); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if err := compareEventActionCmdConfigFields(expected.Options.CmdConfig, actual.Options.CmdConfig); err != nil {
|
if err := compareEventActionCmdConfigFields(expected.Options.CmdConfig, actual.Options.CmdConfig); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1707,6 +1710,9 @@ func checkEventConditions(expected, actual dataprovider.EventConditions) error {
|
||||||
if err := checkEventConditionOptions(expected.Options, actual.Options); err != nil {
|
if err := checkEventConditionOptions(expected.Options, actual.Options); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if expected.IDPLoginEvent != actual.IDPLoginEvent {
|
||||||
|
return errors.New("IDP login event mismatch")
|
||||||
|
}
|
||||||
|
|
||||||
return checkEventSchedules(expected.Schedules, actual.Schedules)
|
return checkEventSchedules(expected.Schedules, actual.Schedules)
|
||||||
}
|
}
|
||||||
|
@ -2707,6 +2713,19 @@ func compareEventActionFsConfigFields(expected, actual dataprovider.EventActionF
|
||||||
return compareEventActionFsCompressFields(expected.Compress, actual.Compress)
|
return compareEventActionFsCompressFields(expected.Compress, actual.Compress)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func compareEventActionIDPConfigFields(expected, actual dataprovider.EventActionIDPAccountCheck) error {
|
||||||
|
if expected.Mode != actual.Mode {
|
||||||
|
return errors.New("mode mismatch")
|
||||||
|
}
|
||||||
|
if expected.TemplateAdmin != actual.TemplateAdmin {
|
||||||
|
return errors.New("admin template mismatch")
|
||||||
|
}
|
||||||
|
if expected.TemplateUser != actual.TemplateUser {
|
||||||
|
return errors.New("user template mismatch")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func compareEventActionCmdConfigFields(expected, actual dataprovider.EventActionCommandConfig) error {
|
func compareEventActionCmdConfigFields(expected, actual dataprovider.EventActionCommandConfig) error {
|
||||||
if expected.Cmd != actual.Cmd {
|
if expected.Cmd != actual.Cmd {
|
||||||
return errors.New("command mismatch")
|
return errors.New("command mismatch")
|
||||||
|
|
|
@ -38,7 +38,7 @@ func init() {
|
||||||
RegisterSecretProvider(sdkkms.SchemeBuiltin, sdkkms.SecretStatusAES256GCM, newBuiltinSecret)
|
RegisterSecretProvider(sdkkms.SchemeBuiltin, sdkkms.SecretStatusAES256GCM, newBuiltinSecret)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newBuiltinSecret(base BaseSecret, url, masterKey string) SecretProvider {
|
func newBuiltinSecret(base BaseSecret, _, _ string) SecretProvider {
|
||||||
return &builtinSecret{
|
return &builtinSecret{
|
||||||
BaseSecret: base,
|
BaseSecret: base,
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ type localSecret struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLocalSecret returns a SecretProvider that use a locally provided symmetric key
|
// NewLocalSecret returns a SecretProvider that use a locally provided symmetric key
|
||||||
func NewLocalSecret(base BaseSecret, url, masterKey string) SecretProvider {
|
func NewLocalSecret(base BaseSecret, _, masterKey string) SecretProvider {
|
||||||
return &localSecret{
|
return &localSecret{
|
||||||
BaseSecret: base,
|
BaseSecret: base,
|
||||||
masterKey: masterKey,
|
masterKey: masterKey,
|
||||||
|
|
|
@ -81,11 +81,11 @@ func (l *HCLogAdapter) Named(name string) hclog.Logger {
|
||||||
}
|
}
|
||||||
|
|
||||||
// StandardLogger returns a value that conforms to the stdlib log.Logger interface
|
// StandardLogger returns a value that conforms to the stdlib log.Logger interface
|
||||||
func (l *HCLogAdapter) StandardLogger(opts *hclog.StandardLoggerOptions) *log.Logger {
|
func (l *HCLogAdapter) StandardLogger(_ *hclog.StandardLoggerOptions) *log.Logger {
|
||||||
return log.New(&StdLoggerWrapper{Sender: l.Name()}, "", 0)
|
return log.New(&StdLoggerWrapper{Sender: l.Name()}, "", 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// StandardWriter returns a value that conforms to io.Writer, which can be passed into log.SetOutput()
|
// StandardWriter returns a value that conforms to io.Writer, which can be passed into log.SetOutput()
|
||||||
func (l *HCLogAdapter) StandardWriter(opts *hclog.StandardLoggerOptions) io.Writer {
|
func (l *HCLogAdapter) StandardWriter(_ *hclog.StandardLoggerOptions) io.Writer {
|
||||||
return &StdLoggerWrapper{Sender: l.Name()}
|
return &StdLoggerWrapper{Sender: l.Name()}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ func (l *StructuredLogger) NewLogEntry(r *http.Request) middleware.LogEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write logs a new entry at the end of the HTTP request
|
// Write logs a new entry at the end of the HTTP request
|
||||||
func (l *StructuredLoggerEntry) Write(status, bytes int, header http.Header, elapsed time.Duration, extra any) {
|
func (l *StructuredLoggerEntry) Write(status, bytes int, _ http.Header, elapsed time.Duration, _ any) {
|
||||||
metric.HTTPRequestServed(status)
|
metric.HTTPRequestServed(status)
|
||||||
l.Logger.Info().
|
l.Logger.Info().
|
||||||
Timestamp().
|
Timestamp().
|
||||||
|
|
|
@ -338,7 +338,7 @@ func (m *Manager) SetModificationTime(storageID, objectPath string, mTime int64)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetModificationTime returns the modification time for the specified path
|
// GetModificationTime returns the modification time for the specified path
|
||||||
func (m *Manager) GetModificationTime(storageID, objectPath string, isDir bool) (int64, error) {
|
func (m *Manager) GetModificationTime(storageID, objectPath string, _ bool) (int64, error) {
|
||||||
if !m.hasMetadater {
|
if !m.hasMetadater {
|
||||||
return 0, ErrNoMetadater
|
return 0, ErrNoMetadater
|
||||||
}
|
}
|
||||||
|
|
|
@ -351,7 +351,7 @@ func (s *Service) LoadInitialData() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) restoreDump(dump *dataprovider.BackupData) error {
|
func (s *Service) restoreDump(dump *dataprovider.BackupData) error {
|
||||||
err := httpd.RestoreConfigs(dump.Configs, s.LoadDataFrom, s.LoadDataMode, dataprovider.ActionExecutorSystem, "", "")
|
err := httpd.RestoreConfigs(dump.Configs, s.LoadDataMode, dataprovider.ActionExecutorSystem, "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to restore configs from file %q: %v", s.LoadDataFrom, err)
|
return fmt.Errorf("unable to restore configs from file %q: %v", s.LoadDataFrom, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,7 @@ func (c *MockChannel) CloseWrite() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MockChannel) SendRequest(name string, wantReply bool, payload []byte) (bool, error) {
|
func (c *MockChannel) SendRequest(_ string, _ bool, _ []byte) (bool, error) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ func (fs MockOsFs) Lstat(name string) (os.FileInfo, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove removes the named file or (empty) directory.
|
// Remove removes the named file or (empty) directory.
|
||||||
func (fs MockOsFs) Remove(name string, isDir bool) error {
|
func (fs MockOsFs) Remove(name string, _ bool) error {
|
||||||
if fs.err != nil {
|
if fs.err != nil {
|
||||||
return fs.err
|
return fs.err
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ type failingReader struct {
|
||||||
errRead error
|
errRead error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *failingReader) ReadAt(p []byte, off int64) (n int, err error) {
|
func (r *failingReader) ReadAt(_ []byte, _ int64) (n int, err error) {
|
||||||
return 0, r.errRead
|
return 0, r.errRead
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/drakkan/sftpgo/v2/internal/dataprovider"
|
"github.com/drakkan/sftpgo/v2/internal/dataprovider"
|
||||||
"github.com/drakkan/sftpgo/v2/internal/logger"
|
"github.com/drakkan/sftpgo/v2/internal/logger"
|
||||||
"github.com/drakkan/sftpgo/v2/internal/util"
|
"github.com/drakkan/sftpgo/v2/internal/util"
|
||||||
|
"github.com/drakkan/sftpgo/v2/internal/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -287,7 +288,9 @@ func (c *Config) getMailClientOptions() []mail.Option {
|
||||||
|
|
||||||
func (c *Config) getSMTPClientAndMsg(to []string, subject, body string, contentType EmailContentType,
|
func (c *Config) getSMTPClientAndMsg(to []string, subject, body string, contentType EmailContentType,
|
||||||
attachments ...*mail.File) (*mail.Client, *mail.Msg, error) {
|
attachments ...*mail.File) (*mail.Client, *mail.Msg, error) {
|
||||||
|
version := version.Get()
|
||||||
msg := mail.NewMsg()
|
msg := mail.NewMsg()
|
||||||
|
msg.SetUserAgent(fmt.Sprintf("SFTPGo-%s-%s", version.Version, version.CommitHash))
|
||||||
|
|
||||||
var from string
|
var from string
|
||||||
if c.From != "" {
|
if c.From != "" {
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"encoding/json"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -589,7 +590,7 @@ func HTTPListenAndServe(srv *http.Server, address string, port int, isTLS bool,
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info(logSender, "", "server listener registered, address: %v TLS enabled: %v", listener.Addr().String(), isTLS)
|
logger.Info(logSender, "", "server listener registered, address: %s TLS enabled: %t", listener.Addr().String(), isTLS)
|
||||||
|
|
||||||
defer listener.Close()
|
defer listener.Close()
|
||||||
|
|
||||||
|
@ -834,3 +835,15 @@ func GetLastIPForPrefix(p netip.Prefix) netip.Addr {
|
||||||
}
|
}
|
||||||
return netip.AddrFrom16(a16) // doesn't unmap
|
return netip.AddrFrom16(a16) // doesn't unmap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JSONEscape returns the JSON escaped format for the input string
|
||||||
|
func JSONEscape(val string) string {
|
||||||
|
if val == "" {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
b, err := json.Marshal(val)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return string(b[1 : len(b)-1])
|
||||||
|
}
|
||||||
|
|
|
@ -326,27 +326,27 @@ func (fs *AzureBlobFs) Mkdir(name string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Symlink creates source as a symbolic link to target.
|
// Symlink creates source as a symbolic link to target.
|
||||||
func (*AzureBlobFs) Symlink(source, target string) error {
|
func (*AzureBlobFs) Symlink(_, _ string) error {
|
||||||
return ErrVfsUnsupported
|
return ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// Readlink returns the destination of the named symbolic link
|
// Readlink returns the destination of the named symbolic link
|
||||||
func (*AzureBlobFs) Readlink(name string) (string, error) {
|
func (*AzureBlobFs) Readlink(_ string) (string, error) {
|
||||||
return "", ErrVfsUnsupported
|
return "", ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chown changes the numeric uid and gid of the named file.
|
// Chown changes the numeric uid and gid of the named file.
|
||||||
func (*AzureBlobFs) Chown(name string, uid int, gid int) error {
|
func (*AzureBlobFs) Chown(_ string, _ int, _ int) error {
|
||||||
return ErrVfsUnsupported
|
return ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chmod changes the mode of the named file to mode.
|
// Chmod changes the mode of the named file to mode.
|
||||||
func (*AzureBlobFs) Chmod(name string, mode os.FileMode) error {
|
func (*AzureBlobFs) Chmod(_ string, _ os.FileMode) error {
|
||||||
return ErrVfsUnsupported
|
return ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chtimes changes the access and modification times of the named file.
|
// Chtimes changes the access and modification times of the named file.
|
||||||
func (fs *AzureBlobFs) Chtimes(name string, atime, mtime time.Time, isUploading bool) error {
|
func (fs *AzureBlobFs) Chtimes(name string, _, mtime time.Time, isUploading bool) error {
|
||||||
if !plugin.Handler.HasMetadater() {
|
if !plugin.Handler.HasMetadater() {
|
||||||
return ErrVfsUnsupported
|
return ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
@ -367,7 +367,7 @@ func (fs *AzureBlobFs) Chtimes(name string, atime, mtime time.Time, isUploading
|
||||||
// Truncate changes the size of the named file.
|
// Truncate changes the size of the named file.
|
||||||
// Truncate by path is not supported, while truncating an opened
|
// Truncate by path is not supported, while truncating an opened
|
||||||
// file is handled inside base transfer
|
// file is handled inside base transfer
|
||||||
func (*AzureBlobFs) Truncate(name string, size int64) error {
|
func (*AzureBlobFs) Truncate(_ string, _ int64) error {
|
||||||
return ErrVfsUnsupported
|
return ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -609,7 +609,7 @@ func (fs *AzureBlobFs) GetDirSize(dirname string) (int, int64, error) {
|
||||||
|
|
||||||
// GetAtomicUploadPath returns the path to use for an atomic upload.
|
// GetAtomicUploadPath returns the path to use for an atomic upload.
|
||||||
// Azure Blob Storage uploads are already atomic, we never call this method
|
// Azure Blob Storage uploads are already atomic, we never call this method
|
||||||
func (*AzureBlobFs) GetAtomicUploadPath(name string) string {
|
func (*AzureBlobFs) GetAtomicUploadPath(_ string) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -702,7 +702,7 @@ func (fs *AzureBlobFs) ResolvePath(virtualPath string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CopyFile implements the FsFileCopier interface
|
// CopyFile implements the FsFileCopier interface
|
||||||
func (fs *AzureBlobFs) CopyFile(source, target string, srcSize int64) error {
|
func (fs *AzureBlobFs) CopyFile(source, target string, _ int64) error {
|
||||||
return fs.copyFileInternal(source, target)
|
return fs.copyFileInternal(source, target)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -731,7 +731,7 @@ func (*AzureBlobFs) Close() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAvailableDiskSize returns the available size for the specified path
|
// GetAvailableDiskSize returns the available size for the specified path
|
||||||
func (*AzureBlobFs) GetAvailableDiskSize(dirName string) (*sftp.StatVFS, error) {
|
func (*AzureBlobFs) GetAvailableDiskSize(_ string) (*sftp.StatVFS, error) {
|
||||||
return nil, ErrStorageSizeUnavailable
|
return nil, ErrStorageSizeUnavailable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -206,7 +206,7 @@ func (fs *CryptFs) Create(name string, flag int) (File, *PipeWriter, func(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Truncate changes the size of the named file
|
// Truncate changes the size of the named file
|
||||||
func (*CryptFs) Truncate(name string, size int64) error {
|
func (*CryptFs) Truncate(_ string, _ int64) error {
|
||||||
return ErrVfsUnsupported
|
return ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -284,27 +284,27 @@ func (fs *GCSFs) Mkdir(name string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Symlink creates source as a symbolic link to target.
|
// Symlink creates source as a symbolic link to target.
|
||||||
func (*GCSFs) Symlink(source, target string) error {
|
func (*GCSFs) Symlink(_, _ string) error {
|
||||||
return ErrVfsUnsupported
|
return ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// Readlink returns the destination of the named symbolic link
|
// Readlink returns the destination of the named symbolic link
|
||||||
func (*GCSFs) Readlink(name string) (string, error) {
|
func (*GCSFs) Readlink(_ string) (string, error) {
|
||||||
return "", ErrVfsUnsupported
|
return "", ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chown changes the numeric uid and gid of the named file.
|
// Chown changes the numeric uid and gid of the named file.
|
||||||
func (*GCSFs) Chown(name string, uid int, gid int) error {
|
func (*GCSFs) Chown(_ string, _ int, _ int) error {
|
||||||
return ErrVfsUnsupported
|
return ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chmod changes the mode of the named file to mode.
|
// Chmod changes the mode of the named file to mode.
|
||||||
func (*GCSFs) Chmod(name string, mode os.FileMode) error {
|
func (*GCSFs) Chmod(_ string, _ os.FileMode) error {
|
||||||
return ErrVfsUnsupported
|
return ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chtimes changes the access and modification times of the named file.
|
// Chtimes changes the access and modification times of the named file.
|
||||||
func (fs *GCSFs) Chtimes(name string, atime, mtime time.Time, isUploading bool) error {
|
func (fs *GCSFs) Chtimes(name string, _, mtime time.Time, isUploading bool) error {
|
||||||
if !plugin.Handler.HasMetadater() {
|
if !plugin.Handler.HasMetadater() {
|
||||||
return ErrVfsUnsupported
|
return ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
@ -325,7 +325,7 @@ func (fs *GCSFs) Chtimes(name string, atime, mtime time.Time, isUploading bool)
|
||||||
// Truncate changes the size of the named file.
|
// Truncate changes the size of the named file.
|
||||||
// Truncate by path is not supported, while truncating an opened
|
// Truncate by path is not supported, while truncating an opened
|
||||||
// file is handled inside base transfer
|
// file is handled inside base transfer
|
||||||
func (*GCSFs) Truncate(name string, size int64) error {
|
func (*GCSFs) Truncate(_ string, _ int64) error {
|
||||||
return ErrVfsUnsupported
|
return ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -587,7 +587,7 @@ func (fs *GCSFs) GetDirSize(dirname string) (int, int64, error) {
|
||||||
|
|
||||||
// GetAtomicUploadPath returns the path to use for an atomic upload.
|
// GetAtomicUploadPath returns the path to use for an atomic upload.
|
||||||
// GCS uploads are already atomic, we never call this method for GCS
|
// GCS uploads are already atomic, we never call this method for GCS
|
||||||
func (*GCSFs) GetAtomicUploadPath(name string) string {
|
func (*GCSFs) GetAtomicUploadPath(_ string) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -688,7 +688,7 @@ func (fs *GCSFs) ResolvePath(virtualPath string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CopyFile implements the FsFileCopier interface
|
// CopyFile implements the FsFileCopier interface
|
||||||
func (fs *GCSFs) CopyFile(source, target string, srcSize int64) error {
|
func (fs *GCSFs) CopyFile(source, target string, _ int64) error {
|
||||||
return fs.copyFileInternal(source, target)
|
return fs.copyFileInternal(source, target)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -904,7 +904,7 @@ func (fs *GCSFs) Close() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAvailableDiskSize returns the available size for the specified path
|
// GetAvailableDiskSize returns the available size for the specified path
|
||||||
func (*GCSFs) GetAvailableDiskSize(dirName string) (*sftp.StatVFS, error) {
|
func (*GCSFs) GetAvailableDiskSize(_ string) (*sftp.StatVFS, error) {
|
||||||
return nil, ErrStorageSizeUnavailable
|
return nil, ErrStorageSizeUnavailable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -385,7 +385,7 @@ func (fs *HTTPFs) Rename(source, target string) (int, int64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove removes the named file or (empty) directory.
|
// Remove removes the named file or (empty) directory.
|
||||||
func (fs *HTTPFs) Remove(name string, isDir bool) error {
|
func (fs *HTTPFs) Remove(name string, _ bool) error {
|
||||||
ctx, cancelFn := context.WithDeadline(context.Background(), time.Now().Add(fs.ctxTimeout))
|
ctx, cancelFn := context.WithDeadline(context.Background(), time.Now().Add(fs.ctxTimeout))
|
||||||
defer cancelFn()
|
defer cancelFn()
|
||||||
|
|
||||||
|
@ -411,17 +411,17 @@ func (fs *HTTPFs) Mkdir(name string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Symlink creates source as a symbolic link to target.
|
// Symlink creates source as a symbolic link to target.
|
||||||
func (*HTTPFs) Symlink(source, target string) error {
|
func (*HTTPFs) Symlink(_, _ string) error {
|
||||||
return ErrVfsUnsupported
|
return ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// Readlink returns the destination of the named symbolic link
|
// Readlink returns the destination of the named symbolic link
|
||||||
func (*HTTPFs) Readlink(name string) (string, error) {
|
func (*HTTPFs) Readlink(_ string) (string, error) {
|
||||||
return "", ErrVfsUnsupported
|
return "", ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chown changes the numeric uid and gid of the named file.
|
// Chown changes the numeric uid and gid of the named file.
|
||||||
func (fs *HTTPFs) Chown(name string, uid int, gid int) error {
|
func (fs *HTTPFs) Chown(_ string, _ int, _ int) error {
|
||||||
return ErrVfsUnsupported
|
return ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,7 +440,7 @@ func (fs *HTTPFs) Chmod(name string, mode os.FileMode) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chtimes changes the access and modification times of the named file.
|
// Chtimes changes the access and modification times of the named file.
|
||||||
func (fs *HTTPFs) Chtimes(name string, atime, mtime time.Time, isUploading bool) error {
|
func (fs *HTTPFs) Chtimes(name string, atime, mtime time.Time, _ bool) error {
|
||||||
ctx, cancelFn := context.WithDeadline(context.Background(), time.Now().Add(fs.ctxTimeout))
|
ctx, cancelFn := context.WithDeadline(context.Background(), time.Now().Add(fs.ctxTimeout))
|
||||||
defer cancelFn()
|
defer cancelFn()
|
||||||
|
|
||||||
|
@ -562,7 +562,7 @@ func (fs *HTTPFs) GetDirSize(dirname string) (int, int64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAtomicUploadPath returns the path to use for an atomic upload.
|
// GetAtomicUploadPath returns the path to use for an atomic upload.
|
||||||
func (*HTTPFs) GetAtomicUploadPath(name string) string {
|
func (*HTTPFs) GetAtomicUploadPath(_ string) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,7 +140,7 @@ func (fs *OsFs) Rename(source, target string) (int, int64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove removes the named file or (empty) directory.
|
// Remove removes the named file or (empty) directory.
|
||||||
func (*OsFs) Remove(name string, isDir bool) error {
|
func (*OsFs) Remove(name string, _ bool) error {
|
||||||
return os.Remove(name)
|
return os.Remove(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,7 +181,7 @@ func (*OsFs) Chmod(name string, mode os.FileMode) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chtimes changes the access and modification times of the named file
|
// Chtimes changes the access and modification times of the named file
|
||||||
func (*OsFs) Chtimes(name string, atime, mtime time.Time, isUploading bool) error {
|
func (*OsFs) Chtimes(name string, atime, mtime time.Time, _ bool) error {
|
||||||
return os.Chtimes(name, atime, mtime)
|
return os.Chtimes(name, atime, mtime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -337,27 +337,27 @@ func (fs *S3Fs) Mkdir(name string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Symlink creates source as a symbolic link to target.
|
// Symlink creates source as a symbolic link to target.
|
||||||
func (*S3Fs) Symlink(source, target string) error {
|
func (*S3Fs) Symlink(_, _ string) error {
|
||||||
return ErrVfsUnsupported
|
return ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// Readlink returns the destination of the named symbolic link
|
// Readlink returns the destination of the named symbolic link
|
||||||
func (*S3Fs) Readlink(name string) (string, error) {
|
func (*S3Fs) Readlink(_ string) (string, error) {
|
||||||
return "", ErrVfsUnsupported
|
return "", ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chown changes the numeric uid and gid of the named file.
|
// Chown changes the numeric uid and gid of the named file.
|
||||||
func (*S3Fs) Chown(name string, uid int, gid int) error {
|
func (*S3Fs) Chown(_ string, _ int, _ int) error {
|
||||||
return ErrVfsUnsupported
|
return ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chmod changes the mode of the named file to mode.
|
// Chmod changes the mode of the named file to mode.
|
||||||
func (*S3Fs) Chmod(name string, mode os.FileMode) error {
|
func (*S3Fs) Chmod(_ string, _ os.FileMode) error {
|
||||||
return ErrVfsUnsupported
|
return ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chtimes changes the access and modification times of the named file.
|
// Chtimes changes the access and modification times of the named file.
|
||||||
func (fs *S3Fs) Chtimes(name string, atime, mtime time.Time, isUploading bool) error {
|
func (fs *S3Fs) Chtimes(name string, _, mtime time.Time, isUploading bool) error {
|
||||||
if !plugin.Handler.HasMetadater() {
|
if !plugin.Handler.HasMetadater() {
|
||||||
return ErrVfsUnsupported
|
return ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
@ -377,7 +377,7 @@ func (fs *S3Fs) Chtimes(name string, atime, mtime time.Time, isUploading bool) e
|
||||||
// Truncate changes the size of the named file.
|
// Truncate changes the size of the named file.
|
||||||
// Truncate by path is not supported, while truncating an opened
|
// Truncate by path is not supported, while truncating an opened
|
||||||
// file is handled inside base transfer
|
// file is handled inside base transfer
|
||||||
func (*S3Fs) Truncate(name string, size int64) error {
|
func (*S3Fs) Truncate(_ string, _ int64) error {
|
||||||
return ErrVfsUnsupported
|
return ErrVfsUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -595,7 +595,7 @@ func (fs *S3Fs) GetDirSize(dirname string) (int, int64, error) {
|
||||||
|
|
||||||
// GetAtomicUploadPath returns the path to use for an atomic upload.
|
// GetAtomicUploadPath returns the path to use for an atomic upload.
|
||||||
// S3 uploads are already atomic, we never call this method for S3
|
// S3 uploads are already atomic, we never call this method for S3
|
||||||
func (*S3Fs) GetAtomicUploadPath(name string) string {
|
func (*S3Fs) GetAtomicUploadPath(_ string) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1009,7 +1009,7 @@ func (*S3Fs) Close() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAvailableDiskSize returns the available size for the specified path
|
// GetAvailableDiskSize returns the available size for the specified path
|
||||||
func (*S3Fs) GetAvailableDiskSize(dirName string) (*sftp.StatVFS, error) {
|
func (*S3Fs) GetAvailableDiskSize(_ string) (*sftp.StatVFS, error) {
|
||||||
return nil, ErrStorageSizeUnavailable
|
return nil, ErrStorageSizeUnavailable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -510,7 +510,7 @@ func (fs *SFTPFs) Chmod(name string, mode os.FileMode) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chtimes changes the access and modification times of the named file.
|
// Chtimes changes the access and modification times of the named file.
|
||||||
func (fs *SFTPFs) Chtimes(name string, atime, mtime time.Time, isUploading bool) error {
|
func (fs *SFTPFs) Chtimes(name string, atime, mtime time.Time, _ bool) error {
|
||||||
client, err := fs.conn.getClient()
|
client, err := fs.conn.getClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -27,6 +27,6 @@ func isCrossDeviceError(err error) bool {
|
||||||
return errors.Is(err, unix.EXDEV)
|
return errors.Is(err, unix.EXDEV)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isInvalidNameError(err error) bool {
|
func isInvalidNameError(_ error) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ type webDavFileInfo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContentType implements webdav.ContentTyper interface
|
// ContentType implements webdav.ContentTyper interface
|
||||||
func (fi *webDavFileInfo) ContentType(ctx context.Context) (string, error) {
|
func (fi *webDavFileInfo) ContentType(_ context.Context) (string, error) {
|
||||||
extension := path.Ext(fi.virtualPath)
|
extension := path.Ext(fi.virtualPath)
|
||||||
if ctype, ok := customMimeTypeMapping[extension]; ok {
|
if ctype, ok := customMimeTypeMapping[extension]; ok {
|
||||||
return ctype, nil
|
return ctype, nil
|
||||||
|
@ -107,7 +107,7 @@ func (fi *webDavFileInfo) ContentType(ctx context.Context) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Readdir reads directory entries from the handle
|
// Readdir reads directory entries from the handle
|
||||||
func (f *webDavFile) Readdir(count int) ([]os.FileInfo, error) {
|
func (f *webDavFile) Readdir(_ int) ([]os.FileInfo, error) {
|
||||||
if !f.Connection.User.HasPerm(dataprovider.PermListItems, f.GetVirtualPath()) {
|
if !f.Connection.User.HasPerm(dataprovider.PermListItems, f.GetVirtualPath()) {
|
||||||
return nil, f.Connection.GetPermissionDeniedError()
|
return nil, f.Connection.GetPermissionDeniedError()
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ func (c *Connection) GetCommand() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mkdir creates a directory using the connection filesystem
|
// Mkdir creates a directory using the connection filesystem
|
||||||
func (c *Connection) Mkdir(ctx context.Context, name string, perm os.FileMode) error {
|
func (c *Connection) Mkdir(_ context.Context, name string, _ os.FileMode) error {
|
||||||
c.UpdateLastActivity()
|
c.UpdateLastActivity()
|
||||||
|
|
||||||
name = util.CleanPath(name)
|
name = util.CleanPath(name)
|
||||||
|
@ -93,7 +93,7 @@ func (c *Connection) Mkdir(ctx context.Context, name string, perm os.FileMode) e
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rename renames a file or a directory
|
// Rename renames a file or a directory
|
||||||
func (c *Connection) Rename(ctx context.Context, oldName, newName string) error {
|
func (c *Connection) Rename(_ context.Context, oldName, newName string) error {
|
||||||
c.UpdateLastActivity()
|
c.UpdateLastActivity()
|
||||||
|
|
||||||
oldName = util.CleanPath(oldName)
|
oldName = util.CleanPath(oldName)
|
||||||
|
@ -116,7 +116,7 @@ func (c *Connection) Rename(ctx context.Context, oldName, newName string) error
|
||||||
|
|
||||||
// Stat returns a FileInfo describing the named file/directory, or an error,
|
// Stat returns a FileInfo describing the named file/directory, or an error,
|
||||||
// if any happens
|
// if any happens
|
||||||
func (c *Connection) Stat(ctx context.Context, name string) (os.FileInfo, error) {
|
func (c *Connection) Stat(_ context.Context, name string) (os.FileInfo, error) {
|
||||||
c.UpdateLastActivity()
|
c.UpdateLastActivity()
|
||||||
|
|
||||||
name = util.CleanPath(name)
|
name = util.CleanPath(name)
|
||||||
|
@ -133,7 +133,7 @@ func (c *Connection) Stat(ctx context.Context, name string) (os.FileInfo, error)
|
||||||
|
|
||||||
// RemoveAll removes path and any children it contains.
|
// RemoveAll removes path and any children it contains.
|
||||||
// If the path does not exist, RemoveAll returns nil (no error).
|
// If the path does not exist, RemoveAll returns nil (no error).
|
||||||
func (c *Connection) RemoveAll(ctx context.Context, name string) error {
|
func (c *Connection) RemoveAll(_ context.Context, name string) error {
|
||||||
c.UpdateLastActivity()
|
c.UpdateLastActivity()
|
||||||
|
|
||||||
name = util.CleanPath(name)
|
name = util.CleanPath(name)
|
||||||
|
@ -142,7 +142,7 @@ func (c *Connection) RemoveAll(ctx context.Context, name string) error {
|
||||||
|
|
||||||
// OpenFile opens the named file with specified flag.
|
// OpenFile opens the named file with specified flag.
|
||||||
// This method is used for uploads and downloads but also for Stat and Readdir
|
// This method is used for uploads and downloads but also for Stat and Readdir
|
||||||
func (c *Connection) OpenFile(ctx context.Context, name string, flag int, perm os.FileMode) (webdav.File, error) {
|
func (c *Connection) OpenFile(_ context.Context, name string, flag int, _ os.FileMode) (webdav.File, error) {
|
||||||
c.UpdateLastActivity()
|
c.UpdateLastActivity()
|
||||||
|
|
||||||
name = util.CleanPath(name)
|
name = util.CleanPath(name)
|
||||||
|
|
|
@ -303,7 +303,7 @@ func (fs *MockOsFs) IsAtomicUploadSupported() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove removes the named file or (empty) directory.
|
// Remove removes the named file or (empty) directory.
|
||||||
func (fs *MockOsFs) Remove(name string, isDir bool) error {
|
func (fs *MockOsFs) Remove(name string, _ bool) error {
|
||||||
if fs.err != nil {
|
if fs.err != nil {
|
||||||
return fs.err
|
return fs.err
|
||||||
}
|
}
|
||||||
|
@ -317,7 +317,7 @@ func (fs *MockOsFs) Rename(source, target string) (int, int64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMimeType returns the content type
|
// GetMimeType returns the content type
|
||||||
func (fs *MockOsFs) GetMimeType(name string) (string, error) {
|
func (fs *MockOsFs) GetMimeType(_ string) (string, error) {
|
||||||
if fs.err != nil {
|
if fs.err != nil {
|
||||||
return "", fs.err
|
return "", fs.err
|
||||||
}
|
}
|
||||||
|
|
|
@ -4874,6 +4874,7 @@ components:
|
||||||
- 10
|
- 10
|
||||||
- 11
|
- 11
|
||||||
- 12
|
- 12
|
||||||
|
- 13
|
||||||
description: |
|
description: |
|
||||||
Supported event action types:
|
Supported event action types:
|
||||||
* `1` - HTTP
|
* `1` - HTTP
|
||||||
|
@ -4888,6 +4889,7 @@ components:
|
||||||
* `10` - Metadata check
|
* `10` - Metadata check
|
||||||
* `11` - Password expiration check
|
* `11` - Password expiration check
|
||||||
* `12` - User expiration check
|
* `12` - User expiration check
|
||||||
|
* `13` - Identity Provider account check
|
||||||
FilesystemActionTypes:
|
FilesystemActionTypes:
|
||||||
type: integer
|
type: integer
|
||||||
enum:
|
enum:
|
||||||
|
@ -4910,6 +4912,7 @@ components:
|
||||||
- 4
|
- 4
|
||||||
- 5
|
- 5
|
||||||
- 6
|
- 6
|
||||||
|
- 7
|
||||||
description: |
|
description: |
|
||||||
Supported event trigger types:
|
Supported event trigger types:
|
||||||
* `1` - Filesystem event
|
* `1` - Filesystem event
|
||||||
|
@ -4918,6 +4921,7 @@ components:
|
||||||
* `4` - IP blocked
|
* `4` - IP blocked
|
||||||
* `5` - Certificate renewal
|
* `5` - Certificate renewal
|
||||||
* `6` - On demand, like schedule but executed on demand
|
* `6` - On demand, like schedule but executed on demand
|
||||||
|
* `7` - Identity provider login
|
||||||
LoginMethods:
|
LoginMethods:
|
||||||
type: string
|
type: string
|
||||||
enum:
|
enum:
|
||||||
|
@ -6870,6 +6874,24 @@ components:
|
||||||
threshold:
|
threshold:
|
||||||
type: integer
|
type: integer
|
||||||
description: 'An email notification will be generated for users whose password expires in a number of days less than or equal to this threshold'
|
description: 'An email notification will be generated for users whose password expires in a number of days less than or equal to this threshold'
|
||||||
|
EventActionIDPAccountCheck:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
mode:
|
||||||
|
type: integer
|
||||||
|
enum:
|
||||||
|
- 0
|
||||||
|
- 1
|
||||||
|
description: |
|
||||||
|
Account check mode:
|
||||||
|
* `0` Create or update the account
|
||||||
|
* `1` Create the account if it doesn't exist
|
||||||
|
template_user:
|
||||||
|
type: string
|
||||||
|
description: 'SFTPGo user template in JSON format'
|
||||||
|
template_admin:
|
||||||
|
type: string
|
||||||
|
description: 'SFTPGo admin template in JSON format'
|
||||||
BaseEventActionOptions:
|
BaseEventActionOptions:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -6885,6 +6907,8 @@ components:
|
||||||
$ref: '#/components/schemas/EventActionFilesystemConfig'
|
$ref: '#/components/schemas/EventActionFilesystemConfig'
|
||||||
pwd_expiration_config:
|
pwd_expiration_config:
|
||||||
$ref: '#/components/schemas/EventActionPasswordExpiration'
|
$ref: '#/components/schemas/EventActionPasswordExpiration'
|
||||||
|
idp_config:
|
||||||
|
$ref: '#/components/schemas/EventActionIDPAccountCheck'
|
||||||
BaseEventAction:
|
BaseEventAction:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -7026,6 +7050,8 @@ components:
|
||||||
- pre-upload
|
- pre-upload
|
||||||
- pre-download
|
- pre-download
|
||||||
- pre-delete
|
- pre-delete
|
||||||
|
- first-upload
|
||||||
|
- first-download
|
||||||
provider_events:
|
provider_events:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
|
@ -7038,6 +7064,17 @@ components:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: '#/components/schemas/Schedule'
|
$ref: '#/components/schemas/Schedule'
|
||||||
|
idp_login_event:
|
||||||
|
type: integer
|
||||||
|
enum:
|
||||||
|
- 0
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
description: |
|
||||||
|
IDP login events:
|
||||||
|
- `0` any login event
|
||||||
|
- `1` user login event
|
||||||
|
- `2` admin login event
|
||||||
options:
|
options:
|
||||||
$ref: '#/components/schemas/ConditionOptions'
|
$ref: '#/components/schemas/ConditionOptions'
|
||||||
BaseEventRule:
|
BaseEventRule:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
NFPM_VERSION=2.26.0
|
NFPM_VERSION=2.27.1
|
||||||
NFPM_ARCH=${NFPM_ARCH:-amd64}
|
NFPM_ARCH=${NFPM_ARCH:-amd64}
|
||||||
if [ -z ${SFTPGO_VERSION} ]
|
if [ -z ${SFTPGO_VERSION} ]
|
||||||
then
|
then
|
||||||
|
|
|
@ -88,6 +88,38 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group row action-type action-idp">
|
||||||
|
<label for="idIDPMode" class="col-sm-2 col-form-label">Mode</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<select class="form-control selectpicker" id="idIDPMode" name="idp_mode">
|
||||||
|
<option value="0" {{ if eq .Action.Options.IDPConfig.Mode 0 }}selected{{end}}>Create or update</option>
|
||||||
|
<option value="1" {{ if eq .Action.Options.IDPConfig.Mode 1 }}selected{{end}}>Create if it doesn't exist</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group row action-type action-idp">
|
||||||
|
<label for="idIDPUser" class="col-sm-2 col-form-label">User template</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<textarea class="form-control" id="idIDPUser" name="idp_user" rows="4" placeholder=""
|
||||||
|
aria-describedby="idpUserHelpBlock">{{.Action.Options.IDPConfig.TemplateUser}}</textarea>
|
||||||
|
<small id="idpUserHelpBlock" class="form-text text-muted">
|
||||||
|
Template for SFTPGo users in JSON format. Placeholders are supported
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group row action-type action-idp">
|
||||||
|
<label for="idIDAdmin" class="col-sm-2 col-form-label">Admin template</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<textarea class="form-control" id="idIDPAdmin" name="idp_admin" rows="4" placeholder=""
|
||||||
|
aria-describedby="idpAdminHelpBlock">{{.Action.Options.IDPConfig.TemplateAdmin}}</textarea>
|
||||||
|
<small id="idpAdminHelpBlock" class="form-text text-muted">
|
||||||
|
Template for SFTPGo admins in JSON format. Placeholders are supported
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group row action-type action-http">
|
<div class="form-group row action-type action-http">
|
||||||
<label for="idHTTPEndpoint" class="col-sm-2 col-form-label">Endpoint</label>
|
<label for="idHTTPEndpoint" class="col-sm-2 col-form-label">Endpoint</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
|
@ -781,6 +813,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
<p>
|
<p>
|
||||||
<span class="shortcut"><b>{{`{{RetentionReports}}`}}</b></span> => 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.
|
<span class="shortcut"><b>{{`{{RetentionReports}}`}}</b></span> => 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.
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
<span class="shortcut"><b>{{`{{IDPField<fieldname>}}`}}</b></span> => Identity Provider custom fields containing a string.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button class="btn btn-primary" type="button" data-dismiss="modal">OK</button>
|
<button class="btn btn-primary" type="button" data-dismiss="modal">OK</button>
|
||||||
|
@ -1028,6 +1063,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
case '11':
|
case '11':
|
||||||
$('.action-pwd-expiration').show();
|
$('.action-pwd-expiration').show();
|
||||||
break;
|
break;
|
||||||
|
case '13':
|
||||||
|
$('.action-idp').show();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,6 +98,17 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group row trigger trigger-idp">
|
||||||
|
<label for="idIDPEvent" class="col-sm-2 col-form-label">IDP Login event</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<select class="form-control selectpicker" id="idIDPEvent" name="idp_login_event">
|
||||||
|
<option value="0" {{if eq .Rule.Conditions.IDPLoginEvent 0}}selected{{end}}>Any</option>
|
||||||
|
<option value="1" {{if eq .Rule.Conditions.IDPLoginEvent 1}}selected{{end}}>User login</option>
|
||||||
|
<option value="2" {{if eq .Rule.Conditions.IDPLoginEvent 2}}selected{{end}}>Admin login</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="card bg-light mb-3 trigger trigger-schedule">
|
<div class="card bg-light mb-3 trigger trigger-schedule">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<b>Schedules</b>
|
<b>Schedules</b>
|
||||||
|
@ -196,7 +207,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card bg-light mb-3 trigger trigger-fs trigger-provider trigger-schedule trigger-on-demand">
|
<div class="card bg-light mb-3 trigger trigger-fs trigger-provider trigger-schedule trigger-on-demand trigger-idp">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<b>Name filters</b>
|
<b>Name filters</b>
|
||||||
</div>
|
</div>
|
||||||
|
@ -438,7 +449,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
<b>Actions</b>
|
<b>Actions</b>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h6 class="card-title mb-4">One or more actions to execute. The "Execute sync" options is supported for upload events and required for pre-* events</h6>
|
<h6 class="card-title mb-4">One or more actions to execute. The "Execute sync" options is supported for upload events and required for pre-* events and Identity provider login events if the action checks the account</h6>
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<div class="col-md-12 form_field_action_outer">
|
<div class="col-md-12 form_field_action_outer">
|
||||||
{{range $idx, $val := .Rule.Actions}}
|
{{range $idx, $val := .Rule.Actions}}
|
||||||
|
@ -727,6 +738,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
case '6':
|
case '6':
|
||||||
$('.trigger-on-demand').show();
|
$('.trigger-on-demand').show();
|
||||||
break;
|
break;
|
||||||
|
case '7':
|
||||||
|
$('.trigger-idp').show();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.log(`unsupported event trigger type: ${val}`);
|
console.log(`unsupported event trigger type: ${val}`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,16 +10,16 @@ require (
|
||||||
require (
|
require (
|
||||||
github.com/fatih/color v1.15.0 // indirect
|
github.com/fatih/color v1.15.0 // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
github.com/hashicorp/go-hclog v1.4.0 // indirect
|
github.com/hashicorp/go-hclog v1.5.0 // indirect
|
||||||
github.com/hashicorp/yamux v0.1.1 // indirect
|
github.com/hashicorp/yamux v0.1.1 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
github.com/mattn/go-isatty v0.0.18 // indirect
|
||||||
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
||||||
github.com/oklog/run v1.1.0 // indirect
|
github.com/oklog/run v1.1.0 // indirect
|
||||||
golang.org/x/net v0.8.0 // indirect
|
golang.org/x/net v0.8.0 // indirect
|
||||||
golang.org/x/sys v0.6.0 // indirect
|
golang.org/x/sys v0.6.0 // indirect
|
||||||
golang.org/x/text v0.8.0 // indirect
|
golang.org/x/text v0.8.0 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect
|
google.golang.org/genproto v0.0.0-20230320184635-7606e756e683 // indirect
|
||||||
google.golang.org/grpc v1.53.0 // indirect
|
google.golang.org/grpc v1.54.0 // indirect
|
||||||
google.golang.org/protobuf v1.29.1 // indirect
|
google.golang.org/protobuf v1.30.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
|
@ -9,8 +9,8 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg
|
||||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
github.com/hashicorp/go-hclog v1.4.0 h1:ctuWFGrhFha8BnnzxqeRGidlEcQkDyL5u8J8t5eA11I=
|
github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
|
||||||
github.com/hashicorp/go-hclog v1.4.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||||
github.com/hashicorp/go-plugin v1.4.10-0.20230306173702-d78f3fc2891d h1:I5vZgh+FLXZcmwesw2ZbfW4WKiPKlZxNoxJdUNwN/wE=
|
github.com/hashicorp/go-plugin v1.4.10-0.20230306173702-d78f3fc2891d h1:I5vZgh+FLXZcmwesw2ZbfW4WKiPKlZxNoxJdUNwN/wE=
|
||||||
github.com/hashicorp/go-plugin v1.4.10-0.20230306173702-d78f3fc2891d/go.mod h1:6/1TEzT0eQznvI/gV2CM29DLSkAK/e58mUWKVsPaph0=
|
github.com/hashicorp/go-plugin v1.4.10-0.20230306173702-d78f3fc2891d/go.mod h1:6/1TEzT0eQznvI/gV2CM29DLSkAK/e58mUWKVsPaph0=
|
||||||
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
|
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
|
||||||
|
@ -23,8 +23,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
|
||||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
|
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
|
||||||
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
|
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
|
||||||
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
|
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
|
||||||
|
@ -49,14 +49,14 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA=
|
google.golang.org/genproto v0.0.0-20230320184635-7606e756e683 h1:khxVcsk/FhnzxMKOyD+TDGwjbEOpcPuIpmafPGFmhMA=
|
||||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
|
google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
|
||||||
google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
|
google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=
|
||||||
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
|
google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
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.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.29.1 h1:7QBf+IK2gx70Ap/hDsOmam3GE0v9HicjfEdAxE62UoM=
|
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||||
google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
|
@ -10,16 +10,16 @@ require (
|
||||||
require (
|
require (
|
||||||
github.com/fatih/color v1.15.0 // indirect
|
github.com/fatih/color v1.15.0 // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
github.com/hashicorp/go-hclog v1.4.0 // indirect
|
github.com/hashicorp/go-hclog v1.5.0 // indirect
|
||||||
github.com/hashicorp/yamux v0.1.1 // indirect
|
github.com/hashicorp/yamux v0.1.1 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
github.com/mattn/go-isatty v0.0.18 // indirect
|
||||||
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
||||||
github.com/oklog/run v1.1.0 // indirect
|
github.com/oklog/run v1.1.0 // indirect
|
||||||
golang.org/x/net v0.8.0 // indirect
|
golang.org/x/net v0.8.0 // indirect
|
||||||
golang.org/x/sys v0.6.0 // indirect
|
golang.org/x/sys v0.6.0 // indirect
|
||||||
golang.org/x/text v0.8.0 // indirect
|
golang.org/x/text v0.8.0 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect
|
google.golang.org/genproto v0.0.0-20230320184635-7606e756e683 // indirect
|
||||||
google.golang.org/grpc v1.53.0 // indirect
|
google.golang.org/grpc v1.54.0 // indirect
|
||||||
google.golang.org/protobuf v1.29.1 // indirect
|
google.golang.org/protobuf v1.30.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
|
@ -9,8 +9,8 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg
|
||||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
github.com/hashicorp/go-hclog v1.4.0 h1:ctuWFGrhFha8BnnzxqeRGidlEcQkDyL5u8J8t5eA11I=
|
github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
|
||||||
github.com/hashicorp/go-hclog v1.4.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||||
github.com/hashicorp/go-plugin v1.4.10-0.20230306173702-d78f3fc2891d h1:I5vZgh+FLXZcmwesw2ZbfW4WKiPKlZxNoxJdUNwN/wE=
|
github.com/hashicorp/go-plugin v1.4.10-0.20230306173702-d78f3fc2891d h1:I5vZgh+FLXZcmwesw2ZbfW4WKiPKlZxNoxJdUNwN/wE=
|
||||||
github.com/hashicorp/go-plugin v1.4.10-0.20230306173702-d78f3fc2891d/go.mod h1:6/1TEzT0eQznvI/gV2CM29DLSkAK/e58mUWKVsPaph0=
|
github.com/hashicorp/go-plugin v1.4.10-0.20230306173702-d78f3fc2891d/go.mod h1:6/1TEzT0eQznvI/gV2CM29DLSkAK/e58mUWKVsPaph0=
|
||||||
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
|
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
|
||||||
|
@ -23,8 +23,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
|
||||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
|
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
|
||||||
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
|
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
|
||||||
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
|
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
|
||||||
|
@ -49,14 +49,14 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA=
|
google.golang.org/genproto v0.0.0-20230320184635-7606e756e683 h1:khxVcsk/FhnzxMKOyD+TDGwjbEOpcPuIpmafPGFmhMA=
|
||||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
|
google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
|
||||||
google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
|
google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=
|
||||||
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
|
google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
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.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.29.1 h1:7QBf+IK2gx70Ap/hDsOmam3GE0v9HicjfEdAxE62UoM=
|
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||||
google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
Loading…
Reference in a new issue