Browse Source

WebClient: show user quota

Also remove per-source data transfer limits. This was an
oversight

Signed-off-by: Nicola Murino <[email protected]>
Nicola Murino 2 years ago
parent
commit
a38ce460bb

+ 15 - 15
go.mod

@@ -10,14 +10,14 @@ require (
 	github.com/alexedwards/argon2id v0.0.0-20230305115115-4b3c3280a736
 	github.com/alexedwards/argon2id v0.0.0-20230305115115-4b3c3280a736
 	github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964
 	github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964
 	github.com/aws/aws-sdk-go-v2 v1.18.1
 	github.com/aws/aws-sdk-go-v2 v1.18.1
-	github.com/aws/aws-sdk-go-v2/config v1.18.26
-	github.com/aws/aws-sdk-go-v2/credentials v1.13.25
+	github.com/aws/aws-sdk-go-v2/config v1.18.27
+	github.com/aws/aws-sdk-go-v2/credentials v1.13.26
 	github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.4
 	github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.4
-	github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.68
-	github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.14.12
-	github.com/aws/aws-sdk-go-v2/service/s3 v1.34.0
-	github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.19.9
-	github.com/aws/aws-sdk-go-v2/service/sts v1.19.1
+	github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.70
+	github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.14.13
+	github.com/aws/aws-sdk-go-v2/service/s3 v1.35.0
+	github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.19.10
+	github.com/aws/aws-sdk-go-v2/service/sts v1.19.2
 	github.com/bmatcuk/doublestar/v4 v4.6.0
 	github.com/bmatcuk/doublestar/v4 v4.6.0
 	github.com/cockroachdb/cockroach-go/v2 v2.3.5
 	github.com/cockroachdb/cockroach-go/v2 v2.3.5
 	github.com/coreos/go-oidc/v3 v3.6.0
 	github.com/coreos/go-oidc/v3 v3.6.0
@@ -48,12 +48,12 @@ require (
 	github.com/pires/go-proxyproto v0.7.0
 	github.com/pires/go-proxyproto v0.7.0
 	github.com/pkg/sftp v1.13.6-0.20230213180117-971c283182b6
 	github.com/pkg/sftp v1.13.6-0.20230213180117-971c283182b6
 	github.com/pquerna/otp v1.4.0
 	github.com/pquerna/otp v1.4.0
-	github.com/prometheus/client_golang v1.15.1
+	github.com/prometheus/client_golang v1.16.0
 	github.com/robfig/cron/v3 v3.0.1
 	github.com/robfig/cron/v3 v3.0.1
 	github.com/rs/cors v1.9.0
 	github.com/rs/cors v1.9.0
 	github.com/rs/xid v1.5.0
 	github.com/rs/xid v1.5.0
 	github.com/rs/zerolog v1.29.1
 	github.com/rs/zerolog v1.29.1
-	github.com/sftpgo/sdk v0.1.5-0.20230614163902-b9133304e3d2
+	github.com/sftpgo/sdk v0.1.5-0.20230616161947-bb4a056935b0
 	github.com/shirou/gopsutil/v3 v3.23.5
 	github.com/shirou/gopsutil/v3 v3.23.5
 	github.com/spf13/afero v1.9.5
 	github.com/spf13/afero v1.9.5
 	github.com/spf13/cobra v1.7.0
 	github.com/spf13/cobra v1.7.0
@@ -74,7 +74,7 @@ require (
 	golang.org/x/sys v0.9.0
 	golang.org/x/sys v0.9.0
 	golang.org/x/term v0.9.0
 	golang.org/x/term v0.9.0
 	golang.org/x/time v0.3.0
 	golang.org/x/time v0.3.0
-	google.golang.org/api v0.127.0
+	google.golang.org/api v0.128.0
 	gopkg.in/natefinch/lumberjack.v2 v2.2.1
 	gopkg.in/natefinch/lumberjack.v2 v2.2.1
 )
 )
 
 
@@ -94,8 +94,8 @@ require (
 	github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.29 // indirect
 	github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.29 // indirect
 	github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.28 // indirect
 	github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.28 // indirect
 	github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.3 // indirect
 	github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.3 // indirect
-	github.com/aws/aws-sdk-go-v2/service/sso v1.12.11 // indirect
-	github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.11 // indirect
+	github.com/aws/aws-sdk-go-v2/service/sso v1.12.12 // indirect
+	github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.12 // 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
@@ -145,7 +145,7 @@ require (
 	github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
 	github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
 	github.com/prometheus/client_model v0.4.0 // indirect
 	github.com/prometheus/client_model v0.4.0 // indirect
 	github.com/prometheus/common v0.44.0 // indirect
 	github.com/prometheus/common v0.44.0 // indirect
-	github.com/prometheus/procfs v0.10.1 // indirect
+	github.com/prometheus/procfs v0.11.0 // indirect
 	github.com/russross/blackfriday/v2 v2.1.0 // indirect
 	github.com/russross/blackfriday/v2 v2.1.0 // indirect
 	github.com/segmentio/asm v1.2.0 // indirect
 	github.com/segmentio/asm v1.2.0 // indirect
 	github.com/shoenig/go-m1cpu v0.1.6 // indirect
 	github.com/shoenig/go-m1cpu v0.1.6 // indirect
@@ -158,13 +158,13 @@ require (
 	go.opencensus.io v0.24.0 // indirect
 	go.opencensus.io v0.24.0 // indirect
 	golang.org/x/mod v0.11.0 // indirect
 	golang.org/x/mod v0.11.0 // indirect
 	golang.org/x/text v0.10.0 // indirect
 	golang.org/x/text v0.10.0 // indirect
-	golang.org/x/tools v0.9.3 // indirect
+	golang.org/x/tools v0.10.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-20230530153820-e85fd2cbaebc // indirect
 	google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc // indirect
 	google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc // indirect
 	google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect
-	google.golang.org/grpc v1.55.0 // indirect
+	google.golang.org/grpc v1.56.0 // indirect
 	google.golang.org/protobuf v1.30.0 // 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

+ 31 - 31
go.sum

@@ -564,17 +564,17 @@ github.com/aws/aws-sdk-go-v2 v1.18.1/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3eP
 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.26 h1:ivCHcSmKd1+9rBlqVsxZHB35eCW88KWbMdG2VL3BuBw=
-github.com/aws/aws-sdk-go-v2/config v1.18.26/go.mod h1:NVmd//z/PNl7U+ZU2EnuffxOA060JWzgbH3BnqQrUoY=
+github.com/aws/aws-sdk-go-v2/config v1.18.27 h1:Az9uLwmssTE6OGTpsFqOnaGpLnKDqNYOJzWuC6UAYzA=
+github.com/aws/aws-sdk-go-v2/config v1.18.27/go.mod h1:0My+YgmkGxeqjXZb5BYme5pc4drjTnM+x1GJ3zv42Nw=
 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.25 h1:5wROoMcUC7nAE66e0b3IIht6Tos76M4HC+GQw8MeqxU=
-github.com/aws/aws-sdk-go-v2/credentials v1.13.25/go.mod h1:W9I2660WXSwZQ23mM1Ks72+UGeyirIxuU7/KzN7daeA=
+github.com/aws/aws-sdk-go-v2/credentials v1.13.26 h1:qmU+yhKmOCyujmuPY7tf5MxR/RKyZrOPO3V4DobiTUk=
+github.com/aws/aws-sdk-go-v2/credentials v1.13.26/go.mod h1:GoXt2YC8jHUBbA4jr+W3JiemnIbkXOfxSXcisUsZ3os=
 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.4 h1:LxK/bitrAr4lnh9LnIS6i7zWbCOdMsfzKFBI6LUCS0I=
 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.4 h1:LxK/bitrAr4lnh9LnIS6i7zWbCOdMsfzKFBI6LUCS0I=
 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.4/go.mod h1:E1hLXN/BL2e6YizK1zFlYd8vsfi2GTjbjBazinMmeaM=
 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.4/go.mod h1:E1hLXN/BL2e6YizK1zFlYd8vsfi2GTjbjBazinMmeaM=
 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.68 h1:0+IIldXpZPgIO1cvJJc1/83dzVOfeRWvSPUfED3fyfs=
-github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.68/go.mod h1:LIq1+fhV5PgIQ3DhL8D20v4jTQ95wK0FywDFBiype1k=
+github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.70 h1:4bh28MeeXoBFTjb0JjQ5sVatzlf5xA1DziV8mZed9v4=
+github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.70/go.mod h1:9yI5NXzqy2yOiMytv6QLZHvlyHLwYxO9iIq+bZIbrFg=
 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.34 h1:A5UqQEmPaCFpedKouS4v+dHCTUo2sKqhoKO9U5kxyWo=
 github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.34 h1:A5UqQEmPaCFpedKouS4v+dHCTUo2sKqhoKO9U5kxyWo=
 github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.34/go.mod h1:wZpTEecJe0Btj3IYnDx/VlUzor9wm3fJHyvLpQF0VwY=
 github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.34/go.mod h1:wZpTEecJe0Btj3IYnDx/VlUzor9wm3fJHyvLpQF0VwY=
@@ -600,26 +600,26 @@ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.22/go.mod h1:QFVbqK
 github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.3 h1:dBL3StFxHtpBzJJ/mNEsjXVgfO+7jR0dAIEwLqMapEA=
 github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.3 h1:dBL3StFxHtpBzJJ/mNEsjXVgfO+7jR0dAIEwLqMapEA=
 github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.3/go.mod h1:f1QyiAsvIv4B49DmCqrhlXqyaR+0IxMmyX+1P+AnzOM=
 github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.3/go.mod h1:f1QyiAsvIv4B49DmCqrhlXqyaR+0IxMmyX+1P+AnzOM=
 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.12 h1:vxOcOeqRTsO9ru0E5hkbhAeIdpYtizuoNEkLZuqm5ek=
-github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.14.12/go.mod h1:xmV0oIDDFg4i3vNjRfwRAl1ZGpNsEj06gLYpFT+hwpI=
+github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.14.13 h1:INNEByjR77yjugBQPVXkDTleLf5AIvxUslT1N3MG2So=
+github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.14.13/go.mod h1:xmV0oIDDFg4i3vNjRfwRAl1ZGpNsEj06gLYpFT+hwpI=
 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.34.0 h1:2qt8zaVqQCMpnQHBB+PAbfSSXgMl9+zpTRNDHmachJk=
-github.com/aws/aws-sdk-go-v2/service/s3 v1.34.0/go.mod h1:aVbf0sko/TsLWHx30c/uVu7c62+0EAJ3vbxaJga0xCw=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.35.0 h1:ya7fmrN2fE7s1P2gaPbNg5MTkERVWfsH8ToP1YC4Z9o=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.35.0/go.mod h1:aVbf0sko/TsLWHx30c/uVu7c62+0EAJ3vbxaJga0xCw=
 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.9 h1:cLMyxvdb04nboUtwJl8GgyAbA25Hu7dYE/4/DV+Ku9M=
-github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.19.9/go.mod h1:ezn6mzIRqTPdAbDpm03dx4y9g6rvGRb2q33wS76dCxw=
+github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.19.10 h1:eW8zPSh7ZLzb7029xCsIEFbnxLvNHPTt7aWwdKjNJc8=
+github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.19.10/go.mod h1:ezn6mzIRqTPdAbDpm03dx4y9g6rvGRb2q33wS76dCxw=
 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.11 h1:cNrMc266RsZJ8V1u1OQQONKcf9HmfxQFqgcpY7ZJBhY=
-github.com/aws/aws-sdk-go-v2/service/sso v1.12.11/go.mod h1:HuCOxYsF21eKrerARYO6HapNeh9GBNq7fius2AcwodY=
+github.com/aws/aws-sdk-go-v2/service/sso v1.12.12 h1:nneMBM2p79PGWBQovYO/6Xnc2ryRMw3InnDJq1FHkSY=
+github.com/aws/aws-sdk-go-v2/service/sso v1.12.12/go.mod h1:HuCOxYsF21eKrerARYO6HapNeh9GBNq7fius2AcwodY=
 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.11 h1:h2VhtCE5PBiJefmlVCjJRSzBfFcQeAE10SXIGkXw1jQ=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.11/go.mod h1:E4VrHCPzmVB/KFXtqBGKb3c8zpbNBgKe3fisDNLAW5w=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.12 h1:2qTR7IFk7/0IN/adSFhYu9Xthr0zVFTgBrmPldILn80=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.12/go.mod h1:E4VrHCPzmVB/KFXtqBGKb3c8zpbNBgKe3fisDNLAW5w=
 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.19.1 h1:ehPTnLR/es8TL1fpBfq8qw9cAwOpQr47fLmZD9yhHjk=
-github.com/aws/aws-sdk-go-v2/service/sts v1.19.1/go.mod h1:dp0yLPsLBOi++WTxzCjA/oZqi6NPIhoR+uF7GeMU9eg=
+github.com/aws/aws-sdk-go-v2/service/sts v1.19.2 h1:XFJ2Z6sNUUcAz9poj+245DMkrHE4h2j5I9/xD50RHfE=
+github.com/aws/aws-sdk-go-v2/service/sts v1.19.2/go.mod h1:dp0yLPsLBOi++WTxzCjA/oZqi6NPIhoR+uF7GeMU9eg=
 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=
@@ -1753,8 +1753,8 @@ github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqr
 github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
 github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
 github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
 github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
 github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
 github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
-github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI=
-github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
+github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
+github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
 github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@@ -1798,8 +1798,8 @@ github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
 github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
 github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
 github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
 github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
-github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
-github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
+github.com/prometheus/procfs v0.11.0 h1:5EAgkfkMl659uZPbe9AS2N68a7Cc1TJbPEuGzFuRbyk=
+github.com/prometheus/procfs v0.11.0/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
 github.com/prometheus/prometheus v0.35.0/go.mod h1:7HaLx5kEPKJ0GDgbODG0fZgXbQ8K/XjZNJXQmbmgQlY=
 github.com/prometheus/prometheus v0.35.0/go.mod h1:7HaLx5kEPKJ0GDgbODG0fZgXbQ8K/XjZNJXQmbmgQlY=
 github.com/prometheus/prometheus v0.42.0/go.mod h1:Pfqb/MLnnR2KK+0vchiaH39jXxvLMBk+3lnIGP4N7Vk=
 github.com/prometheus/prometheus v0.42.0/go.mod h1:Pfqb/MLnnR2KK+0vchiaH39jXxvLMBk+3lnIGP4N7Vk=
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
@@ -1843,8 +1843,8 @@ github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod
 github.com/secsy/goftp v0.0.0-20200609142545-aa2de14babf4 h1:PT+ElG/UUFMfqy5HrxJxNzj3QBOf7dZwupeVC+mG1Lo=
 github.com/secsy/goftp v0.0.0-20200609142545-aa2de14babf4 h1:PT+ElG/UUFMfqy5HrxJxNzj3QBOf7dZwupeVC+mG1Lo=
 github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
 github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
 github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
 github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
-github.com/sftpgo/sdk v0.1.5-0.20230614163902-b9133304e3d2 h1:LY1SFycc9ZNE9820cIQcpM1D7nSZLM7qfNynEWbMYfE=
-github.com/sftpgo/sdk v0.1.5-0.20230614163902-b9133304e3d2/go.mod h1:TjeoMWS0JEXt9RukJveTnaiHj4+MVLtUiDC+mY++Odk=
+github.com/sftpgo/sdk v0.1.5-0.20230616161947-bb4a056935b0 h1:GtEAHNYNOr7tknN2YYnn52irvpqtwPA/pFC7Gtm16hA=
+github.com/sftpgo/sdk v0.1.5-0.20230616161947-bb4a056935b0/go.mod h1:TjeoMWS0JEXt9RukJveTnaiHj4+MVLtUiDC+mY++Odk=
 github.com/shirou/gopsutil/v3 v3.23.5 h1:5SgDCeQ0KW0S4N0znjeM/eFHXXOKyv2dVNgRq/c9P6Y=
 github.com/shirou/gopsutil/v3 v3.23.5 h1:5SgDCeQ0KW0S4N0znjeM/eFHXXOKyv2dVNgRq/c9P6Y=
 github.com/shirou/gopsutil/v3 v3.23.5/go.mod h1:Ng3Maa27Q2KARVJ0SPZF5NdrQSC3XHKP8IIWrHgMeLY=
 github.com/shirou/gopsutil/v3 v3.23.5/go.mod h1:Ng3Maa27Q2KARVJ0SPZF5NdrQSC3XHKP8IIWrHgMeLY=
 github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
 github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
@@ -2305,7 +2305,7 @@ golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
+golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -2592,8 +2592,8 @@ golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
 golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
 golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
 golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
 golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
 golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
 golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
-golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
-golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
+golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
+golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
 golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -2670,8 +2670,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.127.0 h1:v7rj0vA0imM3Ou81k1eyFxQNScLzn71EyGnJDr+V/XI=
-google.golang.org/api v0.127.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750=
+google.golang.org/api v0.128.0 h1:RjPESny5CnQRn9V6siglged+DZCgfu9l6mO9dkX9VOg=
+google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750=
 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=
@@ -2866,8 +2866,8 @@ google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCD
 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/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
 google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
-google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
-google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
+google.golang.org/grpc v1.56.0 h1:+y7Bs8rtMd07LeXmL3NxcTLn7mUkbKZqEpPhMNkwJEE=
+google.golang.org/grpc v1.56.0/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
 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=

+ 1 - 2
internal/common/connection.go

@@ -1316,8 +1316,7 @@ func (c *BaseConnection) GetTransferQuota() dataprovider.TransferQuota {
 }
 }
 
 
 func (c *BaseConnection) checkUserQuota() (dataprovider.TransferQuota, int, int64) {
 func (c *BaseConnection) checkUserQuota() (dataprovider.TransferQuota, int, int64) {
-	clientIP := c.GetRemoteIP()
-	ul, dl, total := c.User.GetDataTransferLimits(clientIP)
+	ul, dl, total := c.User.GetDataTransferLimits()
 	result := dataprovider.TransferQuota{
 	result := dataprovider.TransferQuota{
 		ULSize:           ul,
 		ULSize:           ul,
 		DLSize:           dl,
 		DLSize:           dl,

+ 0 - 1
internal/common/eventmanager.go

@@ -1525,7 +1525,6 @@ func getUserForEventAction(user dataprovider.User) (dataprovider.User, error) {
 	user.Filters.DisableFsChecks = false
 	user.Filters.DisableFsChecks = false
 	user.Filters.FilePatterns = nil
 	user.Filters.FilePatterns = nil
 	user.Filters.BandwidthLimits = nil
 	user.Filters.BandwidthLimits = nil
-	user.Filters.DataTransferLimits = nil
 	for k := range user.Permissions {
 	for k := range user.Permissions {
 		user.Permissions[k] = []string{dataprovider.PermAny}
 		user.Permissions[k] = []string{dataprovider.PermAny}
 	}
 	}

+ 0 - 6
internal/common/protocol_test.go

@@ -1548,12 +1548,6 @@ func TestVirtualFoldersQuotaRenameOverwrite(t *testing.T) {
 func TestQuotaRenameOverwrite(t *testing.T) {
 func TestQuotaRenameOverwrite(t *testing.T) {
 	u := getTestUser()
 	u := getTestUser()
 	u.QuotaFiles = 100
 	u.QuotaFiles = 100
-	u.Filters.DataTransferLimits = []sdk.DataTransferLimit{
-		{
-			Sources:           []string{"10.8.0.0/8"},
-			TotalDataTransfer: 1,
-		},
-	}
 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 	user, _, err := httpdtest.AddUser(u, http.StatusCreated)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 	conn, client, err := getSftpClient(user)
 	conn, client, err := getSftpClient(user)

+ 11 - 30
internal/common/transfer_test.go

@@ -332,40 +332,21 @@ func TestFTPMode(t *testing.T) {
 func TestTransferQuota(t *testing.T) {
 func TestTransferQuota(t *testing.T) {
 	user := dataprovider.User{
 	user := dataprovider.User{
 		BaseUser: sdk.BaseUser{
 		BaseUser: sdk.BaseUser{
-			TotalDataTransfer:    -1,
-			UploadDataTransfer:   -1,
-			DownloadDataTransfer: -1,
+			TotalDataTransfer:    3,
+			UploadDataTransfer:   2,
+			DownloadDataTransfer: 1,
 		},
 		},
 	}
 	}
-	user.Filters.DataTransferLimits = []sdk.DataTransferLimit{
-		{
-			Sources:              []string{"127.0.0.1/32", "192.168.1.0/24"},
-			TotalDataTransfer:    100,
-			UploadDataTransfer:   0,
-			DownloadDataTransfer: 0,
-		},
-		{
-			Sources:              []string{"172.16.0.0/24"},
-			TotalDataTransfer:    0,
-			UploadDataTransfer:   120,
-			DownloadDataTransfer: 150,
-		},
-	}
-	ul, dl, total := user.GetDataTransferLimits("127.0.1.1")
-	assert.Equal(t, int64(0), ul)
-	assert.Equal(t, int64(0), dl)
-	assert.Equal(t, int64(0), total)
-	ul, dl, total = user.GetDataTransferLimits("127.0.0.1")
-	assert.Equal(t, int64(0), ul)
-	assert.Equal(t, int64(0), dl)
-	assert.Equal(t, int64(100*1048576), total)
-	ul, dl, total = user.GetDataTransferLimits("192.168.1.4")
+	ul, dl, total := user.GetDataTransferLimits()
+	assert.Equal(t, int64(2*1048576), ul)
+	assert.Equal(t, int64(1*1048576), dl)
+	assert.Equal(t, int64(3*1048576), total)
+	user.TotalDataTransfer = -1
+	user.UploadDataTransfer = -1
+	user.DownloadDataTransfer = -1
+	ul, dl, total = user.GetDataTransferLimits()
 	assert.Equal(t, int64(0), ul)
 	assert.Equal(t, int64(0), ul)
 	assert.Equal(t, int64(0), dl)
 	assert.Equal(t, int64(0), dl)
-	assert.Equal(t, int64(100*1048576), total)
-	ul, dl, total = user.GetDataTransferLimits("172.16.0.2")
-	assert.Equal(t, int64(120*1048576), ul)
-	assert.Equal(t, int64(150*1048576), dl)
 	assert.Equal(t, int64(0), total)
 	assert.Equal(t, int64(0), total)
 	transferQuota := dataprovider.TransferQuota{}
 	transferQuota := dataprovider.TransferQuota{}
 	assert.True(t, transferQuota.HasDownloadSpace())
 	assert.True(t, transferQuota.HasDownloadSpace())

+ 1 - 1
internal/common/transferschecker.go

@@ -61,7 +61,7 @@ type baseTransferChecker struct {
 func (t *baseTransferChecker) isDataTransferExceeded(user dataprovider.User, transfer dataprovider.ActiveTransfer, ulSize,
 func (t *baseTransferChecker) isDataTransferExceeded(user dataprovider.User, transfer dataprovider.ActiveTransfer, ulSize,
 	dlSize int64,
 	dlSize int64,
 ) bool {
 ) bool {
-	ulQuota, dlQuota, totalQuota := user.GetDataTransferLimits(transfer.IP)
+	ulQuota, dlQuota, totalQuota := user.GetDataTransferLimits()
 	if totalQuota > 0 {
 	if totalQuota > 0 {
 		allowedSize := totalQuota - (user.UsedUploadDataTransfer + user.UsedDownloadDataTransfer)
 		allowedSize := totalQuota - (user.UsedUploadDataTransfer + user.UsedDownloadDataTransfer)
 		if ulSize+dlSize > allowedSize {
 		if ulSize+dlSize > allowedSize {

+ 1 - 16
internal/common/transferschecker_test.go

@@ -622,17 +622,6 @@ func TestGetUsersForQuotaCheck(t *testing.T) {
 					QuotaSize:   100,
 					QuotaSize:   100,
 				},
 				},
 			},
 			},
-			Filters: dataprovider.UserFilters{
-				BaseUserFilters: sdk.BaseUserFilters{
-					DataTransferLimits: []sdk.DataTransferLimit{
-						{
-							Sources:              []string{"172.16.0.0/16"},
-							UploadDataTransfer:   50,
-							DownloadDataTransfer: 80,
-						},
-					},
-				},
-			},
 		}
 		}
 		err = dataprovider.AddUser(&user, "", "", "")
 		err = dataprovider.AddUser(&user, "", "", "")
 		assert.NoError(t, err)
 		assert.NoError(t, err)
@@ -660,14 +649,10 @@ func TestGetUsersForQuotaCheck(t *testing.T) {
 				assert.Len(t, user.VirtualFolders, 0, user.Username)
 				assert.Len(t, user.VirtualFolders, 0, user.Username)
 			}
 			}
 		}
 		}
-		ul, dl, total := user.GetDataTransferLimits("127.1.1.1")
+		ul, dl, total := user.GetDataTransferLimits()
 		assert.Equal(t, int64(0), ul)
 		assert.Equal(t, int64(0), ul)
 		assert.Equal(t, int64(0), dl)
 		assert.Equal(t, int64(0), dl)
 		assert.Equal(t, int64(0), total)
 		assert.Equal(t, int64(0), total)
-		ul, dl, total = user.GetDataTransferLimits("172.16.2.3")
-		assert.Equal(t, int64(50*1024*1024), ul)
-		assert.Equal(t, int64(80*1024*1024), dl)
-		assert.Equal(t, int64(0), total)
 	}
 	}
 
 
 	for i := 0; i < 40; i++ {
 	for i := 0; i < 40; i++ {

+ 0 - 35
internal/dataprovider/dataprovider.go

@@ -2585,18 +2585,6 @@ func copyBaseUserFilters(in sdk.BaseUserFilters) sdk.BaseUserFilters {
 		copy(bwLimit.Sources, limit.Sources)
 		copy(bwLimit.Sources, limit.Sources)
 		filters.BandwidthLimits = append(filters.BandwidthLimits, bwLimit)
 		filters.BandwidthLimits = append(filters.BandwidthLimits, bwLimit)
 	}
 	}
-	filters.DataTransferLimits = make([]sdk.DataTransferLimit, 0, len(in.DataTransferLimits))
-	for _, limit := range in.DataTransferLimits {
-		dtLimit := sdk.DataTransferLimit{
-			UploadDataTransfer:   limit.UploadDataTransfer,
-			DownloadDataTransfer: limit.DownloadDataTransfer,
-			TotalDataTransfer:    limit.TotalDataTransfer,
-			Sources:              make([]string, 0, len(limit.Sources)),
-		}
-		dtLimit.Sources = make([]string, len(limit.Sources))
-		copy(dtLimit.Sources, limit.Sources)
-		filters.DataTransferLimits = append(filters.DataTransferLimits, dtLimit)
-	}
 	return filters
 	return filters
 }
 }
 
 
@@ -2943,26 +2931,6 @@ func validateBandwidthLimitsFilter(filters *sdk.BaseUserFilters) error {
 	return nil
 	return nil
 }
 }
 
 
-func validateTransferLimitsFilter(filters *sdk.BaseUserFilters) error {
-	for idx, limit := range filters.DataTransferLimits {
-		filters.DataTransferLimits[idx].Sources = util.RemoveDuplicates(limit.Sources, false)
-		if len(limit.Sources) == 0 {
-			return util.NewValidationError("no data transfer limit source specified")
-		}
-		for _, source := range limit.Sources {
-			_, _, err := net.ParseCIDR(source)
-			if err != nil {
-				return util.NewValidationError(fmt.Sprintf("could not parse data transfer limit source %q: %v", source, err))
-			}
-		}
-		if limit.TotalDataTransfer > 0 {
-			filters.DataTransferLimits[idx].UploadDataTransfer = 0
-			filters.DataTransferLimits[idx].DownloadDataTransfer = 0
-		}
-	}
-	return nil
-}
-
 func updateFiltersValues(filters *sdk.BaseUserFilters) {
 func updateFiltersValues(filters *sdk.BaseUserFilters) {
 	if filters.StartDirectory != "" {
 	if filters.StartDirectory != "" {
 		filters.StartDirectory = util.CleanPath(filters.StartDirectory)
 		filters.StartDirectory = util.CleanPath(filters.StartDirectory)
@@ -2998,9 +2966,6 @@ func validateBaseFilters(filters *sdk.BaseUserFilters) error {
 	if err := validateBandwidthLimitsFilter(filters); err != nil {
 	if err := validateBandwidthLimitsFilter(filters); err != nil {
 		return err
 		return err
 	}
 	}
-	if err := validateTransferLimitsFilter(filters); err != nil {
-		return err
-	}
 	if len(filters.DeniedLoginMethods) >= len(ValidLoginMethods) {
 	if len(filters.DeniedLoginMethods) >= len(ValidLoginMethods) {
 		return util.NewValidationError("invalid denied_login_methods")
 		return util.NewValidationError("invalid denied_login_methods")
 	}
 	}

+ 1 - 29
internal/dataprovider/user.go

@@ -1289,39 +1289,12 @@ func (u *User) HasQuotaRestrictions() bool {
 
 
 // HasTransferQuotaRestrictions returns true if there are any data transfer restrictions
 // HasTransferQuotaRestrictions returns true if there are any data transfer restrictions
 func (u *User) HasTransferQuotaRestrictions() bool {
 func (u *User) HasTransferQuotaRestrictions() bool {
-	if len(u.Filters.DataTransferLimits) > 0 {
-		return true
-	}
 	return u.UploadDataTransfer > 0 || u.TotalDataTransfer > 0 || u.DownloadDataTransfer > 0
 	return u.UploadDataTransfer > 0 || u.TotalDataTransfer > 0 || u.DownloadDataTransfer > 0
 }
 }
 
 
 // GetDataTransferLimits returns upload, download and total data transfer limits
 // GetDataTransferLimits returns upload, download and total data transfer limits
-func (u *User) GetDataTransferLimits(clientIP string) (int64, int64, int64) {
+func (u *User) GetDataTransferLimits() (int64, int64, int64) {
 	var total, ul, dl int64
 	var total, ul, dl int64
-	if len(u.Filters.DataTransferLimits) > 0 {
-		ip := net.ParseIP(clientIP)
-		if ip != nil {
-			for _, limit := range u.Filters.DataTransferLimits {
-				for _, source := range limit.Sources {
-					_, ipNet, err := net.ParseCIDR(source)
-					if err == nil {
-						if ipNet.Contains(ip) {
-							if limit.TotalDataTransfer > 0 {
-								total = limit.TotalDataTransfer * 1048576
-							}
-							if limit.DownloadDataTransfer > 0 {
-								dl = limit.DownloadDataTransfer * 1048576
-							}
-							if limit.UploadDataTransfer > 0 {
-								ul = limit.UploadDataTransfer * 1048576
-							}
-							return ul, dl, total
-						}
-					}
-				}
-			}
-		}
-	}
 	if u.TotalDataTransfer > 0 {
 	if u.TotalDataTransfer > 0 {
 		total = u.TotalDataTransfer * 1048576
 		total = u.TotalDataTransfer * 1048576
 	}
 	}
@@ -1825,7 +1798,6 @@ func (u *User) mergeAdditiveProperties(group *Group, groupType int, replacer *st
 	u.mergePermissions(group, groupType, replacer)
 	u.mergePermissions(group, groupType, replacer)
 	u.mergeFilePatterns(group, groupType, replacer)
 	u.mergeFilePatterns(group, groupType, replacer)
 	u.Filters.BandwidthLimits = append(u.Filters.BandwidthLimits, group.UserSettings.Filters.BandwidthLimits...)
 	u.Filters.BandwidthLimits = append(u.Filters.BandwidthLimits, group.UserSettings.Filters.BandwidthLimits...)
-	u.Filters.DataTransferLimits = append(u.Filters.DataTransferLimits, group.UserSettings.Filters.DataTransferLimits...)
 	u.Filters.AllowedIP = append(u.Filters.AllowedIP, group.UserSettings.Filters.AllowedIP...)
 	u.Filters.AllowedIP = append(u.Filters.AllowedIP, group.UserSettings.Filters.AllowedIP...)
 	u.Filters.DeniedIP = append(u.Filters.DeniedIP, group.UserSettings.Filters.DeniedIP...)
 	u.Filters.DeniedIP = append(u.Filters.DeniedIP, group.UserSettings.Filters.DeniedIP...)
 	u.Filters.DeniedLoginMethods = append(u.Filters.DeniedLoginMethods, group.UserSettings.Filters.DeniedLoginMethods...)
 	u.Filters.DeniedLoginMethods = append(u.Filters.DeniedLoginMethods, group.UserSettings.Filters.DeniedLoginMethods...)

+ 0 - 164
internal/httpd/httpd_test.go

@@ -2627,103 +2627,6 @@ func TestEventRuleValidation(t *testing.T) {
 	assert.Contains(t, string(resp), "invalid Identity Provider login event")
 	assert.Contains(t, string(resp), "invalid Identity Provider login event")
 }
 }
 
 
-func TestUserTransferLimits(t *testing.T) {
-	u := getTestUser()
-	u.TotalDataTransfer = 100
-	u.Filters.DataTransferLimits = []sdk.DataTransferLimit{
-		{
-			Sources: nil,
-		},
-	}
-	_, resp, err := httpdtest.AddUser(u, http.StatusBadRequest)
-	assert.NoError(t, err, string(resp))
-	assert.Contains(t, string(resp), "Validation error: no data transfer limit source specified")
-	u.Filters.DataTransferLimits = []sdk.DataTransferLimit{
-		{
-			Sources: []string{"a"},
-		},
-	}
-	_, resp, err = httpdtest.AddUser(u, http.StatusBadRequest)
-	assert.NoError(t, err, string(resp))
-	assert.Contains(t, string(resp), "Validation error: could not parse data transfer limit source")
-	u.Filters.DataTransferLimits = []sdk.DataTransferLimit{
-		{
-			Sources:              []string{"127.0.0.1/32"},
-			UploadDataTransfer:   120,
-			DownloadDataTransfer: 140,
-		},
-		{
-			Sources:           []string{"192.168.0.0/24", "192.168.1.0/24"},
-			TotalDataTransfer: 400,
-		},
-		{
-			Sources: []string{"10.0.0.0/8"},
-		},
-	}
-	user, resp, err := httpdtest.AddUser(u, http.StatusCreated)
-	assert.NoError(t, err, string(resp))
-	assert.Len(t, user.Filters.DataTransferLimits, 3)
-	assert.Equal(t, u.Filters.DataTransferLimits, user.Filters.DataTransferLimits)
-	up, down, total := user.GetDataTransferLimits("1.1.1.1")
-	assert.Equal(t, user.TotalDataTransfer*1024*1024, total)
-	assert.Equal(t, user.UploadDataTransfer*1024*1024, up)
-	assert.Equal(t, user.DownloadDataTransfer*1024*1024, down)
-	up, down, total = user.GetDataTransferLimits("127.0.0.1")
-	assert.Equal(t, user.Filters.DataTransferLimits[0].TotalDataTransfer*1024*1024, total)
-	assert.Equal(t, user.Filters.DataTransferLimits[0].UploadDataTransfer*1024*1024, up)
-	assert.Equal(t, user.Filters.DataTransferLimits[0].DownloadDataTransfer*1024*1024, down)
-	up, down, total = user.GetDataTransferLimits("192.168.1.6")
-	assert.Equal(t, user.Filters.DataTransferLimits[1].TotalDataTransfer*1024*1024, total)
-	assert.Equal(t, user.Filters.DataTransferLimits[1].UploadDataTransfer*1024*1024, up)
-	assert.Equal(t, user.Filters.DataTransferLimits[1].DownloadDataTransfer*1024*1024, down)
-	up, down, total = user.GetDataTransferLimits("10.1.2.3")
-	assert.Equal(t, user.Filters.DataTransferLimits[2].TotalDataTransfer*1024*1024, total)
-	assert.Equal(t, user.Filters.DataTransferLimits[2].UploadDataTransfer*1024*1024, up)
-	assert.Equal(t, user.Filters.DataTransferLimits[2].DownloadDataTransfer*1024*1024, down)
-
-	connID := xid.New().String()
-	localAddr := "::1"
-	conn := common.NewBaseConnection(connID, common.ProtocolHTTP, localAddr, "1.1.1.2", user)
-	transferQuota := conn.GetTransferQuota()
-	assert.Equal(t, user.TotalDataTransfer*1024*1024, transferQuota.AllowedTotalSize)
-	assert.Equal(t, user.UploadDataTransfer*1024*1024, transferQuota.AllowedULSize)
-	assert.Equal(t, user.DownloadDataTransfer*1024*1024, transferQuota.AllowedDLSize)
-
-	conn = common.NewBaseConnection(connID, common.ProtocolHTTP, localAddr, "127.0.0.1", user)
-	transferQuota = conn.GetTransferQuota()
-	assert.Equal(t, user.Filters.DataTransferLimits[0].TotalDataTransfer*1024*1024, transferQuota.AllowedTotalSize)
-	assert.Equal(t, user.Filters.DataTransferLimits[0].UploadDataTransfer*1024*1024, transferQuota.AllowedULSize)
-	assert.Equal(t, user.Filters.DataTransferLimits[0].DownloadDataTransfer*1024*1024, transferQuota.AllowedDLSize)
-
-	conn = common.NewBaseConnection(connID, common.ProtocolHTTP, localAddr, "192.168.1.5", user)
-	transferQuota = conn.GetTransferQuota()
-	assert.Equal(t, user.Filters.DataTransferLimits[1].TotalDataTransfer*1024*1024, transferQuota.AllowedTotalSize)
-	assert.Equal(t, user.Filters.DataTransferLimits[1].UploadDataTransfer*1024*1024, transferQuota.AllowedULSize)
-	assert.Equal(t, user.Filters.DataTransferLimits[1].DownloadDataTransfer*1024*1024, transferQuota.AllowedDLSize)
-
-	u.UsedDownloadDataTransfer = 10 * 1024 * 1024
-	u.UsedUploadDataTransfer = 5 * 1024 * 1024
-	_, err = httpdtest.UpdateTransferQuotaUsage(u, "", http.StatusOK)
-	assert.NoError(t, err)
-
-	conn = common.NewBaseConnection(connID, common.ProtocolHTTP, localAddr, "192.168.1.6", user)
-	transferQuota = conn.GetTransferQuota()
-	assert.Equal(t, (user.Filters.DataTransferLimits[1].TotalDataTransfer-15)*1024*1024, transferQuota.AllowedTotalSize)
-	assert.Equal(t, user.Filters.DataTransferLimits[1].UploadDataTransfer*1024*1024, transferQuota.AllowedULSize)
-	assert.Equal(t, user.Filters.DataTransferLimits[1].DownloadDataTransfer*1024*1024, transferQuota.AllowedDLSize)
-
-	conn = common.NewBaseConnection(connID, common.ProtocolHTTP, localAddr, "10.8.3.4", user)
-	transferQuota = conn.GetTransferQuota()
-	assert.Equal(t, int64(0), transferQuota.AllowedTotalSize)
-	assert.Equal(t, int64(0), transferQuota.AllowedULSize)
-	assert.Equal(t, int64(0), transferQuota.AllowedDLSize)
-
-	err = os.RemoveAll(user.GetHomeDir())
-	assert.NoError(t, err)
-	_, err = httpdtest.RemoveUser(user, http.StatusOK)
-	assert.NoError(t, err)
-}
-
 func TestUserBandwidthLimits(t *testing.T) {
 func TestUserBandwidthLimits(t *testing.T) {
 	u := getTestUser()
 	u := getTestUser()
 	u.UploadBandwidth = 128
 	u.UploadBandwidth = 128
@@ -19686,49 +19589,6 @@ func TestWebUserAddMock(t *testing.T) {
 	assert.Contains(t, rr.Body.String(), "Validation error: could not parse bandwidth limit source")
 	assert.Contains(t, rr.Body.String(), "Validation error: could not parse bandwidth limit source")
 	form.Set("bandwidth_limit_sources1", "127.0.0.1/32")
 	form.Set("bandwidth_limit_sources1", "127.0.0.1/32")
 	form.Set("upload_bandwidth_source1", "-1")
 	form.Set("upload_bandwidth_source1", "-1")
-	form.Set("data_transfer_limit_sources0", "127.0.1.1")
-	b, contentType, _ = getMultipartFormData(form, "", "")
-	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
-	setJWTCookieForReq(req, webToken)
-	req.Header.Set("Content-Type", contentType)
-	rr = executeRequest(req)
-	checkResponseCode(t, http.StatusOK, rr)
-	assert.Contains(t, rr.Body.String(), "could not parse data transfer limit source")
-	form.Set("data_transfer_limit_sources0", "127.0.1.1/32")
-	form.Set("upload_data_transfer_source0", "a")
-	b, contentType, _ = getMultipartFormData(form, "", "")
-	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
-	setJWTCookieForReq(req, webToken)
-	req.Header.Set("Content-Type", contentType)
-	rr = executeRequest(req)
-	checkResponseCode(t, http.StatusOK, rr)
-	assert.Contains(t, rr.Body.String(), "invalid upload_data_transfer_source")
-	form.Set("upload_data_transfer_source0", "0")
-	form.Set("download_data_transfer_source0", "a")
-	b, contentType, _ = getMultipartFormData(form, "", "")
-	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
-	setJWTCookieForReq(req, webToken)
-	req.Header.Set("Content-Type", contentType)
-	rr = executeRequest(req)
-	checkResponseCode(t, http.StatusOK, rr)
-	assert.Contains(t, rr.Body.String(), "invalid download_data_transfer_source")
-	form.Set("download_data_transfer_source0", "0")
-	form.Set("total_data_transfer_source0", "a")
-	b, contentType, _ = getMultipartFormData(form, "", "")
-	req, _ = http.NewRequest(http.MethodPost, webUserPath, &b)
-	setJWTCookieForReq(req, webToken)
-	req.Header.Set("Content-Type", contentType)
-	rr = executeRequest(req)
-	checkResponseCode(t, http.StatusOK, rr)
-	assert.Contains(t, rr.Body.String(), "invalid total_data_transfer_source")
-	form.Set("total_data_transfer_source0", "0")
-	form.Set("data_transfer_limit_sources10", "192.168.5.0/24, 10.8.0.0/16")
-	form.Set("download_data_transfer_source10", "100")
-	form.Set("upload_data_transfer_source10", "120")
-	form.Set("data_transfer_limit_sources12", "192.168.3.0/24, 10.8.2.0/24,::1/64")
-	form.Set("download_data_transfer_source12", "100")
-	form.Set("upload_data_transfer_source12", "120")
-	form.Set("total_data_transfer_source12", "200")
 	// invalid external auth cache size
 	// invalid external auth cache size
 	form.Set("external_auth_cache_time", "a")
 	form.Set("external_auth_cache_time", "a")
 	b, contentType, _ = getMultipartFormData(form, "", "")
 	b, contentType, _ = getMultipartFormData(form, "", "")
@@ -19850,30 +19710,6 @@ func TestWebUserAddMock(t *testing.T) {
 			}
 			}
 		}
 		}
 	}
 	}
-	if assert.Len(t, newUser.Filters.DataTransferLimits, 3) {
-		for _, dtLimit := range newUser.Filters.DataTransferLimits {
-			switch len(dtLimit.Sources) {
-			case 3:
-				assert.Equal(t, "192.168.3.0/24", dtLimit.Sources[0])
-				assert.Equal(t, "10.8.2.0/24", dtLimit.Sources[1])
-				assert.Equal(t, "::1/64", dtLimit.Sources[2])
-				assert.Equal(t, int64(0), dtLimit.UploadDataTransfer)
-				assert.Equal(t, int64(0), dtLimit.DownloadDataTransfer)
-				assert.Equal(t, int64(200), dtLimit.TotalDataTransfer)
-			case 2:
-				assert.Equal(t, "192.168.5.0/24", dtLimit.Sources[0])
-				assert.Equal(t, "10.8.0.0/16", dtLimit.Sources[1])
-				assert.Equal(t, int64(120), dtLimit.UploadDataTransfer)
-				assert.Equal(t, int64(100), dtLimit.DownloadDataTransfer)
-				assert.Equal(t, int64(0), dtLimit.TotalDataTransfer)
-			case 1:
-				assert.Equal(t, "127.0.1.1/32", dtLimit.Sources[0])
-				assert.Equal(t, int64(0), dtLimit.UploadDataTransfer)
-				assert.Equal(t, int64(0), dtLimit.DownloadDataTransfer)
-				assert.Equal(t, int64(0), dtLimit.TotalDataTransfer)
-			}
-		}
-	}
 	assert.Len(t, newUser.Groups, 3)
 	assert.Len(t, newUser.Groups, 3)
 	assert.Equal(t, sdk.TLSUsernameNone, newUser.Filters.TLSUsername)
 	assert.Equal(t, sdk.TLSUsernameNone, newUser.Filters.TLSUsername)
 	req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, newUser.Username), nil)
 	req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, newUser.Username), nil)

+ 86 - 0
internal/httpd/internal_test.go

@@ -3365,6 +3365,92 @@ func TestGetLogEventString(t *testing.T) {
 	assert.Empty(t, getLogEventString(0))
 	assert.Empty(t, getLogEventString(0))
 }
 }
 
 
+func TestUserQuotaUsage(t *testing.T) {
+	usage := userQuotaUsage{
+		QuotaSize: 100,
+	}
+	require.True(t, usage.HasQuotaInfo())
+	require.NotEmpty(t, usage.GetQuotaSize())
+	providerConf := dataprovider.GetProviderConfig()
+	quotaTracking := dataprovider.GetQuotaTracking()
+	providerConf.TrackQuota = 0
+	err := dataprovider.Close()
+	assert.NoError(t, err)
+	err = dataprovider.Initialize(providerConf, configDir, true)
+	assert.NoError(t, err)
+	err = dataprovider.Close()
+	assert.NoError(t, err)
+	assert.False(t, usage.HasQuotaInfo())
+	providerConf.TrackQuota = quotaTracking
+	err = dataprovider.Initialize(providerConf, configDir, true)
+	assert.NoError(t, err)
+	usage.QuotaSize = 0
+	assert.False(t, usage.HasQuotaInfo())
+	assert.Empty(t, usage.GetQuotaSize())
+	assert.Equal(t, 0, usage.GetQuotaSizePercentage())
+	assert.False(t, usage.IsQuotaSizeLow())
+	assert.False(t, usage.IsDiskQuotaLow())
+	assert.False(t, usage.IsQuotaLow())
+	usage.UsedQuotaSize = 9
+	assert.NotEmpty(t, usage.GetQuotaSize())
+	usage.QuotaSize = 10
+	assert.True(t, usage.IsQuotaSizeLow())
+	assert.True(t, usage.IsDiskQuotaLow())
+	assert.True(t, usage.IsQuotaLow())
+	usage.DownloadDataTransfer = 1
+	assert.True(t, usage.HasQuotaInfo())
+	assert.True(t, usage.HasTranferQuota())
+	assert.Empty(t, usage.GetQuotaFiles())
+	assert.Equal(t, 0, usage.GetQuotaFilesPercentage())
+	usage.QuotaFiles = 1
+	assert.NotEmpty(t, usage.GetQuotaFiles())
+	usage.QuotaFiles = 0
+	usage.UsedQuotaFiles = 9
+	assert.NotEmpty(t, usage.GetQuotaFiles())
+	usage.QuotaFiles = 10
+	usage.DownloadDataTransfer = 0
+	assert.True(t, usage.IsQuotaFilesLow())
+	assert.True(t, usage.IsDiskQuotaLow())
+	assert.False(t, usage.IsTotalTransferQuotaLow())
+	assert.False(t, usage.IsUploadTransferQuotaLow())
+	assert.False(t, usage.IsDownloadTransferQuotaLow())
+	assert.Equal(t, 0, usage.GetTotalTransferQuotaPercentage())
+	assert.Equal(t, 0, usage.GetUploadTransferQuotaPercentage())
+	assert.Equal(t, 0, usage.GetDownloadTransferQuotaPercentage())
+	assert.Empty(t, usage.GetTotalTransferQuota())
+	assert.Empty(t, usage.GetUploadTransferQuota())
+	assert.Empty(t, usage.GetDownloadTransferQuota())
+	usage.TotalDataTransfer = 3
+	usage.UsedUploadDataTransfer = 1 * 1048576
+	assert.NotEmpty(t, usage.GetTotalTransferQuota())
+	usage.TotalDataTransfer = 0
+	assert.NotEmpty(t, usage.GetTotalTransferQuota())
+	assert.NotEmpty(t, usage.GetUploadTransferQuota())
+	usage.UploadDataTransfer = 2
+	assert.NotEmpty(t, usage.GetUploadTransferQuota())
+	usage.UsedDownloadDataTransfer = 1 * 1048576
+	assert.NotEmpty(t, usage.GetDownloadTransferQuota())
+	usage.DownloadDataTransfer = 2
+	assert.NotEmpty(t, usage.GetDownloadTransferQuota())
+	assert.False(t, usage.IsTransferQuotaLow())
+	usage.UsedDownloadDataTransfer = 8 * 1048576
+	usage.TotalDataTransfer = 10
+	assert.True(t, usage.IsTotalTransferQuotaLow())
+	assert.True(t, usage.IsTransferQuotaLow())
+	usage.TotalDataTransfer = 0
+	usage.UploadDataTransfer = 0
+	usage.DownloadDataTransfer = 0
+	assert.False(t, usage.IsTransferQuotaLow())
+	usage.UploadDataTransfer = 10
+	usage.UsedUploadDataTransfer = 9 * 1048576
+	assert.True(t, usage.IsUploadTransferQuotaLow())
+	assert.True(t, usage.IsTransferQuotaLow())
+	usage.DownloadDataTransfer = 10
+	usage.UsedDownloadDataTransfer = 9 * 1048576
+	assert.True(t, usage.IsDownloadTransferQuotaLow())
+	assert.True(t, usage.IsTransferQuotaLow())
+}
+
 func isSharedProviderSupported() bool {
 func isSharedProviderSupported() bool {
 	// SQLite shares the implementation with other SQL-based provider but it makes no sense
 	// SQLite shares the implementation with other SQL-based provider but it makes no sense
 	// to use it outside test cases
 	// to use it outside test cases

+ 0 - 49
internal/httpd/webadmin.go

@@ -1353,50 +1353,6 @@ func getUserPermissionsFromPostFields(r *http.Request) map[string][]string {
 	return permissions
 	return permissions
 }
 }
 
 
-func getDataTransferLimitsFromPostFields(r *http.Request) ([]sdk.DataTransferLimit, error) {
-	var result []sdk.DataTransferLimit
-
-	for k := range r.Form {
-		if strings.HasPrefix(k, "data_transfer_limit_sources") {
-			sources := getSliceFromDelimitedValues(r.Form.Get(k), ",")
-			if len(sources) > 0 {
-				dtLimit := sdk.DataTransferLimit{
-					Sources: sources,
-				}
-				idx := strings.TrimPrefix(k, "data_transfer_limit_sources")
-				ul := r.Form.Get(fmt.Sprintf("upload_data_transfer_source%v", idx))
-				dl := r.Form.Get(fmt.Sprintf("download_data_transfer_source%v", idx))
-				total := r.Form.Get(fmt.Sprintf("total_data_transfer_source%v", idx))
-				if ul != "" {
-					dataUL, err := strconv.ParseInt(ul, 10, 64)
-					if err != nil {
-						return result, fmt.Errorf("invalid upload_data_transfer_source%v %q: %w", idx, ul, err)
-					}
-					dtLimit.UploadDataTransfer = dataUL
-				}
-				if dl != "" {
-					dataDL, err := strconv.ParseInt(dl, 10, 64)
-					if err != nil {
-						return result, fmt.Errorf("invalid download_data_transfer_source%v %q: %w", idx, dl, err)
-					}
-					dtLimit.DownloadDataTransfer = dataDL
-				}
-				if total != "" {
-					dataTotal, err := strconv.ParseInt(total, 10, 64)
-					if err != nil {
-						return result, fmt.Errorf("invalid total_data_transfer_source%v %q: %w", idx, total, err)
-					}
-					dtLimit.TotalDataTransfer = dataTotal
-				}
-
-				result = append(result, dtLimit)
-			}
-		}
-	}
-
-	return result, nil
-}
-
 func getBandwidthLimitsFromPostFields(r *http.Request) ([]sdk.BandwidthLimit, error) {
 func getBandwidthLimitsFromPostFields(r *http.Request) ([]sdk.BandwidthLimit, error) {
 	var result []sdk.BandwidthLimit
 	var result []sdk.BandwidthLimit
 
 
@@ -1534,10 +1490,6 @@ func getFiltersFromUserPostFields(r *http.Request) (sdk.BaseUserFilters, error)
 	if err != nil {
 	if err != nil {
 		return filters, err
 		return filters, err
 	}
 	}
-	dtLimits, err := getDataTransferLimitsFromPostFields(r)
-	if err != nil {
-		return filters, err
-	}
 	maxFileSize, err := util.ParseBytes(r.Form.Get("max_upload_file_size"))
 	maxFileSize, err := util.ParseBytes(r.Form.Get("max_upload_file_size"))
 	if err != nil {
 	if err != nil {
 		return filters, fmt.Errorf("invalid max upload file size: %w", err)
 		return filters, fmt.Errorf("invalid max upload file size: %w", err)
@@ -1558,7 +1510,6 @@ func getFiltersFromUserPostFields(r *http.Request) (sdk.BaseUserFilters, error)
 		filters.FTPSecurity = 1
 		filters.FTPSecurity = 1
 	}
 	}
 	filters.BandwidthLimits = bwLimits
 	filters.BandwidthLimits = bwLimits
-	filters.DataTransferLimits = dtLimits
 	filters.AllowedIP = getSliceFromDelimitedValues(r.Form.Get("allowed_ip"), ",")
 	filters.AllowedIP = getSliceFromDelimitedValues(r.Form.Get("allowed_ip"), ",")
 	filters.DeniedIP = getSliceFromDelimitedValues(r.Form.Get("denied_ip"), ",")
 	filters.DeniedIP = getSliceFromDelimitedValues(r.Form.Get("denied_ip"), ",")
 	filters.DeniedLoginMethods = r.Form["denied_login_methods"]
 	filters.DeniedLoginMethods = r.Form["denied_login_methods"]

+ 186 - 4
internal/httpd/webclient.go

@@ -21,6 +21,7 @@ import (
 	"fmt"
 	"fmt"
 	"html/template"
 	"html/template"
 	"io"
 	"io"
+	"math"
 	"net/http"
 	"net/http"
 	"net/url"
 	"net/url"
 	"os"
 	"os"
@@ -155,6 +156,7 @@ type filesPage struct {
 	Error           string
 	Error           string
 	Paths           []dirMapping
 	Paths           []dirMapping
 	HasIntegrations bool
 	HasIntegrations bool
+	QuotaUsage      *userQuotaUsage
 }
 }
 
 
 type shareLoginPage struct {
 type shareLoginPage struct {
@@ -229,6 +231,185 @@ type clientSharePage struct {
 	IsAdd bool
 	IsAdd bool
 }
 }
 
 
+type userQuotaUsage struct {
+	QuotaSize                int64
+	QuotaFiles               int
+	UsedQuotaSize            int64
+	UsedQuotaFiles           int
+	UploadDataTransfer       int64
+	DownloadDataTransfer     int64
+	TotalDataTransfer        int64
+	UsedUploadDataTransfer   int64
+	UsedDownloadDataTransfer int64
+}
+
+func (u *userQuotaUsage) HasQuotaInfo() bool {
+	if dataprovider.GetQuotaTracking() == 0 {
+		return false
+	}
+	if u.HasDiskQuota() {
+		return true
+	}
+	return u.HasTranferQuota()
+}
+
+func (u *userQuotaUsage) HasDiskQuota() bool {
+	if u.QuotaSize > 0 || u.UsedQuotaSize > 0 {
+		return true
+	}
+	return u.QuotaFiles > 0 || u.UsedQuotaFiles > 0
+}
+
+func (u *userQuotaUsage) HasTranferQuota() bool {
+	if u.TotalDataTransfer > 0 || u.UploadDataTransfer > 0 || u.DownloadDataTransfer > 0 {
+		return true
+	}
+	return u.UsedDownloadDataTransfer > 0 || u.UsedUploadDataTransfer > 0
+}
+
+func (u *userQuotaUsage) GetQuotaSize() string {
+	if u.QuotaSize > 0 {
+		return fmt.Sprintf("%s/%s", util.ByteCountIEC(u.UsedQuotaSize), util.ByteCountIEC(u.QuotaSize))
+	}
+	if u.UsedQuotaSize > 0 {
+		return util.ByteCountIEC(u.UsedQuotaSize)
+	}
+	return ""
+}
+
+func (u *userQuotaUsage) GetQuotaFiles() string {
+	if u.QuotaFiles > 0 {
+		return fmt.Sprintf("%d/%d", u.UsedQuotaFiles, u.QuotaFiles)
+	}
+	if u.UsedQuotaFiles > 0 {
+		return strconv.FormatInt(int64(u.UsedQuotaFiles), 10)
+	}
+	return ""
+}
+
+func (u *userQuotaUsage) GetQuotaSizePercentage() int {
+	if u.QuotaSize > 0 {
+		return int(math.Round(100 * float64(u.UsedQuotaSize) / float64(u.QuotaSize)))
+	}
+	return 0
+}
+
+func (u *userQuotaUsage) GetQuotaFilesPercentage() int {
+	if u.QuotaFiles > 0 {
+		return int(math.Round(100 * float64(u.UsedQuotaFiles) / float64(u.QuotaFiles)))
+	}
+	return 0
+}
+
+func (u *userQuotaUsage) IsQuotaSizeLow() bool {
+	return u.GetQuotaSizePercentage() > 85
+}
+
+func (u *userQuotaUsage) IsQuotaFilesLow() bool {
+	return u.GetQuotaFilesPercentage() > 85
+}
+
+func (u *userQuotaUsage) IsDiskQuotaLow() bool {
+	return u.IsQuotaSizeLow() || u.IsQuotaFilesLow()
+}
+
+func (u *userQuotaUsage) GetTotalTransferQuota() string {
+	total := u.UsedUploadDataTransfer + u.UsedDownloadDataTransfer
+	if u.TotalDataTransfer > 0 {
+		return fmt.Sprintf("%s/%s", util.ByteCountIEC(total), util.ByteCountIEC(u.TotalDataTransfer*1048576))
+	}
+	if total > 0 {
+		return util.ByteCountIEC(total)
+	}
+	return ""
+}
+
+func (u *userQuotaUsage) GetUploadTransferQuota() string {
+	if u.UploadDataTransfer > 0 {
+		return fmt.Sprintf("%s/%s", util.ByteCountIEC(u.UsedUploadDataTransfer),
+			util.ByteCountIEC(u.UploadDataTransfer*1048576))
+	}
+	if u.UsedUploadDataTransfer > 0 {
+		return util.ByteCountIEC(u.UsedUploadDataTransfer)
+	}
+	return ""
+}
+
+func (u *userQuotaUsage) GetDownloadTransferQuota() string {
+	if u.DownloadDataTransfer > 0 {
+		return fmt.Sprintf("%s/%s", util.ByteCountIEC(u.UsedDownloadDataTransfer),
+			util.ByteCountIEC(u.DownloadDataTransfer*1048576))
+	}
+	if u.UsedDownloadDataTransfer > 0 {
+		return util.ByteCountIEC(u.UsedDownloadDataTransfer)
+	}
+	return ""
+}
+
+func (u *userQuotaUsage) GetTotalTransferQuotaPercentage() int {
+	if u.TotalDataTransfer > 0 {
+		return int(math.Round(100 * float64(u.UsedDownloadDataTransfer+u.UsedUploadDataTransfer) / float64(u.TotalDataTransfer*1048576)))
+	}
+	return 0
+}
+
+func (u *userQuotaUsage) GetUploadTransferQuotaPercentage() int {
+	if u.UploadDataTransfer > 0 {
+		return int(math.Round(100 * float64(u.UsedUploadDataTransfer) / float64(u.UploadDataTransfer*1048576)))
+	}
+	return 0
+}
+
+func (u *userQuotaUsage) GetDownloadTransferQuotaPercentage() int {
+	if u.DownloadDataTransfer > 0 {
+		return int(math.Round(100 * float64(u.UsedDownloadDataTransfer) / float64(u.DownloadDataTransfer*1048576)))
+	}
+	return 0
+}
+
+func (u *userQuotaUsage) IsTotalTransferQuotaLow() bool {
+	if u.TotalDataTransfer > 0 {
+		return u.GetTotalTransferQuotaPercentage() > 85
+	}
+	return false
+}
+
+func (u *userQuotaUsage) IsUploadTransferQuotaLow() bool {
+	if u.UploadDataTransfer > 0 {
+		return u.GetUploadTransferQuotaPercentage() > 85
+	}
+	return false
+}
+
+func (u *userQuotaUsage) IsDownloadTransferQuotaLow() bool {
+	if u.DownloadDataTransfer > 0 {
+		return u.GetDownloadTransferQuotaPercentage() > 85
+	}
+	return false
+}
+
+func (u *userQuotaUsage) IsTransferQuotaLow() bool {
+	return u.IsTotalTransferQuotaLow() || u.IsUploadTransferQuotaLow() || u.IsDownloadTransferQuotaLow()
+}
+
+func (u *userQuotaUsage) IsQuotaLow() bool {
+	return u.IsDiskQuotaLow() || u.IsTransferQuotaLow()
+}
+
+func newUserQuotaUsage(u *dataprovider.User) *userQuotaUsage {
+	return &userQuotaUsage{
+		QuotaSize:                u.QuotaSize,
+		QuotaFiles:               u.QuotaFiles,
+		UsedQuotaSize:            u.UsedQuotaSize,
+		UsedQuotaFiles:           u.UsedQuotaFiles,
+		TotalDataTransfer:        u.TotalDataTransfer,
+		UploadDataTransfer:       u.UploadDataTransfer,
+		DownloadDataTransfer:     u.DownloadDataTransfer,
+		UsedUploadDataTransfer:   u.UsedUploadDataTransfer,
+		UsedDownloadDataTransfer: u.UsedDownloadDataTransfer,
+	}
+}
+
 func getFileObjectURL(baseDir, name, baseWebPath string) string {
 func getFileObjectURL(baseDir, name, baseWebPath string) string {
 	return fmt.Sprintf("%v?path=%v&_=%v", baseWebPath, url.QueryEscape(path.Join(baseDir, name)), time.Now().UTC().Unix())
 	return fmt.Sprintf("%v?path=%v&_=%v", baseWebPath, url.QueryEscape(path.Join(baseDir, name)), time.Now().UTC().Unix())
 }
 }
@@ -595,7 +776,7 @@ func (s *httpdServer) renderUploadToSharePage(w http.ResponseWriter, r *http.Req
 	renderClientTemplate(w, templateUploadToShare, data)
 	renderClientTemplate(w, templateUploadToShare, data)
 }
 }
 
 
-func (s *httpdServer) renderFilesPage(w http.ResponseWriter, r *http.Request, dirName, error string, user dataprovider.User,
+func (s *httpdServer) renderFilesPage(w http.ResponseWriter, r *http.Request, dirName, error string, user *dataprovider.User,
 	hasIntegrations bool,
 	hasIntegrations bool,
 ) {
 ) {
 	data := filesPage{
 	data := filesPage{
@@ -615,6 +796,7 @@ func (s *httpdServer) renderFilesPage(w http.ResponseWriter, r *http.Request, di
 		CanShare:        user.CanManageShares(),
 		CanShare:        user.CanManageShares(),
 		HasIntegrations: hasIntegrations,
 		HasIntegrations: hasIntegrations,
 		Paths:           getDirMapping(dirName, webClientFilesPath),
 		Paths:           getDirMapping(dirName, webClientFilesPath),
+		QuotaUsage:      newUserQuotaUsage(user),
 	}
 	}
 	renderClientTemplate(w, templateClientFiles, data)
 	renderClientTemplate(w, templateClientFiles, data)
 }
 }
@@ -964,11 +1146,11 @@ func (s *httpdServer) handleClientGetFiles(w http.ResponseWriter, r *http.Reques
 	}
 	}
 	if err != nil {
 	if err != nil {
 		s.renderFilesPage(w, r, path.Dir(name), fmt.Sprintf("unable to stat file %q: %v", name, err),
 		s.renderFilesPage(w, r, path.Dir(name), fmt.Sprintf("unable to stat file %q: %v", name, err),
-			user, len(s.binding.WebClientIntegrations) > 0)
+			&user, len(s.binding.WebClientIntegrations) > 0)
 		return
 		return
 	}
 	}
 	if info.IsDir() {
 	if info.IsDir() {
-		s.renderFilesPage(w, r, name, "", user, len(s.binding.WebClientIntegrations) > 0)
+		s.renderFilesPage(w, r, name, "", &user, len(s.binding.WebClientIntegrations) > 0)
 		return
 		return
 	}
 	}
 	if status, err := downloadFile(w, r, connection, name, info, false, nil); err != nil && status != 0 {
 	if status, err := downloadFile(w, r, connection, name, info, false, nil); err != nil && status != 0 {
@@ -977,7 +1159,7 @@ func (s *httpdServer) handleClientGetFiles(w http.ResponseWriter, r *http.Reques
 				s.renderClientMessagePage(w, r, http.StatusText(status), "", status, err, "")
 				s.renderClientMessagePage(w, r, http.StatusText(status), "", status, err, "")
 				return
 				return
 			}
 			}
-			s.renderFilesPage(w, r, path.Dir(name), err.Error(), user, len(s.binding.WebClientIntegrations) > 0)
+			s.renderFilesPage(w, r, path.Dir(name), err.Error(), &user, len(s.binding.WebClientIntegrations) > 0)
 		}
 		}
 	}
 	}
 }
 }

+ 0 - 27
internal/httpdtest/httpdtest.go

@@ -2487,9 +2487,6 @@ func compareUserFilters(expected sdk.BaseUserFilters, actual sdk.BaseUserFilters
 	if err := compareUserBandwidthLimitFilters(expected, actual); err != nil {
 	if err := compareUserBandwidthLimitFilters(expected, actual); err != nil {
 		return err
 		return err
 	}
 	}
-	if err := compareUserDataTransferLimitFilters(expected, actual); err != nil {
-		return err
-	}
 	return compareUserFilePatternsFilters(expected, actual)
 	return compareUserFilePatternsFilters(expected, actual)
 }
 }
 
 
@@ -2505,30 +2502,6 @@ func checkFilterMatch(expected []string, actual []string) bool {
 	return true
 	return true
 }
 }
 
 
-func compareUserDataTransferLimitFilters(expected sdk.BaseUserFilters, actual sdk.BaseUserFilters) error {
-	if len(expected.DataTransferLimits) != len(actual.DataTransferLimits) {
-		return errors.New("data transfer limits filters mismatch")
-	}
-	for idx, l := range expected.DataTransferLimits {
-		if actual.DataTransferLimits[idx].UploadDataTransfer != l.UploadDataTransfer {
-			return errors.New("data transfer limit upload_data_transfer mismatch")
-		}
-		if actual.DataTransferLimits[idx].DownloadDataTransfer != l.DownloadDataTransfer {
-			return errors.New("data transfer limit download_data_transfer mismatch")
-		}
-		if actual.DataTransferLimits[idx].TotalDataTransfer != l.TotalDataTransfer {
-			return errors.New("data transfer limit total_data_transfer mismatch")
-		}
-		for _, source := range actual.DataTransferLimits[idx].Sources {
-			if !util.Contains(l.Sources, source) {
-				return errors.New("data transfer limit source mismatch")
-			}
-		}
-	}
-
-	return nil
-}
-
 func compareUserBandwidthLimitFilters(expected sdk.BaseUserFilters, actual sdk.BaseUserFilters) error {
 func compareUserBandwidthLimitFilters(expected sdk.BaseUserFilters, actual sdk.BaseUserFilters) error {
 	if len(expected.BandwidthLimits) != len(actual.BandwidthLimits) {
 	if len(expected.BandwidthLimits) != len(actual.BandwidthLimits) {
 		return errors.New("bandwidth limits filters mismatch")
 		return errors.New("bandwidth limits filters mismatch")

+ 0 - 21
openapi/openapi.yaml

@@ -5455,23 +5455,6 @@ components:
           type: integer
           type: integer
           format: int32
           format: int32
           description: 'Maximum download bandwidth as KB/s, 0 means unlimited'
           description: 'Maximum download bandwidth as KB/s, 0 means unlimited'
-    DataTransferLimit:
-      type: object
-      properties:
-        sources:
-          type: array
-          items:
-            type: string
-          description: 'Source networks in CIDR notation as defined in RFC 4632 and RFC 4291 for example `192.0.2.0/24` or `2001:db8::/32`. The limit applies if the defined networks contain the client IP'
-        upload_data_transfer:
-          type: integer
-          description: 'Maximum data transfer allowed for uploads as MB. 0 means no limit'
-        download_data_transfer:
-          type: integer
-          description: 'Maximum data transfer allowed for downloads as MB. 0 means no limit'
-        total_data_transfer:
-          type: integer
-          description: 'Maximum total data transfer as MB. 0 means unlimited. You can set a total data transfer instead of the individual values for uploads and downloads'
     BaseUserFilters:
     BaseUserFilters:
       type: object
       type: object
       properties:
       properties:
@@ -5532,10 +5515,6 @@ components:
           type: array
           type: array
           items:
           items:
             $ref: '#/components/schemas/BandwidthLimit'
             $ref: '#/components/schemas/BandwidthLimit'
-        data_transfer_limits:
-          type: array
-          items:
-            $ref: '#/components/schemas/DataTransferLimit'
         external_auth_cache_time:
         external_auth_cache_time:
           type: integer
           type: integer
           description: 'Defines the cache time, in seconds, for users authenticated using an external auth hook. 0 means no cache'
           description: 'Defines the cache time, in seconds, for users authenticated using an external auth hook. 0 means no cache'

+ 0 - 99
templates/webadmin/group.html

@@ -554,105 +554,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                                 </div>
                                 </div>
                             </div>
                             </div>
 
 
-                            <div class="card bg-light mb-3">
-                                <div class="card-header">
-                                    <b>Per-source data transfer limits</b>
-                                </div>
-                                <div class="card-body">
-                                    <div class="form-group row">
-                                        <div class="col-md-12 form_field_dtlimits_outer">
-                                            {{range $idx, $dtLimit := .Group.UserSettings.Filters.DataTransferLimits -}}
-                                            <div class="row form_field_dtlimits_outer_row">
-                                                <div class="form-group col-md-5">
-                                                    <textarea class="form-control" id="idDataTransferLimitSources{{$idx}}" name="data_transfer_limit_sources{{$idx}}" rows="4" placeholder=""
-                                                            aria-describedby="dtLimitSourcesHelpBlock{{$idx}}">{{$dtLimit.GetSourcesAsString}}</textarea>
-                                                    <small id="dtLimitSourcesHelpBlock{{$idx}}" class="form-text text-muted">
-                                                        Comma separated IP/Mask in CIDR format, example: "192.168.1.0/24,10.8.0.100/32"
-                                                    </small>
-                                                </div>
-                                                <div class="col-md-3">
-                                                    <div class="form-group">
-                                                        <input type="number" class="form-control" id="idUploadTransferSource{{$idx}}" name="upload_data_transfer_source{{$idx}}"
-                                                            placeholder="" value="{{$dtLimit.UploadDataTransfer}}" min="0" aria-describedby="ulDtHelpBlock{{$idx}}">
-                                                        <small id="ulDtHelpBlock{{$idx}}" class="form-text text-muted">
-                                                            UL (MB). 0 means no limit
-                                                        </small>
-                                                    </div>
-                                                    <div class="form-group">
-                                                        <input type="number" class="form-control" id="idDownloadTransferSource{{$idx}}" name="download_data_transfer_source{{$idx}}"
-                                                            placeholder="" value="{{$dtLimit.DownloadDataTransfer}}" min="0" aria-describedby="dlDtHelpBlock{{$idx}}">
-                                                        <small id="dlDtHelpBlock{{$idx}}" class="form-text text-muted">
-                                                            DL (MB). 0 means no limit
-                                                        </small>
-                                                    </div>
-                                                </div>
-                                                <div class="col-md-3">
-                                                    <div class="form-group">
-                                                        <input type="number" class="form-control" id="idTotalTransferSource{{$idx}}" name="total_data_transfer_source{{$idx}}"
-                                                            placeholder="" value="{{$dtLimit.TotalDataTransfer}}" min="0" aria-describedby="totalDtHelpBlock{{$idx}}">
-                                                        <small id="totalDtHelpBlock{{$idx}}" class="form-text text-muted">
-                                                            Total (MB). 0 means no limit
-                                                        </small>
-                                                    </div>
-                                                </div>
-                                                <div class="form-group col-md-1">
-                                                    <button class="btn btn-circle btn-danger remove_dtlimit_btn_frm_field">
-                                                        <i class="fas fa-trash"></i>
-                                                    </button>
-                                                </div>
-                                            </div>
-                                            {{else}}
-                                            <div class="row form_field_dtlimits_outer_row">
-                                                <div class="form-group col-md-5">
-                                                    <textarea class="form-control" id="idDataTransferLimitSources0" name="data_transfer_limit_sources0" rows="4" placeholder=""
-                                                            aria-describedby="dtLimitSourcesHelpBlock0"></textarea>
-                                                    <small id="dtLimitSourcesHelpBlock0" class="form-text text-muted">
-                                                        Comma separated IP/Mask in CIDR format, example: "192.168.1.0/24,10.8.0.100/32"
-                                                    </small>
-                                                </div>
-                                                <div class="col-md-3">
-                                                    <div class="form-group">
-                                                        <input type="number" class="form-control" id="idUploadTransferSource0" name="upload_data_transfer_source0"
-                                                            placeholder="" value="" min="0" aria-describedby="ulDtHelpBlock0">
-                                                        <small id="ulDtHelpBlock0" class="form-text text-muted">
-                                                            UL (MB). 0 means no limit
-                                                        </small>
-                                                    </div>
-                                                    <div class="form-group">
-                                                        <input type="number" class="form-control" id="idDownloadTransferSource0" name="download_data_transfer_source0"
-                                                            placeholder="" value="" min="0" aria-describedby="dlDtHelpBlock0">
-                                                        <small id="dlDtHelpBlock0" class="form-text text-muted">
-                                                            DL (MB). 0 means no limit
-                                                        </small>
-                                                    </div>
-                                                </div>
-                                                <div class="col-md-3">
-                                                    <div class="form-group">
-                                                        <input type="number" class="form-control" id="idTotalTransferSource0" name="total_data_transfer_source0"
-                                                            placeholder="" value="" min="0" aria-describedby="totalDtHelpBlock0">
-                                                        <small id="totalDtHelpBlock0" class="form-text text-muted">
-                                                            Total (MB). 0 means no limit
-                                                        </small>
-                                                    </div>
-                                                </div>
-                                                <div class="form-group col-md-1">
-                                                    <button class="btn btn-circle btn-danger remove_dtlimit_btn_frm_field">
-                                                        <i class="fas fa-trash"></i>
-                                                    </button>
-                                                </div>
-                                            </div>
-                                            {{end}}
-                                        </div>
-                                    </div>
-
-                                    <div class="row mx-1">
-                                        <button type="button" class="btn btn-secondary add_new_dtlimit_field_btn">
-                                            <i class="fas fa-plus"></i> Add new data transfer limit
-                                        </button>
-                                    </div>
-                                </div>
-                            </div>
-
                         </div>
                         </div>
                     </div>
                     </div>
                 </div>
                 </div>

+ 0 - 52
templates/webadmin/sharedcomponents.html

@@ -137,58 +137,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
         $(this).closest(".form_field_bwlimits_outer_row").remove();
         $(this).closest(".form_field_bwlimits_outer_row").remove();
     });
     });
 
 
-    $("body").on("click", ".add_new_dtlimit_field_btn", function () {
-        let index = $(".form_field_dtlimits_outer").find(".form_field_dtlimits_outer_row").length;
-        while (document.getElementById("idDataTransferLimitSources"+index) != null){
-            index++;
-        }
-        $(".form_field_dtlimits_outer").append(`
-                <div class="row form_field_dtlimits_outer_row">
-                    <div class="form-group col-md-5">
-                        <textarea class="form-control" id="idDataTransferLimitSources${index}" name="data_transfer_limit_sources${index}" rows="4" placeholder=""
-                            aria-describedby="dtLimitSourcesHelpBlock${index}"></textarea>
-                        <small id="dtLimitSourcesHelpBlock${index}" class="form-text text-muted">
-                            Comma separated IP/Mask in CIDR format, example: "192.168.1.0/24,10.8.0.100/32"
-                        </small>
-                    </div>
-                    <div class="col-md-3">
-                        <div class="form-group">
-                            <input type="number" class="form-control" id="idUploadTransferSource${index}" name="upload_data_transfer_source${index}"
-                                placeholder="" value="" min="0" aria-describedby="ulDtHelpBlock${index}">
-                            <small id="ulDtHelpBlock${index}" class="form-text text-muted">
-                                UL (MB). 0 means no limit
-                            </small>
-                        </div>
-                        <div class="form-group">
-                            <input type="number" class="form-control" id="idDownloadTransferSource${index}" name="download_data_transfer_source${index}"
-                                placeholder="" value="" min="0" aria-describedby="dlDtHelpBlock${index}">
-                            <small id="dlDtHelpBlock${index}" class="form-text text-muted">
-                                DL (MB). 0 means no limit
-                            </small>
-                        </div>
-                    </div>
-                    <div class="col-md-3">
-                        <div class="form-group">
-                            <input type="number" class="form-control" id="idTotalTransferSource${index}" name="total_data_transfer_source${index}"
-                                placeholder="" value="" min="0" aria-describedby="totalDtHelpBlock${index}">
-                            <small id="totalDtHelpBlock${index}" class="form-text text-muted">
-                                Total (MB). 0 means no limit
-                            </small>
-                        </div>
-                    </div>
-                    <div class="form-group col-md-1">
-                        <button class="btn btn-circle btn-danger remove_dtlimit_btn_frm_field">
-                            <i class="fas fa-trash"></i>
-                        </button>
-                    </div>
-                </div>
-            `);
-    });
-
-    $("body").on("click", ".remove_dtlimit_btn_frm_field", function () {
-        $(this).closest(".form_field_dtlimits_outer_row").remove();
-    });
-
     $("body").on("click", ".add_new_pattern_field_btn", function () {
     $("body").on("click", ".add_new_pattern_field_btn", function () {
         let index = $(".form_field_patterns_outer").find(".form_field_patterns_outer_row").length;
         let index = $(".form_field_patterns_outer").find(".form_field_patterns_outer_row").length;
         while (document.getElementById("idPatternPath"+index) != null){
         while (document.getElementById("idPatternPath"+index) != null){

+ 0 - 99
templates/webadmin/user.html

@@ -834,105 +834,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                                 </div>
                                 </div>
                             </div>
                             </div>
 
 
-                            <div class="card bg-light mb-3">
-                                <div class="card-header">
-                                    <b>Per-source data transfer limits</b>
-                                </div>
-                                <div class="card-body">
-                                    <div class="form-group row">
-                                        <div class="col-md-12 form_field_dtlimits_outer">
-                                            {{range $idx, $dtLimit := .User.Filters.DataTransferLimits -}}
-                                            <div class="row form_field_dtlimits_outer_row">
-                                                <div class="form-group col-md-5">
-                                                    <textarea class="form-control" id="idDataTransferLimitSources{{$idx}}" name="data_transfer_limit_sources{{$idx}}" rows="4" placeholder=""
-                                                            aria-describedby="dtLimitSourcesHelpBlock{{$idx}}">{{$dtLimit.GetSourcesAsString}}</textarea>
-                                                    <small id="dtLimitSourcesHelpBlock{{$idx}}" class="form-text text-muted">
-                                                        Comma separated IP/Mask in CIDR format, example: "192.168.1.0/24,10.8.0.100/32"
-                                                    </small>
-                                                </div>
-                                                <div class="col-md-3">
-                                                    <div class="form-group">
-                                                        <input type="number" class="form-control" id="idUploadTransferSource{{$idx}}" name="upload_data_transfer_source{{$idx}}"
-                                                            placeholder="" value="{{$dtLimit.UploadDataTransfer}}" min="0" aria-describedby="ulDtHelpBlock{{$idx}}">
-                                                        <small id="ulDtHelpBlock{{$idx}}" class="form-text text-muted">
-                                                            UL (MB). 0 means no limit
-                                                        </small>
-                                                    </div>
-                                                    <div class="form-group">
-                                                        <input type="number" class="form-control" id="idDownloadTransferSource{{$idx}}" name="download_data_transfer_source{{$idx}}"
-                                                            placeholder="" value="{{$dtLimit.DownloadDataTransfer}}" min="0" aria-describedby="dlDtHelpBlock{{$idx}}">
-                                                        <small id="dlDtHelpBlock{{$idx}}" class="form-text text-muted">
-                                                            DL (MB). 0 means no limit
-                                                        </small>
-                                                    </div>
-                                                </div>
-                                                <div class="col-md-3">
-                                                    <div class="form-group">
-                                                        <input type="number" class="form-control" id="idTotalTransferSource{{$idx}}" name="total_data_transfer_source{{$idx}}"
-                                                            placeholder="" value="{{$dtLimit.TotalDataTransfer}}" min="0" aria-describedby="totalDtHelpBlock{{$idx}}">
-                                                        <small id="totalDtHelpBlock{{$idx}}" class="form-text text-muted">
-                                                            Total (MB). 0 means no limit
-                                                        </small>
-                                                    </div>
-                                                </div>
-                                                <div class="form-group col-md-1">
-                                                    <button class="btn btn-circle btn-danger remove_dtlimit_btn_frm_field">
-                                                        <i class="fas fa-trash"></i>
-                                                    </button>
-                                                </div>
-                                            </div>
-                                            {{else}}
-                                            <div class="row form_field_dtlimits_outer_row">
-                                                <div class="form-group col-md-5">
-                                                    <textarea class="form-control" id="idDataTransferLimitSources0" name="data_transfer_limit_sources0" rows="4" placeholder=""
-                                                            aria-describedby="dtLimitSourcesHelpBlock0"></textarea>
-                                                    <small id="dtLimitSourcesHelpBlock0" class="form-text text-muted">
-                                                        Comma separated IP/Mask in CIDR format, example: "192.168.1.0/24,10.8.0.100/32"
-                                                    </small>
-                                                </div>
-                                                <div class="col-md-3">
-                                                    <div class="form-group">
-                                                        <input type="number" class="form-control" id="idUploadTransferSource0" name="upload_data_transfer_source0"
-                                                            placeholder="" value="" min="0" aria-describedby="ulDtHelpBlock0">
-                                                        <small id="ulDtHelpBlock0" class="form-text text-muted">
-                                                            UL (MB). 0 means no limit
-                                                        </small>
-                                                    </div>
-                                                    <div class="form-group">
-                                                        <input type="number" class="form-control" id="idDownloadTransferSource0" name="download_data_transfer_source0"
-                                                            placeholder="" value="" min="0" aria-describedby="dlDtHelpBlock0">
-                                                        <small id="dlDtHelpBlock0" class="form-text text-muted">
-                                                            DL (MB). 0 means no limit
-                                                        </small>
-                                                    </div>
-                                                </div>
-                                                <div class="col-md-3">
-                                                    <div class="form-group">
-                                                        <input type="number" class="form-control" id="idTotalTransferSource0" name="total_data_transfer_source0"
-                                                            placeholder="" value="" min="0" aria-describedby="totalDtHelpBlock0">
-                                                        <small id="totalDtHelpBlock0" class="form-text text-muted">
-                                                            Total (MB). 0 means no limit
-                                                        </small>
-                                                    </div>
-                                                </div>
-                                                <div class="form-group col-md-1">
-                                                    <button class="btn btn-circle btn-danger remove_dtlimit_btn_frm_field">
-                                                        <i class="fas fa-trash"></i>
-                                                    </button>
-                                                </div>
-                                            </div>
-                                            {{end}}
-                                        </div>
-                                    </div>
-
-                                    <div class="row mx-1">
-                                        <button type="button" class="btn btn-secondary add_new_dtlimit_field_btn">
-                                            <i class="fas fa-plus"></i> Add new data transfer limit
-                                        </button>
-                                    </div>
-                                </div>
-                            </div>
-
                         </div>
                         </div>
                     </div>
                     </div>
                 </div>
                 </div>

+ 76 - 0
templates/webclient/files.html

@@ -34,6 +34,82 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 </style>
 </style>
 {{end}}
 {{end}}
 
 
+{{define "additionalnavitems"}}
+{{if .QuotaUsage.HasQuotaInfo}}
+<li class="nav-item dropdown no-arrow mx-1">
+    <a class="nav-link dropdown-toggle" href="#" id="quotaDropdown" role="button"
+        data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+        <span class="mr-2 d-none d-lg-inline text-gray-600 small">Quota</span>
+        {{if .QuotaUsage.IsQuotaLow}}
+        <i class="fas fa-exclamation-triangle fa-fw"></i>
+        {{else}}
+        <i class="fas fa-info fa-fw"></i>
+        {{end}}
+    </a>
+    <div class="dropdown-list dropdown-menu dropdown-menu-right shadow animated--grow-in"
+        ria-labelledby="alertsDropdown">
+        <h6 class="dropdown-header">
+            Quota usage
+        </h6>
+        {{ if .QuotaUsage.HasDiskQuota}}
+        <a class="dropdown-item d-flex align-items-center" href="#">
+            <div class="mr-3">
+                <div class="icon-circle  {{if .QuotaUsage.IsDiskQuotaLow}}bg-warning{{else}}bg-success{{end}}">
+                    <i class="fas fa-hdd text-white"></i>
+                </div>
+            </div>
+            <div>
+                <div class="small text-gray-500">Disk quota</div>
+                {{$size := .QuotaUsage.GetQuotaSize}}
+                {{$files := .QuotaUsage.GetQuotaFiles}}
+                {{if $size}}
+                {{$percentage := .QuotaUsage.GetQuotaSizePercentage}}
+                <span class="font-weight-bold {{if .QuotaUsage.IsQuotaSizeLow}}text-warning{{end}}">Size: {{$size}}{{if gt $percentage 0}} ({{$percentage}}%){{end}}</span>
+                {{if $files}}<br>{{end}}
+                {{end}}
+                {{if $files}}
+                {{$percentage := .QuotaUsage.GetQuotaFilesPercentage}}
+                <span class="font-weight-bold {{if .QuotaUsage.IsQuotaFilesLow}}text-warning{{end}}">Files: {{$files}}{{if gt $percentage 0}} ({{$percentage}}%){{end}}</span>
+                {{end}}
+            </div>
+        </a>
+        {{end}}
+        {{ if .QuotaUsage.HasTranferQuota}}
+        <a class="dropdown-item d-flex align-items-center" href="#">
+            <div class="mr-3">
+                <div class="icon-circle {{if .QuotaUsage.IsTransferQuotaLow}}bg-warning{{else}}bg-success{{end}}">
+                    <i class="fas fa-exchange-alt text-white"></i>
+                </div>
+            </div>
+            <div>
+                <div class="small text-gray-500">Transfer quota</div>
+                {{$total := .QuotaUsage.GetTotalTransferQuota}}
+                {{$upload := .QuotaUsage.GetUploadTransferQuota}}
+                {{$download := .QuotaUsage.GetDownloadTransferQuota}}
+                {{if $total}}
+                {{$percentage := .QuotaUsage.GetTotalTransferQuotaPercentage}}
+                <span class="font-weight-bold {{if .QuotaUsage.IsTotalTransferQuotaLow}}text-warning{{end}}">Total: {{$total}}{{if gt $percentage 0}} ({{$percentage}}%){{end}}</span>
+                {{if or $upload $download}}<br>{{end}}
+                {{end}}
+                {{if $download}}
+                {{$percentage := .QuotaUsage.GetDownloadTransferQuotaPercentage}}
+                <span class="font-weight-bold {{if .QuotaUsage.IsDownloadTransferQuotaLow}}text-warning{{end}}">Download: {{$download}}{{if gt $percentage 0}} ({{$percentage}}%){{end}}</span>
+                {{if $upload}}<br>{{end}}
+                {{end}}
+                {{if $upload}}
+                {{$percentage := .QuotaUsage.GetUploadTransferQuotaPercentage}}
+                <span class="font-weight-bold {{if .QuotaUsage.IsUploadTransferQuotaLow}}text-warning{{end}}">Upload: {{$upload}}{{if gt $percentage 0}} ({{$percentage}}%){{end}}</span>
+                {{end}}
+            </div>
+        </a>
+        {{end}}
+    </div>
+</li>
+
+<div class="topbar-divider d-none d-sm-block"></div>
+{{end}}
+{{end}}
+
 {{define "page_body"}}
 {{define "page_body"}}
 <div id="errorMsg" class="alert alert-warning alert-dismissible fade show" style="display: none;" role="alert">
 <div id="errorMsg" class="alert alert-warning alert-dismissible fade show" style="display: none;" role="alert">
     <span id="errorTxt"></span>
     <span id="errorTxt"></span>