Merge pull request #709 from owncloud/autoincrement-index

Autoincrement index
This commit is contained in:
Michael Barz
2020-10-22 18:51:09 +02:00
committed by GitHub
63 changed files with 6724 additions and 2734 deletions

View File

@@ -147,14 +147,14 @@ def testPipelines(ctx):
pipelines.append(coreApiTests(ctx, config['apiTests']['coreBranch'], config['apiTests']['coreCommit'], runPart, config['apiTests']['numberOfParts'], 'ocis'))
pipelines += uiTests(ctx, config['uiTests']['phoenixBranch'], config['uiTests']['phoenixCommit'])
pipelines.append(accountsUITests(ctx, config['uiTests']['phoenixBranch'], config['uiTests']['phoenixCommit'], 'owncloud'))
pipelines.append(accountsUITests(ctx, config['uiTests']['phoenixBranch'], config['uiTests']['phoenixCommit']))
return pipelines
def testing(ctx, module):
steps = generate(module) + [
{
'name': 'vet',
'image': 'webhippie/golang:1.13',
'image': 'webhippie/golang:1.14',
'pull': 'always',
'commands': [
'cd %s' % (module),
@@ -169,7 +169,7 @@ def testing(ctx, module):
},
{
'name': 'staticcheck',
'image': 'webhippie/golang:1.13',
'image': 'webhippie/golang:1.14',
'pull': 'always',
'commands': [
'cd %s' % (module),
@@ -184,7 +184,7 @@ def testing(ctx, module):
},
{
'name': 'lint',
'image': 'webhippie/golang:1.13',
'image': 'webhippie/golang:1.14',
'pull': 'always',
'commands': [
'cd %s' % (module),
@@ -199,7 +199,7 @@ def testing(ctx, module):
},
{
'name': 'test',
'image': 'webhippie/golang:1.13',
'image': 'webhippie/golang:1.14',
'pull': 'always',
'commands': [
'cd %s' % (module),
@@ -516,7 +516,7 @@ def uiTestPipeline(suiteName, phoenixBranch = 'master', phoenixCommit = '', stor
},
}
def accountsUITests(ctx, phoenixBranch, phoenixCommitId, storage):
def accountsUITests(ctx, phoenixBranch, phoenixCommit, storage = 'owncloud'):
return {
'kind': 'pipeline',
'type': 'docker',
@@ -525,110 +525,48 @@ def accountsUITests(ctx, phoenixBranch, phoenixCommitId, storage):
'os': 'linux',
'arch': 'amd64',
},
'steps': [
{
'name': 'build-ocis',
'image': 'webhippie/golang:1.13',
'pull': 'always',
'commands': [
'cd ocis',
'make build',
'mkdir -p /srv/app/ocis/bin',
'cp bin/ocis /srv/app/ocis/bin',
],
'volumes': [
{
'name': 'gopath',
'path': '/srv/app'
},
]
},
{
'name': 'ocis-server',
'image': 'webhippie/golang:1.13',
'pull': 'always',
'detach': True,
'environment' : {
#'OCIS_LOG_LEVEL': 'debug',
'STORAGE_HOME_DRIVER': '%s' % (storage),
'STORAGE_STORAGE_OCIS_ROOT': '/srv/app/tmp/ocis/storage/users',
'STORAGE_STORAGE_LOCAL_ROOT': '/srv/app/tmp/ocis/reva/root',
'STORAGE_STORAGE_OWNCLOUD_DATADIR': '/srv/app/tmp/ocis/owncloud/data',
'STORAGE_STORAGE_OWNCLOUD_REDIS_ADDR': 'redis:6379',
'STORAGE_OIDC_ISSUER': 'https://ocis-server:9200',
'STORAGE_LDAP_IDP': 'https://ocis-server:9200',
'PROXY_OIDC_ISSUER': 'https://ocis-server:9200',
'STORAGE_HOME_EXPOSE_DATA_SERVER': 'true',
'STORAGE_HOME_DATA_SERVER_URL': 'http://ocis-server:9155/data',
'STORAGE_DATAGATEWAY_PUBLIC_URL': 'https://ocis-server:9200/data',
'STORAGE_FRONTEND_PUBLIC_URL': 'https://ocis-server:9200',
'PHOENIX_WEB_CONFIG': '/drone/src/accounts/ui/tests/config/drone/ocis-config.json',
'KONNECTD_IDENTIFIER_REGISTRATION_CONF': '/drone/src/accounts/ui/tests/config/drone/identifier-registration.yml',
'KONNECTD_ISS': 'https://ocis-server:9200',
'ACCOUNTS_STORAGE_DISK_PATH': '/srv/app/tmp/ocis-accounts', # Temporary workaround, don't use metadata storage
},
'commands': [
'mkdir -p /srv/app/tmp/reva',
# First run settings service because accounts need it to register the settings bundles
'/srv/app/ocis/bin/ocis settings &',
# Wait for the settings service to start
"while [[ \"$(curl -s -o /dev/null -w ''%{http_code}'' localhost:9190)\" != \"404\" ]]; do sleep 2; done",
# Now start the accounts service
'/srv/app/ocis/bin/ocis accounts &',
# Wait for the accounts service to start
"while [[ \"$(curl -s -o /dev/null -w ''%{http_code}'' localhost:9181)\" != \"404\" ]]; do sleep 2; done",
# Now run all the ocis services except the accounts and settings because they are already running
'/srv/app/ocis/bin/ocis server',
],
'volumes': [
{
'name': 'gopath',
'path': '/srv/app'
},
]
},
'steps':
generate('ocis') +
build() +
ocisServer(storage) + [
{
'name': 'WebUIAcceptanceTests',
'image': 'owncloudci/nodejs:10',
'image': 'owncloudci/nodejs:11',
'pull': 'always',
'environment': {
'SERVER_HOST': 'https://ocis-server:9200',
'BACKEND_HOST': 'https://ocis-server:9200',
'RUN_ON_OCIS': 'true',
'OCIS_REVA_DATA_ROOT': '/srv/app/tmp/ocis/owncloud',
'OCIS_REVA_DATA_ROOT': '/srv/app/tmp/ocis/owncloud/data',
'OCIS_SKELETON_DIR': '/srv/app/testing/data/webUISkeleton',
'PHOENIX_CONFIG': '/drone/src/accounts/ui/tests/config/drone/ocis-config.json',
'PHOENIX_CONFIG': '/drone/src/ocis/tests/config/drone/ocis-config.json',
'TEST_TAGS': 'not @skipOnOCIS and not @skip',
'LOCAL_UPLOAD_DIR': '/uploads',
'NODE_TLS_REJECT_UNAUTHORIZED': 0,
'PHOENIX_PATH': '/srv/app/phoenix',
'FEATURE_PATH': '/drone/src/accounts/ui/tests/acceptance/features',
'NODE_TLS_REJECT_UNAUTHORIZED': '0'
},
'commands': [
'git clone --depth=1 https://github.com/owncloud/testing.git /srv/app/testing',
'git clone -b %s --single-branch https://github.com/owncloud/phoenix /srv/app/phoenix' % (phoenixBranch),
'cd /srv/app/phoenix',
'git checkout %s' % (phoenixCommitId),
'git clone -b master --depth=1 https://github.com/owncloud/testing.git /srv/app/testing',
'git clone -b %s --single-branch --no-tags https://github.com/owncloud/phoenix.git /srv/app/phoenix' % (phoenixBranch),
'cp -r /srv/app/phoenix/tests/acceptance/filesForUpload/* /uploads',
'cd /srv/app/phoenix',
] + ([
'git checkout %s' % (phoenixCommit)
] if phoenixCommit != '' else []) + [
'yarn install-all',
'cd /drone/src/accounts',
'yarn install --all',
'make test-acceptance-webui'
],
'volumes': [
{
'name': 'gopath',
'path': '/srv/app',
},
{
'name': 'uploads',
'path': '/uploads'
}
],
'volumes': [{
'name': 'gopath',
'path': '/srv/app',
},
{
'name': 'uploads',
'path': '/uploads'
}],
},
],
'services': [
@@ -867,7 +805,7 @@ def binary(ctx, name):
generate('ocis') + [
{
'name': 'build',
'image': 'webhippie/golang:1.13',
'image': 'webhippie/golang:1.14',
'pull': 'always',
'commands': [
'cd ocis',
@@ -882,7 +820,7 @@ def binary(ctx, name):
},
{
'name': 'finish',
'image': 'webhippie/golang:1.13',
'image': 'webhippie/golang:1.14',
'pull': 'always',
'commands': [
'cd ocis',
@@ -1073,7 +1011,7 @@ def changelog(ctx):
'steps': [
{
'name': 'generate',
'image': 'webhippie/golang:1.13',
'image': 'webhippie/golang:1.14',
'pull': 'always',
'commands': [
'cd ocis',
@@ -1237,7 +1175,7 @@ def docs(ctx):
},
{
'name': 'generate-config-docs',
'image': 'webhippie/golang:1.13',
'image': 'webhippie/golang:1.14',
'commands': generateConfigDocs,
'volumes': [
{
@@ -1325,7 +1263,7 @@ def generate(module):
return [
{
'name': 'generate',
'image': 'webhippie/golang:1.13',
'image': 'webhippie/golang:1.14',
'pull': 'always',
'commands': [
'cd %s' % (module),
@@ -1400,7 +1338,7 @@ def ocisServer(storage):
return [
{
'name': 'ocis-server',
'image': 'webhippie/golang:1.13',
'image': 'webhippie/golang:1.14',
'pull': 'always',
'detach': True,
'environment' : {
@@ -1423,7 +1361,6 @@ def ocisServer(storage):
'KONNECTD_IDENTIFIER_REGISTRATION_CONF': '/drone/src/ocis/tests/config/drone/identifier-registration.yml',
'KONNECTD_ISS': 'https://ocis-server:9200',
'KONNECTD_TLS': 'true',
'ACCOUNTS_DATA_PATH': '/srv/app/tmp/ocis-accounts/',
},
'commands': [
'apk add mailcap', # install /etc/mime.types
@@ -1489,7 +1426,7 @@ def build():
return [
{
'name': 'build',
'image': 'webhippie/golang:1.13',
'image': 'webhippie/golang:1.14',
'pull': 'always',
'commands': [
'cd ocis',

View File

@@ -3,21 +3,14 @@ module github.com/owncloud/ocis/accounts
go 1.13
require (
github.com/CiscoM31/godata v0.0.0-20191007193734-c2c4ebb1b415
github.com/blevesearch/bleve v1.0.9
github.com/cs3org/go-cs3apis v0.0.0-20200730121022-c4f3d4f7ddfd
github.com/cs3org/reva v1.1.0
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d // indirect
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect
github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 // indirect
github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c // indirect
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 // indirect
github.com/cs3org/go-cs3apis v0.0.0-20200810113633-b00aca449666
github.com/cs3org/reva v1.2.2-0.20200924071957-e6676516e61e
github.com/go-chi/chi v4.1.2+incompatible
github.com/go-chi/render v1.0.1
github.com/gofrs/uuid v3.3.0+incompatible
github.com/golang/protobuf v1.4.2
github.com/jmhodges/levigo v1.0.0 // indirect
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 // indirect
github.com/iancoleman/strcase v0.1.2
github.com/mennanov/fieldmask-utils v0.3.2
github.com/micro/cli/v2 v2.1.2
github.com/micro/go-micro/v2 v2.9.1
@@ -25,16 +18,16 @@ require (
github.com/olekukonko/tablewriter v0.0.4
github.com/owncloud/ocis/ocis-pkg v0.0.0-20200918114005-1a0ddd2190ee
github.com/owncloud/ocis/settings v0.0.0-20200918114005-1a0ddd2190ee
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/owncloud/ocis/storage v0.0.0-20201015120921-38358ba4d4df
github.com/prometheus/client_golang v1.7.1
github.com/restic/calens v0.2.0
github.com/rs/zerolog v1.19.0
github.com/rs/zerolog v1.20.0
github.com/spf13/viper v1.7.0
github.com/stretchr/testify v1.6.1
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect
github.com/tredoe/osutil v1.0.5
golang.org/x/net v0.0.0-20200822124328-c89045814202
google.golang.org/genproto v0.0.0-20200624020401-64a14ca9d1ad
google.golang.org/grpc v1.31.0
google.golang.org/grpc v1.32.0
google.golang.org/protobuf v1.25.0
)

View File

@@ -50,8 +50,6 @@ github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzS
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/CiscoM31/godata v0.0.0-20191007193734-c2c4ebb1b415 h1:rATYsVSP89BOyS9/o+cdGZ8qU7AHh4frtS59nFPoX8k=
github.com/CiscoM31/godata v0.0.0-20191007193734-c2c4ebb1b415/go.mod h1:tjaihnMBH6p5DVnGBksDQQHpErbrLvb9ek6cEWuyc7E=
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
@@ -68,10 +66,9 @@ github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcy
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
github.com/Microsoft/hcsshim v0.8.7-0.20191101173118-65519b62243c/go.mod h1:7xhjOwRV2+0HXGmM0jxaEu+ZiXJFoVZOTfL/dmqbrD8=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks=
github.com/RoaringBitmap/roaring v0.4.21 h1:WJ/zIlNX4wQZ9x8Ey33O1UaD9TCTakYsdLFSBcTwH+8=
github.com/RoaringBitmap/roaring v0.4.21/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/UnnoTed/fileb0x v1.1.4 h1:IUgFzgBipF/ujNx9wZgkrKOF3oltUuXMSoaejrBws+A=
@@ -103,12 +100,16 @@ github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:l
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 h1:zV3ejI06GQ59hwDQAvmK1qxOQGB3WuVTRoY0okPTAv0=
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY=
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
github.com/ascarter/requestid v0.0.0-20170313220838-5b76ab3d4aee h1:3T/l+vMotQ7cDSLWNAn2Vg1SAQ3mdyLgBWWBitSS3uU=
github.com/ascarter/requestid v0.0.0-20170313220838-5b76ab3d4aee/go.mod h1:u7Wtt4WATGGgae9mURNGQQqxAudPKrxfsbSDSGOso+g=
github.com/aws/aws-sdk-go v1.20.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.23.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.23.19/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.33.19/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.34.12 h1:7UbBEYDUa4uW0YmRnOd806MS1yoJMcaodBWDzvBShAI=
github.com/aws/aws-sdk-go v1.34.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-xray-sdk-go v0.9.4/go.mod h1:XtMKdBQfpVut+tJEwI7+dJFRxxRdxHDyVNp2tHXRq04=
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
@@ -120,26 +121,6 @@ github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkN
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blevesearch/bleve v1.0.9 h1:kqw/Ank/61UV9/Bx9kCcnfH6qWPgmS8O5LNfpsgzASg=
github.com/blevesearch/bleve v1.0.9/go.mod h1:tb04/rbU29clbtNgorgFd8XdJea4x3ybYaOjWKr+UBU=
github.com/blevesearch/blevex v0.0.0-20190916190636-152f0fe5c040 h1:SjYVcfJVZoCfBlg+fkaq2eoZHTf5HaJfaTeTkOtyfHQ=
github.com/blevesearch/blevex v0.0.0-20190916190636-152f0fe5c040/go.mod h1:WH+MU2F4T0VmSdaPX+Wu5GYoZBrYWdOZWSjzvYcDmqQ=
github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo=
github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M=
github.com/blevesearch/mmap-go v1.0.2 h1:JtMHb+FgQCTTYIhtMvimw15dJwu1Y5lrZDMOFXVWPk0=
github.com/blevesearch/mmap-go v1.0.2/go.mod h1:ol2qBqYaOUsGdm7aRMRrYGgPvnwLe6Y+7LMvAB5IbSA=
github.com/blevesearch/segment v0.9.0 h1:5lG7yBCx98or7gK2cHMKPukPZ/31Kag7nONpoBt22Ac=
github.com/blevesearch/segment v0.9.0/go.mod h1:9PfHYUdQCgHktBgvtUOF4x+pc4/l8rdH0u5spnW85UQ=
github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD/iWeNXm8s=
github.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulNWPl4ABg1tC/hlgLs=
github.com/blevesearch/zap/v11 v11.0.9 h1:wlSrDBeGN1G4M51NQHIXca23ttwUfQpWaK7uhO5lRSo=
github.com/blevesearch/zap/v11 v11.0.9/go.mod h1:47hzinvmY2EvvJruzsSCJpro7so8L1neseaGjrtXHOY=
github.com/blevesearch/zap/v12 v12.0.9 h1:PpatkY+BLVFZf0Ok3/fwgI/I4RU0z5blXFGuQANmqXk=
github.com/blevesearch/zap/v12 v12.0.9/go.mod h1:paQuvxy7yXor+0Mx8p2KNmJgygQbQNN+W6HRfL5Hvwc=
github.com/blevesearch/zap/v13 v13.0.1 h1:NSCM6uKu77Vn/x9nlPp4pE1o/bftqcOWZEHSyZVpGBQ=
github.com/blevesearch/zap/v13 v13.0.1/go.mod h1:XmyNLMvMf8Z5FjLANXwUeDW3e1+o77TTGUWrth7T9WI=
github.com/blevesearch/zap/v14 v14.0.0 h1:HF8Ysjm13qxB0jTGaKLlatNXmJbQD8bY+PrPxm5v4hE=
github.com/blevesearch/zap/v14 v14.0.0/go.mod h1:sUc/gPGJlFbSQ2ZUh/wGRYwkKx+Dg/5p+dd+eq6QMXk=
github.com/bmatcuk/doublestar v1.1.1 h1:YroD6BJCZBYx06yYFEWvUuKVWQn3vLLQAVmDmvTSaiQ=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
@@ -147,6 +128,7 @@ github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dR
github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40 h1:y4B3+GPxKlrigF1ha5FFErxK+sr6sWxQovRMzwMhejo=
github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c=
github.com/bwmarrin/discordgo v0.20.2/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
github.com/c-bata/go-prompt v0.2.3/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=
github.com/caddyserver/certmagic v0.10.6 h1:sCya6FmfaN74oZE46kqfaFOVoROD/mF36rTQfjN7TZc=
github.com/caddyserver/certmagic v0.10.6/go.mod h1:Y8jcUBctgk/IhpAzlHKfimZNyXCkfGgRTC0orl8gROQ=
github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
@@ -162,6 +144,7 @@ github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
github.com/cheggaaa/pb v1.0.28/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s=
github.com/cheggaaa/pb v1.0.29/go.mod h1:W40334L7FMC5JKWldsTWbdGjLo0RxUKK73K+TuPxX30=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
@@ -200,10 +183,6 @@ github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/couchbase/ghistogram v0.1.0/go.mod h1:s1Jhy76zqfEecpNWJfWUiKZookAFaiGOEoyzgHt9i7k=
github.com/couchbase/moss v0.1.0/go.mod h1:9MaHIaRuy9pvLPUJxB8sh8OrLfyDczECVL37grCIubs=
github.com/couchbase/vellum v1.0.1 h1:qrj9ohvZedvc51S5KzPfJ6P6z0Vqzv7Lx7k3mVc2WOk=
github.com/couchbase/vellum v1.0.1/go.mod h1:FcwrEivFpNi24R3jLOs3n+fs5RnuQnQqCLBJ1uAg1W4=
github.com/cpu/goacmedns v0.0.1/go.mod h1:sesf/pNnCYwUevQEQfEwY0Y3DydlQWSGZbaMElOWxok=
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
@@ -213,21 +192,26 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsr
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cs3org/cato v0.0.0-20200626150132-28a40e643719/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4=
github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4=
github.com/cs3org/go-cs3apis v0.0.0-20200730121022-c4f3d4f7ddfd h1:uMaudkC7znaiIKT9rxIhoRYzrhTg1Nc78X7XEqhmjSk=
github.com/cs3org/go-cs3apis v0.0.0-20200730121022-c4f3d4f7ddfd/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/go-cs3apis v0.0.0-20200810113633-b00aca449666 h1:E7VsSSN/2YZLSwrDMJJdAWU11lP7W1qkcXbrslb0PM0=
github.com/cs3org/go-cs3apis v0.0.0-20200810113633-b00aca449666/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/reva v1.1.0 h1:Gih6ECHvMMGSx523SFluFlDmNMuhYelXYShdWvjvW38=
github.com/cs3org/reva v1.1.0/go.mod h1:fBzTrNuAKdQ62ybjpdu8nyhBin90/3/3s6DGQDCdBp4=
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d h1:SwD98825d6bdB+pEuTxWOXiSjBrHdOl/UVp75eI7JT8=
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8=
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 h1:iwZdTE0PVqJCos1vaoKsclOGD3ADKpshg3SRtYBbwso=
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 h1:MZRmHqDBd0vxNwenEbKSQqRVT24d3C05ft8kduSwlqM=
github.com/cznic/strutil v0.0.0-20181122101858-275e90344537/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc=
github.com/cs3org/reva v1.2.2-0.20200924071957-e6676516e61e h1:khITGSnfDXtByQsLezoXgocUgGHJBBn0BPsUihGvk7w=
github.com/cs3org/reva v1.2.2-0.20200924071957-e6676516e61e/go.mod h1:DOV5SjpOBKN+aWfOHLdA4KiLQkpyC786PQaXEdRAZ0M=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgraph-io/ristretto v0.0.1/go.mod h1:T40EBc7CJke8TkpiYfGGKAeFjSaxuFXhuXRyumBd6RE=
github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgraph-io/ristretto v0.0.3 h1:jh22xisGBjrEVnRZ1DVTpBVQm0Xndu8sMl0CWDzSIBI=
github.com/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
github.com/dnaeon/go-vcr v0.0.0-20180814043457-aafff18a5cc2/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
@@ -254,13 +238,8 @@ github.com/evanphx/json-patch/v5 v5.0.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2Vvl
github.com/eventials/go-tus v0.0.0-20200718001131-45c7ec8f5d59 h1:t2+zxJPT/jq/YOx/JRsoByAZI/GHOxYJ7MKeillEX4U=
github.com/eventials/go-tus v0.0.0-20200718001131-45c7ec8f5d59/go.mod h1:XYuK1S5+kS6FGhlIUFuZFPvWiSrOIoLk6+ro33Xce3Y=
github.com/exoscale/egoscale v0.18.1/go.mod h1:Z7OOdzzTOz1Q1PjQXumlz9Wn/CddH0zSYdCF3rnBKXE=
github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0=
github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64=
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg=
github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk=
github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
@@ -268,6 +247,8 @@ github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI
github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c/go.mod h1:pFdJbAhRf7rh6YYMUdIQGyzne6zYL1tCUW8QV2B3UfY=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsouza/go-dockerclient v1.6.0/go.mod h1:YWwtNPuL4XTX1SKJQk86cWPmmqwx+4np9qfPbb+znGc=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
@@ -275,10 +256,6 @@ github.com/gizak/termui/v3 v3.1.0 h1:ZZmVDgwHl7gR7elfKf1xc4IudXZ5qqfDh4wExk4Iajc
github.com/gizak/termui/v3 v3.1.0/go.mod h1:bXQEBkJpzxUAKf0+xq9MSWAvWZlE7c+aidmyFlkYTrY=
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2 h1:Ujru1hufTHVb++eG6OuNDKMxZnGIvF6o/u8q/8h2+I4=
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31 h1:gclg6gY70GLy3PbkQ1AERPfmLMMagS60DKF78eWwLn8=
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
github.com/go-acme/lego/v3 v3.4.0 h1:deB9NkelA+TfjGHVw8J7iKl/rMtffcGMWSMmptvMv0A=
github.com/go-acme/lego/v3 v3.4.0/go.mod h1:xYbLDuxq3Hy4bMUT1t9JIuz6GWIWb3m5X+TeTHYaT7M=
github.com/go-asn1-ber/asn1-ber v1.5.1 h1:pDbRAunXzIUXfx4CB2QJFv5IuPiuoW+sWvr/Us009o8=
@@ -517,6 +494,7 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -534,8 +512,7 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k=
github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
@@ -561,11 +538,14 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gopherjs/gopherjs v0.0.0-20181004151105-1babbf986f6f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw=
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
@@ -588,6 +568,8 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmg
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.0 h1:0IKlLyQ3Hs9nDaiK5cSHAGmcQEIC8l2Ts1u6x5Dfrqg=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.0/go.mod h1:mJzapYve32yjrKlk9GbyCZHuPgZsrbyIbyKhSzOpg6s=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2 h1:FlFbCRLd5Jr4iYXZufAvgWN6Ao0JrI5chLINnUXDDr0=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
@@ -631,12 +613,15 @@ github.com/huandu/xstrings v1.2.0 h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0
github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
github.com/huandu/xstrings v1.3.0 h1:gvV6jG9dTgFEncxo+AF7PH6MZXi/vZl25owA/8Dg8Wo=
github.com/huandu/xstrings v1.3.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/iancoleman/strcase v0.1.2 h1:gnomlvw9tnV3ITTAxzKSgTF+8kFWcU/f+TgttpXGz1U=
github.com/iancoleman/strcase v0.1.2/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4=
github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg=
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
@@ -647,8 +632,6 @@ github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJS
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U=
github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ=
github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
github.com/joho/godotenv v1.2.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
@@ -681,15 +664,17 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/cpuid v1.2.3 h1:CCtW0xUnWGVINKvE/WWOYKdsPV6mawAtvQuSl8guwQs=
github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/kljensen/snowball v0.6.0/go.mod h1:27N7E8fVU5H68RlUmnWwZCfxgt4POBJfENGMvNRhldw=
github.com/kolo/xmlrpc v0.0.0-20190717152603-07c4ee3fd181/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ=
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
@@ -733,9 +718,12 @@ github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGD
github.com/marten-seemann/qtls v0.4.1/go.mod h1:pxVXcHHw1pNIt8Qo0pwSYQEoZ8yYOOPXTCZLQQunvRc=
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
@@ -749,6 +737,8 @@ github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW
github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
github.com/mattn/goveralls v0.0.5/go.mod h1:Xg2LHi51faXLyKXwsndxiW6uxEEQT9+3sjGzzwU4xy0=
github.com/mattn/goveralls v0.0.6 h1:cr8Y0VMo/MnEZBjxNN/vh6G90SZ7IMb6lms1dzMoO+Y=
github.com/mattn/goveralls v0.0.6/go.mod h1:h8b4ow6FxSPMQHF6o2ve3qsclnffZjYTNEKmLesRwqw=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mennanov/fieldmask-utils v0.3.2 h1:AkHXYBEOoyvocl8YhzoStATRnto5OH1PY4Rj78I5Cuc=
@@ -788,6 +778,7 @@ github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
@@ -803,9 +794,6 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd
github.com/monoculum/formam v0.0.0-20180901015400-4e68be1d79ba/go.mod h1:RKgILGEJq24YyJ2ban8EO0RUVSJlF1pGsEvoLEACr/Q=
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/moul/http2curl v0.0.0-20170919181001-9ac6cf4d929b/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8=
github.com/nats-io/jwt v0.3.2 h1:+RB5hMpXUUA2dfxuhBTEkMOrYmM+gKIZYS1KjSostMI=
@@ -834,6 +822,7 @@ github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQ
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/oleiade/reflections v1.0.0 h1:0ir4pc6v8/PJ0yw5AEtMddfXpWBXg9cnG7SgSoJuCgY=
github.com/oleiade/reflections v1.0.0/go.mod h1:RbATFBbKYkVdqmSFtx13Bb/tVhR0lgOBXunWTZKeL4w=
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
@@ -862,16 +851,25 @@ github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnh
github.com/ory/fosite v0.29.0/go.mod h1:0atSZmXO7CAcs6NPMI/Qtot8tmZYj04Nddoold4S2h0=
github.com/ory/fosite v0.32.2 h1:iRV495P/9EyoYQ8qEHYxFQeeYCdDFawqjAML+qiMF9s=
github.com/ory/fosite v0.32.2/go.mod h1:UeBhRgW6nAjTcd8S7kAo0IFsY/rTPyOXPq/t8N20Q8I=
github.com/ory/fosite v0.33.0 h1:tK+3Luazv4vIBJY3uagOBryAQ3IG3cs6kfo8piGBhAY=
github.com/ory/fosite v0.33.0/go.mod h1:h+ize9gk0GvRyGjabriqSEmTkMhny+O95cijb8DVqPE=
github.com/ory/go-acc v0.0.0-20181118080137-ddc355013f90/go.mod h1:sxnvPCxChFuSmTJGj8FdMupeq1BezCiEpDjTUXQ4hf4=
github.com/ory/go-acc v0.2.1/go.mod h1:0omgy2aa3nDBJ45VAKeLHH8ccPBudxLeic4xiDRtug0=
github.com/ory/go-acc v0.2.5 h1:31irXHzG2vnKQSE4weJm7AdfrnpaVjVCq3nD7viXCJE=
github.com/ory/go-acc v0.2.5/go.mod h1:4Kb/UnPcT8qRAk3IAxta+hvVapdxTLWtrr7bFLlEgpw=
github.com/ory/go-convenience v0.1.0 h1:zouLKfF2GoSGnJwGq+PE/nJAE6dj2Zj5QlTgmMTsTS8=
github.com/ory/go-convenience v0.1.0/go.mod h1:uEY/a60PL5c12nYz4V5cHY03IBmwIAEm8TWB0yn9KNs=
github.com/ory/gojsonreference v0.0.0-20190720135523-6b606c2d8ee8/go.mod h1:wsH1C4nIeeQClDtD5AH7kF1uTS6zWyqfjVDTmB0Em7A=
github.com/ory/gojsonschema v1.1.1-0.20190919112458-f254ca73d5e9/go.mod h1:BNZpdJgB74KOLSsWFvzw6roXg1I6O51WO8roMmW+T7Y=
github.com/ory/herodot v0.6.2/go.mod h1:3BOneqcyBsVybCPAJoi92KN2BpJHcmDqAMcAAaJiJow=
github.com/ory/viper v1.5.6/go.mod h1:TYmpFpKLxjQwvT4f0QPpkOn4sDXU1kDgAwJpgLYiQ28=
github.com/ory/viper v1.7.5 h1:+xVdq7SU3e1vNaCsk/ixsfxE4zylk1TJUiJrY647jUE=
github.com/ory/viper v1.7.5/go.mod h1:ypOuyJmEUb3oENywQZRgeAMwqgOyDqwboO1tj3DjTaM=
github.com/ory/x v0.0.85/go.mod h1:s44V8t3xyjWZREcU+mWlp4h302rTuM4aLXcW+y5FbQ8=
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ=
github.com/owncloud/flaex v0.0.0-20200411150708-dce59891a203/go.mod h1:jip86t4OVURJTf8CM/0e2qcji/Y4NG3l2lR8kex4JWw=
github.com/owncloud/ocis/storage v0.0.0-20201015120921-38358ba4d4df h1:PhRLD+WTGIfQ1T4MqBabp6/1Q8H/iwxjlygh6xzao0A=
github.com/owncloud/ocis/storage v0.0.0-20201015120921-38358ba4d4df/go.mod h1:s9kJvxtBlHEi5qc1TuPAdz2bprk9yGFe+FSOeC76Pbs=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
github.com/parnurzeal/gorequest v0.2.15/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE=
@@ -884,8 +882,8 @@ github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg=
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pelletier/go-toml v1.8.0 h1:Keo9qb7iRJs2voHvunFtuuYFsbWeOBh8/P9v/kVMFtw=
github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -893,6 +891,8 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pkg/term v0.0.0-20200520122047-c3ffed290a03/go.mod h1:Z9+Ul5bCbBKnbCvdOWbLqTHhJiYV414CURZJba6L8qA=
github.com/pkg/xattr v0.4.1 h1:dhclzL6EqOXNaPDWqoeb9tIxATfBSmjqL0b4DpSjwRw=
github.com/pkg/xattr v0.4.1/go.mod h1:W2cGD0TBEus7MkUgv0tNZ9JutLtVO3cXu+IBRuHqnFs=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -936,9 +936,6 @@ github.com/prometheus/statsd_exporter v0.15.0/go.mod h1:Dv8HnkoLQkeEjkIE4/2ndAA7
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/restic/calens v0.2.0 h1:LVNAtmFc+Pb4ODX66qdX1T3Di1P0OTLyUsVyvM/xD7E=
github.com/restic/calens v0.2.0/go.mod h1:UXwyAKS4wsgUZGEc7NrzzygJbLsQZIo3wl+62Q1wvmU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
@@ -953,6 +950,8 @@ github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.19.0 h1:hYz4ZVdUgjXTBUmrkrw55j1nHx68LfOKIQk5IYtyScg=
github.com/rs/zerolog v1.19.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo=
github.com/rs/zerolog v1.20.0 h1:38k9hgtUBdxFwE34yS8rTHmHBa4eN16E4DJlv177LNs=
github.com/rs/zerolog v1.20.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo=
github.com/rubenv/sql-migrate v0.0.0-20190212093014-1007f53448d7/go.mod h1:WS0rl9eEliYI8DPnr3TOwz4439pay+qNgzJoVya/DmY=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
@@ -1001,17 +1000,24 @@ github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.0/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/afero v1.3.2 h1:GDarE4TJQI52kYSbSAmLiId1Elfj+xgSDqrUZxFhxlU=
github.com/spf13/afero v1.3.2/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
@@ -1023,11 +1029,10 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/spf13/viper v1.2.1/go.mod h1:P4AexN0a+C9tGAnUFNwDMYYZv3pjFuvmeiMyKRaNVlI=
github.com/spf13/viper v1.3.1/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw=
github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/steveyen/gtreap v0.1.0 h1:CjhzTa274PyJLJuMZwIzCO1PfC00oRa8d1Kc78bFXJM=
github.com/steveyen/gtreap v0.1.0/go.mod h1:kl/5J7XbrOmlIbYIXdRHDDE5QxHqpk0cmkT7Z4dM9/Y=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -1038,22 +1043,20 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/studio-b12/gowebdav v0.0.0-20200303150724-9380631c29a1 h1:TPyHV/OgChqNcnYqCoCvIFjR9TU60gFXXBKnhOBzVEI=
github.com/studio-b12/gowebdav v0.0.0-20200303150724-9380631c29a1/go.mod h1:gCcfDlA1Y7GqOaeEKw5l9dOGx1VLdc/HuQSlQAaZ30s=
github.com/subosito/gotenv v1.1.1/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok=
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8=
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
github.com/tidwall/gjson v1.3.2/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/sjson v1.0.4/go.mod h1:bURseu1nuBkFpIES5cz6zBtjmYeOQmEESshn7VpF15Y=
github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7/go.mod h1:imsgLplxEC/etjIhdr3dNzV3JeT27LbVu5pYWm0JCBY=
github.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU=
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20200122045848-3419fae592fc h1:yUaosFVTJwnltaHbSNC3i82I92quFs+OFPRl8kNMVwo=
github.com/tmc/grpc-websocket-proxy v0.0.0-20200122045848-3419fae592fc/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@@ -1085,8 +1088,6 @@ github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 h1:gKMu1Bf6QI
github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4/go.mod h1:50wTf68f99/Zt14pr046Tgt3Lp2vLyFZKzbFXTOabXw=
github.com/vimeo/go-util v1.2.0/go.mod h1:s13SMDTSO7AjH1nbgp707mfN5JFIWUFDU5MDDuRRtKs=
github.com/vultr/govultr v0.1.4/go.mod h1:9H008Uxr/C4vFNGLqKx232C206GL0PBHzOP0809bGNA=
github.com/willf/bitset v1.1.10 h1:NotGKqX0KwQ72NUzqrjZq5ipPNDQex9lo3WpaS8L2sc=
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
@@ -1098,6 +1099,8 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
@@ -1150,16 +1153,20 @@ golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaE
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200320181102-891825fb96df/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -1170,6 +1177,7 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@@ -1190,6 +1198,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180611182652-db08ff08e862/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180816102801-aaf60122140d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1232,6 +1242,7 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
@@ -1278,12 +1289,12 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181206074257-70b957f3b65e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181221143128-b4a75ba826a6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190116161447-11f53e031339/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1297,12 +1308,13 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1310,21 +1322,28 @@ golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121 h1:rITEj+UZHYC927n8GT97eC3zrpzXdb/voyeOuVKS46o=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666 h1:gVCS+QOncANNPlmlO1AhlU3oxs4V9z+gTtPwIk3p2N8=
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1392,6 +1411,9 @@ golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4 h1:kDtqNkeBrZb8B+atrj50B5XLHpzXXqcCdZPP/ApQ5NY=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200721223218-6123e77877b2 h1:kxDWg8KNMtpGjI/XVKGgOtSljTnVg/PrjhS8+0pxjLE=
golang.org/x/tools v0.0.0-20200721223218-6123e77877b2/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
@@ -1441,6 +1463,7 @@ google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece h1:1YM0uhfumvoDu9sx8+RyWwTI63zoCQvI23IYFRlvte0=
@@ -1483,6 +1506,8 @@ gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww=
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mail.v2 v2.0.0-20180731213649-a0242b2233b4/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
gopkg.in/ns1/ns1-go.v2 v2.0.0-20190730140822-b51389932cbc/go.mod h1:VV+3haRsgDiVLxyifmMBrBIuCWFBPYKbRssXB9z67Hw=
gopkg.in/resty.v1 v1.9.1/go.mod h1:vo52Hzryw9PnPHcJfPsBiFW62XhNx5OczbV9y+IMpgc=
@@ -1492,6 +1517,8 @@ gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.5.0 h1:OZ4sdq+Y+SHfYB7vfthi1Ei8b0vkP8ZPQgUfUwdUSqo=
gopkg.in/square/go-jose.v2 v2.5.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w=
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/telegram-bot-api.v4 v4.6.4/go.mod h1:5DpGO5dbumb40px+dXcwCpcjmeHNYLpk0bp3XRNvWDM=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
@@ -1505,6 +1532,9 @@ gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo=

View File

@@ -77,16 +77,27 @@ type CS3 struct {
ProviderAddr string
DataURL string
DataPrefix string
JWTSecret string
}
// ServiceUser defines the user required for EOS
// ServiceUser defines the user required for EOS.
type ServiceUser struct {
UUID string
UUID string
Username string
UID int64
GID int64
}
// Index defines config for indexes.
type Index struct {
UID, GID Bound
}
// Bound defines a lower and upper bound.
type Bound struct {
Lower, Upper int64
}
// Config merges all Account config parameters.
type Config struct {
LDAP LDAP
@@ -97,6 +108,7 @@ type Config struct {
Log Log
TokenManager TokenManager
Repo Repo
Index Index
ServiceUser ServiceUser
}

View File

@@ -127,6 +127,13 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag {
EnvVars: []string{"ACCOUNTS_STORAGE_CS3_DATA_PREFIX"},
Destination: &cfg.Repo.CS3.DataPrefix,
},
&cli.StringFlag{
Name: "storage-cs3-jwt-secret",
Value: "Pive-Fumkiu4",
Usage: "Used to create JWT to talk to reva, should equal reva's jwt-secret",
EnvVars: []string{"ACCOUNTS_STORAGE_CS3_JWT_SECRET"},
Destination: &cfg.Repo.CS3.JWTSecret,
},
&cli.StringFlag{
Name: "service-user-uuid",
Value: "95cb8724-03b2-11eb-a0a6-c33ef8ef53ad",
@@ -155,6 +162,34 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag {
EnvVars: []string{"ACCOUNTS_SERVICE_USER_GID"},
Destination: &cfg.ServiceUser.GID,
},
&cli.Int64Flag{
Name: "uid-index-lower-bound",
Value: 0,
Usage: "define a starting point for the account UID",
EnvVars: []string{"ACCOUNTS_UID_INDEX_LOWER_BOUND"},
Destination: &cfg.Index.UID.Lower,
},
&cli.Int64Flag{
Name: "gid-index-lower-bound",
Value: 1000,
Usage: "define a starting point for the account GID",
EnvVars: []string{"ACCOUNTS_GID_INDEX_LOWER_BOUND"},
Destination: &cfg.Index.GID.Lower,
},
&cli.Int64Flag{
Name: "uid-index-upper-bound",
Value: 0,
Usage: "define an ending point for the account UID",
EnvVars: []string{"ACCOUNTS_UID_INDEX_UPPER_BOUND"},
Destination: &cfg.Index.UID.Upper,
},
&cli.Int64Flag{
Name: "gid-index-upper-bound",
Value: 1000,
Usage: "define an ending point for the account GID",
EnvVars: []string{"ACCOUNTS_GID_INDEX_UPPER_BOUND"},
Destination: &cfg.Index.GID.Upper,
},
}
}

View File

@@ -0,0 +1,35 @@
package errors
import (
"fmt"
)
// AlreadyExistsErr implements the Error interface.
type AlreadyExistsErr struct {
TypeName, Key, Value string
}
func (e *AlreadyExistsErr) Error() string {
return fmt.Sprintf("%s with %s=%s does already exist", e.TypeName, e.Key, e.Value)
}
// IsAlreadyExistsErr checks whether an error is of type AlreadyExistsErr.
func IsAlreadyExistsErr(e error) bool {
_, ok := e.(*AlreadyExistsErr)
return ok
}
// NotFoundErr implements the Error interface.
type NotFoundErr struct {
TypeName, Key, Value string
}
func (e *NotFoundErr) Error() string {
return fmt.Sprintf("%s with %s=%s not found", e.TypeName, e.Key, e.Value)
}
// IsNotFoundErr checks whether an error is of type IsNotFoundErr.
func IsNotFoundErr(e error) bool {
_, ok := e.(*NotFoundErr)
return ok
}

View File

@@ -0,0 +1,387 @@
package cs3
import (
"context"
"fmt"
"io/ioutil"
"net/http"
"os"
"path"
"path/filepath"
"sort"
"strconv"
"strings"
idxerrs "github.com/owncloud/ocis/accounts/pkg/indexer/errors"
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
v1beta11 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/pkg/token"
"github.com/cs3org/reva/pkg/token/manager/jwt"
"google.golang.org/grpc/metadata"
"github.com/owncloud/ocis/accounts/pkg/indexer/index"
"github.com/owncloud/ocis/accounts/pkg/indexer/option"
"github.com/owncloud/ocis/accounts/pkg/indexer/registry"
)
// Autoincrement are fields for an index of type autoincrement.
type Autoincrement struct {
indexBy string
typeName string
filesDir string
indexBaseDir string
indexRootDir string
tokenManager token.Manager
storageProvider provider.ProviderAPIClient
dataProvider dataProviderClient // Used to create and download data via http, bypassing reva upload protocol
cs3conf *Config
}
func init() {
registry.IndexConstructorRegistry["cs3"]["autoincrement"] = NewAutoincrementIndex
}
// NewAutoincrementIndex instantiates a new AutoincrementIndex instance.
func NewAutoincrementIndex(o ...option.Option) index.Index {
opts := &option.Options{}
for _, opt := range o {
opt(opts)
}
u := &Autoincrement{
indexBy: opts.IndexBy,
typeName: opts.TypeName,
filesDir: opts.FilesDir,
indexBaseDir: path.Join(opts.DataDir, "index.cs3"),
indexRootDir: path.Join(path.Join(opts.DataDir, "index.cs3"), strings.Join([]string{"autoincrement", opts.TypeName, opts.IndexBy}, ".")),
cs3conf: &Config{
ProviderAddr: opts.ProviderAddr,
DataURL: opts.DataURL,
DataPrefix: opts.DataPrefix,
JWTSecret: opts.JWTSecret,
ServiceUserName: opts.ServiceUserName,
ServiceUserUUID: opts.ServiceUserUUID,
},
dataProvider: dataProviderClient{
baseURL: singleJoiningSlash(opts.DataURL, opts.DataPrefix),
client: http.Client{
Transport: http.DefaultTransport,
},
},
}
return u
}
// Init initializes an autoincrement index.
func (idx *Autoincrement) Init() error {
tokenManager, err := jwt.New(map[string]interface{}{
"secret": idx.cs3conf.JWTSecret,
})
if err != nil {
return err
}
idx.tokenManager = tokenManager
client, err := pool.GetStorageProviderServiceClient(idx.cs3conf.ProviderAddr)
if err != nil {
return err
}
idx.storageProvider = client
ctx := context.Background()
tk, err := idx.authenticate(ctx)
if err != nil {
return err
}
ctx = metadata.AppendToOutgoingContext(ctx, token.TokenHeader, tk)
if err := idx.makeDirIfNotExists(ctx, idx.indexBaseDir); err != nil {
return err
}
if err := idx.makeDirIfNotExists(ctx, idx.indexRootDir); err != nil {
return err
}
return nil
}
// Lookup exact lookup by value.
func (idx *Autoincrement) Lookup(v string) ([]string, error) {
searchPath := path.Join(idx.indexRootDir, v)
oldname, err := idx.resolveSymlink(searchPath)
if err != nil {
if os.IsNotExist(err) {
err = &idxerrs.NotFoundErr{TypeName: idx.typeName, Key: idx.indexBy, Value: v}
}
return nil, err
}
return []string{oldname}, nil
}
// Add a new value to the index.
func (idx *Autoincrement) Add(id, v string) (string, error) {
var newName string
if v == "" {
next, err := idx.next()
if err != nil {
return "", err
}
newName = path.Join(idx.indexRootDir, strconv.Itoa(next))
} else {
newName = path.Join(idx.indexRootDir, v)
}
if err := idx.createSymlink(id, newName); err != nil {
if os.IsExist(err) {
return "", &idxerrs.AlreadyExistsErr{TypeName: idx.typeName, Key: idx.indexBy, Value: v}
}
return "", err
}
return newName, nil
}
// Remove a value v from an index.
func (idx *Autoincrement) Remove(id string, v string) error {
if v == "" {
return nil
}
searchPath := path.Join(idx.indexRootDir, v)
_, err := idx.resolveSymlink(searchPath)
if err != nil {
if os.IsNotExist(err) {
err = &idxerrs.NotFoundErr{TypeName: idx.typeName, Key: idx.indexBy, Value: v}
}
return err
}
ctx := context.Background()
t, err := idx.authenticate(ctx)
if err != nil {
return err
}
deletePath := path.Join("/meta", idx.indexRootDir, v)
ctx = metadata.AppendToOutgoingContext(ctx, token.TokenHeader, t)
resp, err := idx.storageProvider.Delete(ctx, &provider.DeleteRequest{
Ref: &provider.Reference{
Spec: &provider.Reference_Path{Path: deletePath},
},
})
if err != nil {
return err
}
// TODO Handle other error codes?
if resp.Status.Code == v1beta11.Code_CODE_NOT_FOUND {
return &idxerrs.NotFoundErr{}
}
return err
}
// Update index from <oldV> to <newV>.
func (idx *Autoincrement) Update(id, oldV, newV string) error {
if err := idx.Remove(id, oldV); err != nil {
return err
}
if _, err := idx.Add(id, newV); err != nil {
return err
}
return nil
}
// Search allows for glob search on the index.
func (idx *Autoincrement) Search(pattern string) ([]string, error) {
ctx := context.Background()
t, err := idx.authenticate(ctx)
if err != nil {
return nil, err
}
ctx = metadata.AppendToOutgoingContext(ctx, token.TokenHeader, t)
res, err := idx.storageProvider.ListContainer(ctx, &provider.ListContainerRequest{
Ref: &provider.Reference{
Spec: &provider.Reference_Path{Path: path.Join("/meta", idx.indexRootDir)},
},
})
if err != nil {
return nil, err
}
searchPath := idx.indexRootDir
matches := make([]string, 0)
for _, i := range res.GetInfos() {
if found, err := filepath.Match(pattern, path.Base(i.Path)); found {
if err != nil {
return nil, err
}
oldPath, err := idx.resolveSymlink(path.Join(searchPath, path.Base(i.Path)))
if err != nil {
return nil, err
}
matches = append(matches, oldPath)
}
}
return matches, nil
}
// CaseInsensitive undocumented.
func (idx *Autoincrement) CaseInsensitive() bool {
return false
}
// IndexBy undocumented.
func (idx *Autoincrement) IndexBy() string {
return idx.indexBy
}
// TypeName undocumented.
func (idx *Autoincrement) TypeName() string {
return idx.typeName
}
// FilesDir undocumented.
func (idx *Autoincrement) FilesDir() string {
return idx.filesDir
}
func (idx *Autoincrement) createSymlink(oldname, newname string) error {
t, err := idx.authenticate(context.TODO())
if err != nil {
return err
}
if _, err := idx.resolveSymlink(newname); err == nil {
return os.ErrExist
}
resp, err := idx.dataProvider.put(newname, strings.NewReader(oldname), t)
if err != nil {
return err
}
if err = resp.Body.Close(); err != nil {
return err
}
return nil
}
func (idx *Autoincrement) resolveSymlink(name string) (string, error) {
t, err := idx.authenticate(context.TODO())
if err != nil {
return "", err
}
resp, err := idx.dataProvider.get(name, t)
if err != nil {
return "", err
}
if resp.StatusCode != http.StatusOK {
if resp.StatusCode == http.StatusNotFound {
return "", os.ErrNotExist
}
return "", fmt.Errorf("could not resolve symlink %s, got status %v", name, resp.StatusCode)
}
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
if err = resp.Body.Close(); err != nil {
return "", err
}
return string(b), err
}
func (idx *Autoincrement) makeDirIfNotExists(ctx context.Context, folder string) error {
var rootPathRef = &provider.Reference{
Spec: &provider.Reference_Path{Path: fmt.Sprintf("/meta/%v", folder)},
}
resp, err := idx.storageProvider.Stat(ctx, &provider.StatRequest{
Ref: rootPathRef,
})
if err != nil {
return err
}
if resp.Status.Code == v1beta11.Code_CODE_NOT_FOUND {
_, err := idx.storageProvider.CreateContainer(ctx, &provider.CreateContainerRequest{
Ref: rootPathRef,
})
if err != nil {
return err
}
}
return nil
}
func (idx *Autoincrement) authenticate(ctx context.Context) (token string, err error) {
u := &user.User{
Id: &user.UserId{OpaqueId: idx.cs3conf.ServiceUserUUID},
Groups: []string{},
}
return idx.tokenManager.MintToken(ctx, u)
}
func (idx *Autoincrement) next() (int, error) {
ctx := context.Background()
t, err := idx.authenticate(ctx)
if err != nil {
return -1, err
}
ctx = metadata.AppendToOutgoingContext(ctx, token.TokenHeader, t)
res, err := idx.storageProvider.ListContainer(ctx, &provider.ListContainerRequest{
Ref: &provider.Reference{
Spec: &provider.Reference_Path{Path: path.Join("/meta", idx.indexRootDir)},
},
})
if err != nil {
return -1, err
}
if len(res.GetInfos()) == 0 {
return 0, nil
}
infos := res.GetInfos()
sort.Slice(infos, func(i, j int) bool {
a, _ := strconv.Atoi(path.Base(infos[i].Path))
b, _ := strconv.Atoi(path.Base(infos[j].Path))
return a < b
})
latest, err := strconv.Atoi(path.Base(infos[len(infos)-1].Path)) // would returning a string be a better interface?
if err != nil {
return -1, err
}
return latest + 1, nil
}

View File

@@ -0,0 +1,83 @@
package cs3
//
//import (
// "os"
// "testing"
//
// "github.com/owncloud/ocis/accounts/pkg/config"
// "github.com/owncloud/ocis/accounts/pkg/indexer/option"
// . "github.com/owncloud/ocis/accounts/pkg/indexer/test"
// "github.com/stretchr/testify/assert"
//)
//
//const cs3RootFolder = "/var/tmp/ocis/storage/users/data"
//
//func TestAutoincrementIndexAdd(t *testing.T) {
// dataDir, err := WriteIndexTestData(Data, "ID", cs3RootFolder)
// assert.NoError(t, err)
// cfg := generateConfig()
//
// sut := NewAutoincrementIndex(
// option.WithTypeName(GetTypeFQN(User{})),
// option.WithIndexBy("UID"),
// option.WithDataURL(cfg.Repo.CS3.DataURL),
// option.WithDataPrefix(cfg.Repo.CS3.DataPrefix),
// option.WithJWTSecret(cfg.Repo.CS3.JWTSecret),
// option.WithProviderAddr(cfg.Repo.CS3.ProviderAddr),
// )
//
// assert.NoError(t, sut.Init())
//
// for i := 0; i < 5; i++ {
// res, err := sut.Add("abcdefg-123", "")
// assert.NoError(t, err)
// t.Log(res)
// }
//
// _ = os.RemoveAll(dataDir)
//}
//
//func BenchmarkAutoincrementIndexAdd(b *testing.B) {
// dataDir, err := WriteIndexTestData(Data, "ID", cs3RootFolder)
// assert.NoError(b, err)
// cfg := generateConfig()
//
// sut := NewAutoincrementIndex(
// option.WithTypeName(GetTypeFQN(User{})),
// option.WithIndexBy("UID"),
// option.WithDataURL(cfg.Repo.CS3.DataURL),
// option.WithDataPrefix(cfg.Repo.CS3.DataPrefix),
// option.WithJWTSecret(cfg.Repo.CS3.JWTSecret),
// option.WithProviderAddr(cfg.Repo.CS3.ProviderAddr),
// )
//
// err = sut.Init()
// assert.NoError(b, err)
//
// for n := 0; n < b.N; n++ {
// _, err := sut.Add("abcdefg-123", "")
// if err != nil {
// b.Error(err)
// }
// assert.NoError(b, err)
// }
//
// _ = os.RemoveAll(dataDir)
//}
//
//func generateConfig() config.Config {
// return config.Config{
// Repo: config.Repo{
// Disk: config.Disk{
// Path: "",
// },
// CS3: config.CS3{
// ProviderAddr: "0.0.0.0:9215",
// DataURL: "http://localhost:9216",
// DataPrefix: "data",
// JWTSecret: "Pive-Fumkiu4",
// },
// },
// }
//}

View File

@@ -0,0 +1,45 @@
package cs3
import (
"io"
"net/http"
"strings"
)
type dataProviderClient struct {
client http.Client
baseURL string
}
func (d dataProviderClient) put(url string, body io.Reader, token string) (*http.Response, error) {
req, err := http.NewRequest(http.MethodPut, singleJoiningSlash(d.baseURL, url), body)
if err != nil {
return nil, err
}
req.Header.Add("x-access-token", token)
return d.client.Do(req)
}
func (d dataProviderClient) get(url string, token string) (*http.Response, error) {
req, err := http.NewRequest(http.MethodGet, singleJoiningSlash(d.baseURL, url), nil)
if err != nil {
return nil, err
}
req.Header.Add("x-access-token", token)
return d.client.Do(req)
}
// TODO: this is copied from proxy. Find a better solution or move it to ocis-pkg
func singleJoiningSlash(a, b string) string {
aslash := strings.HasSuffix(a, "/")
bslash := strings.HasPrefix(b, "/")
switch {
case aslash && bslash:
return a + b[1:]
case !aslash && !bslash:
return a + "/" + b
}
return a + b
}

View File

@@ -0,0 +1,410 @@
package cs3
import (
"context"
"fmt"
"io/ioutil"
"net/http"
"os"
"path"
"path/filepath"
"strings"
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
v1beta11 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/pkg/token"
"github.com/cs3org/reva/pkg/token/manager/jwt"
idxerrs "github.com/owncloud/ocis/accounts/pkg/indexer/errors"
"github.com/owncloud/ocis/accounts/pkg/indexer/index"
"github.com/owncloud/ocis/accounts/pkg/indexer/option"
"github.com/owncloud/ocis/accounts/pkg/indexer/registry"
"google.golang.org/grpc/metadata"
)
func init() {
registry.IndexConstructorRegistry["cs3"]["non_unique"] = NewNonUniqueIndexWithOptions
}
// NonUnique are fields for an index of type non_unique.
type NonUnique struct {
caseInsensitive bool
indexBy string
typeName string
filesDir string
indexBaseDir string
indexRootDir string
tokenManager token.Manager
storageProvider provider.ProviderAPIClient
dataProvider dataProviderClient // Used to create and download data via http, bypassing reva upload protocol
cs3conf *Config
}
// NewNonUniqueIndexWithOptions instantiates a new NonUniqueIndex instance.
// /var/tmp/ocis-accounts/index.cs3/Pets/Bro*
// ├── Brown/
// │ └── rebef-123 -> /var/tmp/testfiles-395764020/pets/rebef-123
// ├── Green/
// │ ├── goefe-789 -> /var/tmp/testfiles-395764020/pets/goefe-789
// │ └── xadaf-189 -> /var/tmp/testfiles-395764020/pets/xadaf-189
// └── White/
// └── wefwe-456 -> /var/tmp/testfiles-395764020/pets/wefwe-456
func NewNonUniqueIndexWithOptions(o ...option.Option) index.Index {
opts := &option.Options{}
for _, opt := range o {
opt(opts)
}
return &NonUnique{
caseInsensitive: opts.CaseInsensitive,
indexBy: opts.IndexBy,
typeName: opts.TypeName,
filesDir: opts.FilesDir,
indexBaseDir: path.Join(opts.DataDir, "index.cs3"),
indexRootDir: path.Join(path.Join(opts.DataDir, "index.cs3"), strings.Join([]string{"non_unique", opts.TypeName, opts.IndexBy}, ".")),
cs3conf: &Config{
ProviderAddr: opts.ProviderAddr,
DataURL: opts.DataURL,
DataPrefix: opts.DataPrefix,
JWTSecret: opts.JWTSecret,
ServiceUserName: opts.ServiceUserName,
ServiceUserUUID: opts.ServiceUserUUID,
},
dataProvider: dataProviderClient{
baseURL: singleJoiningSlash(opts.DataURL, opts.DataPrefix),
client: http.Client{
Transport: http.DefaultTransport,
},
},
}
}
// Init initializes a non_unique index.
func (idx *NonUnique) Init() error {
tokenManager, err := jwt.New(map[string]interface{}{
"secret": idx.cs3conf.JWTSecret,
})
if err != nil {
return err
}
idx.tokenManager = tokenManager
client, err := pool.GetStorageProviderServiceClient(idx.cs3conf.ProviderAddr)
if err != nil {
return err
}
idx.storageProvider = client
ctx := context.Background()
tk, err := idx.authenticate(ctx)
if err != nil {
return err
}
ctx = metadata.AppendToOutgoingContext(ctx, token.TokenHeader, tk)
if err := idx.makeDirIfNotExists(ctx, idx.indexBaseDir); err != nil {
return err
}
if err := idx.makeDirIfNotExists(ctx, idx.indexRootDir); err != nil {
return err
}
return nil
}
// Lookup exact lookup by value.
func (idx *NonUnique) Lookup(v string) ([]string, error) {
if idx.caseInsensitive {
v = strings.ToLower(v)
}
var matches = make([]string, 0)
ctx, err := idx.getAuthenticatedContext(context.Background())
if err != nil {
return nil, err
}
res, err := idx.storageProvider.ListContainer(ctx, &provider.ListContainerRequest{
Ref: &provider.Reference{
Spec: &provider.Reference_Path{Path: path.Join("/meta", idx.indexRootDir, v)},
},
})
if err != nil {
return nil, err
}
for _, info := range res.Infos {
matches = append(matches, path.Base(info.Path))
}
return matches, nil
}
// Add a new value to the index.
func (idx *NonUnique) Add(id, v string) (string, error) {
if v == "" {
return "", nil
}
if idx.caseInsensitive {
v = strings.ToLower(v)
}
ctx, err := idx.getAuthenticatedContext(context.Background())
if err != nil {
return "", err
}
newName := path.Join(idx.indexRootDir, v)
if err := idx.makeDirIfNotExists(ctx, newName); err != nil {
return "", err
}
if err := idx.createSymlink(id, path.Join(newName, id)); err != nil {
if os.IsExist(err) {
return "", &idxerrs.AlreadyExistsErr{TypeName: idx.typeName, Key: idx.indexBy, Value: v}
}
return "", err
}
return newName, nil
}
// Remove a value v from an index.
func (idx *NonUnique) Remove(id string, v string) error {
if v == "" {
return nil
}
if idx.caseInsensitive {
v = strings.ToLower(v)
}
ctx, err := idx.getAuthenticatedContext(context.Background())
if err != nil {
return err
}
deletePath := path.Join("/meta", idx.indexRootDir, v, id)
resp, err := idx.storageProvider.Delete(ctx, &provider.DeleteRequest{
Ref: &provider.Reference{
Spec: &provider.Reference_Path{Path: deletePath},
},
})
if err != nil {
return err
}
if resp.Status.Code == v1beta11.Code_CODE_NOT_FOUND {
return &idxerrs.NotFoundErr{TypeName: idx.typeName, Key: idx.indexBy, Value: v}
}
toStat := path.Join("/meta", idx.indexRootDir, v)
lcResp, err := idx.storageProvider.ListContainer(ctx, &provider.ListContainerRequest{
Ref: &provider.Reference{
Spec: &provider.Reference_Path{Path: toStat},
},
})
if err != nil {
return err
}
if len(lcResp.Infos) == 0 {
deletePath = path.Join("/meta", idx.indexRootDir, v)
_, err := idx.storageProvider.Delete(ctx, &provider.DeleteRequest{
Ref: &provider.Reference{
Spec: &provider.Reference_Path{Path: deletePath},
},
})
if err != nil {
return err
}
}
return nil
}
// Update index from <oldV> to <newV>.
func (idx *NonUnique) Update(id, oldV, newV string) error {
if idx.caseInsensitive {
oldV = strings.ToLower(oldV)
newV = strings.ToLower(newV)
}
if err := idx.Remove(id, oldV); err != nil {
return err
}
if _, err := idx.Add(id, newV); err != nil {
return err
}
return nil
}
// Search allows for glob search on the index.
func (idx *NonUnique) Search(pattern string) ([]string, error) {
if idx.caseInsensitive {
pattern = strings.ToLower(pattern)
}
ctx, err := idx.getAuthenticatedContext(context.Background())
if err != nil {
return nil, err
}
foldersMatched := make([]string, 0)
matches := make([]string, 0)
res, err := idx.storageProvider.ListContainer(ctx, &provider.ListContainerRequest{
Ref: &provider.Reference{
Spec: &provider.Reference_Path{Path: path.Join("/meta", idx.indexRootDir)},
},
})
if err != nil {
return nil, err
}
for _, i := range res.Infos {
if found, err := filepath.Match(pattern, path.Base(i.Path)); found {
if err != nil {
return nil, err
}
foldersMatched = append(foldersMatched, i.Path)
}
}
for i := range foldersMatched {
res, _ := idx.storageProvider.ListContainer(ctx, &provider.ListContainerRequest{
Ref: &provider.Reference{
Spec: &provider.Reference_Path{Path: foldersMatched[i]},
},
})
for _, info := range res.Infos {
matches = append(matches, path.Base(info.Path))
}
}
return matches, nil
}
// CaseInsensitive undocumented.
func (idx *NonUnique) CaseInsensitive() bool {
return idx.caseInsensitive
}
// IndexBy undocumented.
func (idx *NonUnique) IndexBy() string {
return idx.indexBy
}
// TypeName undocumented.
func (idx *NonUnique) TypeName() string {
return idx.typeName
}
// FilesDir undocumented.
func (idx *NonUnique) FilesDir() string {
return idx.filesDir
}
func (idx *NonUnique) authenticate(ctx context.Context) (token string, err error) {
u := &user.User{
Id: &user.UserId{OpaqueId: idx.cs3conf.ServiceUserUUID},
Groups: []string{},
}
return idx.tokenManager.MintToken(ctx, u)
}
func (idx *NonUnique) makeDirIfNotExists(ctx context.Context, folder string) error {
var rootPathRef = &provider.Reference{
Spec: &provider.Reference_Path{Path: fmt.Sprintf("/meta/%v", folder)},
}
resp, err := idx.storageProvider.Stat(ctx, &provider.StatRequest{
Ref: rootPathRef,
})
if err != nil {
return err
}
if resp.Status.Code == v1beta11.Code_CODE_NOT_FOUND {
_, err := idx.storageProvider.CreateContainer(ctx, &provider.CreateContainerRequest{
Ref: rootPathRef,
})
if err != nil {
return err
}
}
return nil
}
func (idx *NonUnique) createSymlink(oldname, newname string) error {
t, err := idx.authenticate(context.TODO())
if err != nil {
return err
}
if _, err := idx.resolveSymlink(newname); err == nil {
return os.ErrExist
}
resp, err := idx.dataProvider.put(newname, strings.NewReader(oldname), t)
if err != nil {
return err
}
if err = resp.Body.Close(); err != nil {
return err
}
return nil
}
func (idx *NonUnique) resolveSymlink(name string) (string, error) {
t, err := idx.authenticate(context.TODO())
if err != nil {
return "", err
}
resp, err := idx.dataProvider.get(name, t)
if err != nil {
return "", err
}
if resp.StatusCode != http.StatusOK {
if resp.StatusCode == http.StatusNotFound {
return "", os.ErrNotExist
}
return "", fmt.Errorf("could not resolve symlink %s, got status %v", name, resp.StatusCode)
}
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
if err = resp.Body.Close(); err != nil {
return "", err
}
return string(b), err
}
func (idx *NonUnique) getAuthenticatedContext(ctx context.Context) (context.Context, error) {
t, err := idx.authenticate(ctx)
if err != nil {
return nil, err
}
ctx = metadata.AppendToOutgoingContext(ctx, token.TokenHeader, t)
return ctx, nil
}

View File

@@ -0,0 +1,68 @@
package cs3
//
//import (
// "os"
// "path"
// "testing"
//
// "github.com/owncloud/ocis/accounts/pkg/config"
// "github.com/owncloud/ocis/accounts/pkg/indexer/option"
// . "github.com/owncloud/ocis/accounts/pkg/indexer/test"
// "github.com/stretchr/testify/assert"
//)
//
//func TestCS3NonUniqueIndex_FakeSymlink(t *testing.T) {
// dataDir, err := WriteIndexTestData(Data, "ID", cs3RootFolder)
// assert.NoError(t, err)
// cfg := config.Config{
// Repo: config.Repo{
// Disk: config.Disk{
// Path: "",
// },
// CS3: config.CS3{
// ProviderAddr: "0.0.0.0:9215",
// DataURL: "http://localhost:9216",
// DataPrefix: "data",
// JWTSecret: "Pive-Fumkiu4",
// },
// },
// }
//
// sut := NewNonUniqueIndexWithOptions(
// option.WithTypeName(GetTypeFQN(User{})),
// option.WithIndexBy("UserName"),
// option.WithFilesDir(path.Join(cfg.Repo.Disk.Path, "/meta")),
// option.WithDataDir(cfg.Repo.Disk.Path),
// option.WithDataURL(cfg.Repo.CS3.DataURL),
// option.WithDataPrefix(cfg.Repo.CS3.DataPrefix),
// option.WithJWTSecret(cfg.Repo.CS3.JWTSecret),
// option.WithProviderAddr(cfg.Repo.CS3.ProviderAddr),
// )
//
// err = sut.Init()
// assert.NoError(t, err)
//
// res, err := sut.Add("abcdefg-123", "mikey")
// assert.NoError(t, err)
// t.Log(res)
//
// resLookup, err := sut.Lookup("mikey")
// assert.NoError(t, err)
// t.Log(resLookup)
//
// err = sut.Update("abcdefg-123", "mikey", "mickeyX")
// assert.NoError(t, err)
//
// searchRes, err := sut.Search("m*")
// assert.NoError(t, err)
// assert.Len(t, searchRes, 1)
// assert.Equal(t, searchRes[0], "abcdefg-123")
//
// resp, err := sut.Lookup("mikey")
// assert.Len(t, resp, 0)
// assert.NoError(t, err)
//
// _ = os.RemoveAll(dataDir)
//
//}

View File

@@ -0,0 +1,372 @@
package cs3
import (
"context"
"fmt"
"io/ioutil"
"net/http"
"os"
"path"
"path/filepath"
"strings"
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
v1beta11 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/pkg/token"
"github.com/cs3org/reva/pkg/token/manager/jwt"
idxerrs "github.com/owncloud/ocis/accounts/pkg/indexer/errors"
"github.com/owncloud/ocis/accounts/pkg/indexer/index"
"github.com/owncloud/ocis/accounts/pkg/indexer/option"
"github.com/owncloud/ocis/accounts/pkg/indexer/registry"
"google.golang.org/grpc/metadata"
)
// Unique are fields for an index of type non_unique.
type Unique struct {
caseInsensitive bool
indexBy string
typeName string
filesDir string
indexBaseDir string
indexRootDir string
tokenManager token.Manager
storageProvider provider.ProviderAPIClient
dataProvider dataProviderClient // Used to create and download data via http, bypassing reva upload protocol
cs3conf *Config
}
// Config represents cs3conf. Should be deprecated in favor of config.Config.
type Config struct {
ProviderAddr string
DataURL string
DataPrefix string
JWTSecret string
ServiceUserName string
ServiceUserUUID string
}
func init() {
registry.IndexConstructorRegistry["cs3"]["unique"] = NewUniqueIndexWithOptions
}
// NewUniqueIndexWithOptions instantiates a new UniqueIndex instance. Init() should be
// called afterward to ensure correct on-disk structure.
func NewUniqueIndexWithOptions(o ...option.Option) index.Index {
opts := &option.Options{}
for _, opt := range o {
opt(opts)
}
u := &Unique{
caseInsensitive: opts.CaseInsensitive,
indexBy: opts.IndexBy,
typeName: opts.TypeName,
filesDir: opts.FilesDir,
indexBaseDir: path.Join(opts.DataDir, "index.cs3"),
indexRootDir: path.Join(path.Join(opts.DataDir, "index.cs3"), strings.Join([]string{"unique", opts.TypeName, opts.IndexBy}, ".")),
cs3conf: &Config{
ProviderAddr: opts.ProviderAddr,
DataURL: opts.DataURL,
DataPrefix: opts.DataPrefix,
JWTSecret: opts.JWTSecret,
ServiceUserName: opts.ServiceUserName,
ServiceUserUUID: opts.ServiceUserUUID,
},
dataProvider: dataProviderClient{
baseURL: singleJoiningSlash(opts.DataURL, opts.DataPrefix),
client: http.Client{
Transport: http.DefaultTransport,
},
},
}
return u
}
// Init initializes a unique index.
func (idx *Unique) Init() error {
tokenManager, err := jwt.New(map[string]interface{}{
"secret": idx.cs3conf.JWTSecret,
})
if err != nil {
return err
}
idx.tokenManager = tokenManager
client, err := pool.GetStorageProviderServiceClient(idx.cs3conf.ProviderAddr)
if err != nil {
return err
}
idx.storageProvider = client
ctx := context.Background()
tk, err := idx.authenticate(ctx)
if err != nil {
return err
}
ctx = metadata.AppendToOutgoingContext(ctx, token.TokenHeader, tk)
if err := idx.makeDirIfNotExists(ctx, idx.indexBaseDir); err != nil {
return err
}
if err := idx.makeDirIfNotExists(ctx, idx.indexRootDir); err != nil {
return err
}
return nil
}
// Lookup exact lookup by value.
func (idx *Unique) Lookup(v string) ([]string, error) {
if idx.caseInsensitive {
v = strings.ToLower(v)
}
searchPath := path.Join(idx.indexRootDir, v)
oldname, err := idx.resolveSymlink(searchPath)
if err != nil {
if os.IsNotExist(err) {
err = &idxerrs.NotFoundErr{TypeName: idx.typeName, Key: idx.indexBy, Value: v}
}
return nil, err
}
return []string{oldname}, nil
}
// Add adds a value to the index, returns the path to the root-document
func (idx *Unique) Add(id, v string) (string, error) {
if v == "" {
return "", nil
}
if idx.caseInsensitive {
v = strings.ToLower(v)
}
newName := path.Join(idx.indexRootDir, v)
if err := idx.createSymlink(id, newName); err != nil {
if os.IsExist(err) {
return "", &idxerrs.AlreadyExistsErr{TypeName: idx.typeName, Key: idx.indexBy, Value: v}
}
return "", err
}
return newName, nil
}
// Remove a value v from an index.
func (idx *Unique) Remove(id string, v string) error {
if v == "" {
return nil
}
if idx.caseInsensitive {
v = strings.ToLower(v)
}
searchPath := path.Join(idx.indexRootDir, v)
_, err := idx.resolveSymlink(searchPath)
if err != nil {
if os.IsNotExist(err) {
err = &idxerrs.NotFoundErr{TypeName: idx.typeName, Key: idx.indexBy, Value: v}
}
return err
}
ctx := context.Background()
t, err := idx.authenticate(ctx)
if err != nil {
return err
}
deletePath := path.Join("/meta", idx.indexRootDir, v)
ctx = metadata.AppendToOutgoingContext(ctx, token.TokenHeader, t)
resp, err := idx.storageProvider.Delete(ctx, &provider.DeleteRequest{
Ref: &provider.Reference{
Spec: &provider.Reference_Path{Path: deletePath},
},
})
if err != nil {
return err
}
// TODO Handle other error codes?
if resp.Status.Code == v1beta11.Code_CODE_NOT_FOUND {
return &idxerrs.NotFoundErr{}
}
return err
}
// Update index from <oldV> to <newV>.
func (idx *Unique) Update(id, oldV, newV string) error {
if idx.caseInsensitive {
oldV = strings.ToLower(oldV)
newV = strings.ToLower(newV)
}
if err := idx.Remove(id, oldV); err != nil {
return err
}
if _, err := idx.Add(id, newV); err != nil {
return err
}
return nil
}
// Search allows for glob search on the index.
func (idx *Unique) Search(pattern string) ([]string, error) {
if idx.caseInsensitive {
pattern = strings.ToLower(pattern)
}
ctx := context.Background()
t, err := idx.authenticate(ctx)
if err != nil {
return nil, err
}
ctx = metadata.AppendToOutgoingContext(ctx, token.TokenHeader, t)
res, err := idx.storageProvider.ListContainer(ctx, &provider.ListContainerRequest{
Ref: &provider.Reference{
Spec: &provider.Reference_Path{Path: path.Join("/meta", idx.indexRootDir)},
},
})
if err != nil {
return nil, err
}
searchPath := idx.indexRootDir
matches := make([]string, 0)
for _, i := range res.GetInfos() {
if found, err := filepath.Match(pattern, path.Base(i.Path)); found {
if err != nil {
return nil, err
}
oldPath, err := idx.resolveSymlink(path.Join(searchPath, path.Base(i.Path)))
if err != nil {
return nil, err
}
matches = append(matches, oldPath)
}
}
return matches, nil
}
// CaseInsensitive undocumented.
func (idx *Unique) CaseInsensitive() bool {
return idx.caseInsensitive
}
// IndexBy undocumented.
func (idx *Unique) IndexBy() string {
return idx.indexBy
}
// TypeName undocumented.
func (idx *Unique) TypeName() string {
return idx.typeName
}
// FilesDir undocumented.
func (idx *Unique) FilesDir() string {
return idx.filesDir
}
func (idx *Unique) createSymlink(oldname, newname string) error {
t, err := idx.authenticate(context.TODO())
if err != nil {
return err
}
if _, err := idx.resolveSymlink(newname); err == nil {
return os.ErrExist
}
resp, err := idx.dataProvider.put(newname, strings.NewReader(oldname), t)
if err != nil {
return err
}
if err = resp.Body.Close(); err != nil {
return err
}
return nil
}
func (idx *Unique) resolveSymlink(name string) (string, error) {
t, err := idx.authenticate(context.TODO())
if err != nil {
return "", err
}
resp, err := idx.dataProvider.get(name, t)
if err != nil {
return "", err
}
if resp.StatusCode != http.StatusOK {
if resp.StatusCode == http.StatusNotFound {
return "", os.ErrNotExist
}
return "", fmt.Errorf("could not resolve symlink %s, got status %v", name, resp.StatusCode)
}
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
if err = resp.Body.Close(); err != nil {
return "", err
}
return string(b), err
}
func (idx *Unique) makeDirIfNotExists(ctx context.Context, folder string) error {
var rootPathRef = &provider.Reference{
Spec: &provider.Reference_Path{Path: fmt.Sprintf("/meta/%v", folder)},
}
resp, err := idx.storageProvider.Stat(ctx, &provider.StatRequest{
Ref: rootPathRef,
})
if err != nil {
return err
}
if resp.Status.Code == v1beta11.Code_CODE_NOT_FOUND {
_, err := idx.storageProvider.CreateContainer(ctx, &provider.CreateContainerRequest{
Ref: rootPathRef,
})
if err != nil {
return err
}
}
return nil
}
func (idx *Unique) authenticate(ctx context.Context) (token string, err error) {
u := &user.User{
Id: &user.UserId{OpaqueId: idx.cs3conf.ServiceUserUUID},
Groups: []string{},
}
return idx.tokenManager.MintToken(ctx, u)
}

View File

@@ -0,0 +1,107 @@
package cs3
//
//import (
// "os"
// "path"
// "testing"
//
// "github.com/owncloud/ocis/accounts/pkg/config"
// "github.com/owncloud/ocis/accounts/pkg/indexer/option"
// . "github.com/owncloud/ocis/accounts/pkg/indexer/test"
// "github.com/stretchr/testify/assert"
//)
//
//func TestCS3UniqueIndex_FakeSymlink(t *testing.T) {
// dataDir, err := WriteIndexTestData(Data, "ID", cs3RootFolder)
// assert.NoError(t, err)
// cfg := config.Config{
// Repo: config.Repo{
// Disk: config.Disk{
// Path: "",
// },
// CS3: config.CS3{
// ProviderAddr: "0.0.0.0:9215",
// DataURL: "http://localhost:9216",
// DataPrefix: "data",
// JWTSecret: "Pive-Fumkiu4",
// },
// },
// }
//
// sut := NewUniqueIndexWithOptions(
// option.WithTypeName(GetTypeFQN(User{})),
// option.WithIndexBy("UserName"),
// option.WithFilesDir(path.Join(cfg.Repo.Disk.Path, "/meta")),
// option.WithDataDir(cfg.Repo.Disk.Path),
// option.WithDataURL(cfg.Repo.CS3.DataURL),
// option.WithDataPrefix(cfg.Repo.CS3.DataPrefix),
// option.WithJWTSecret(cfg.Repo.CS3.JWTSecret),
// option.WithProviderAddr(cfg.Repo.CS3.ProviderAddr),
// )
//
// err = sut.Init()
// assert.NoError(t, err)
//
// res, err := sut.Add("abcdefg-123", "mikey")
// assert.NoError(t, err)
// t.Log(res)
//
// resLookup, err := sut.Lookup("mikey")
// assert.NoError(t, err)
// t.Log(resLookup)
//
// err = sut.Update("abcdefg-123", "mikey", "mickeyX")
// assert.NoError(t, err)
//
// searchRes, err := sut.Search("m*")
// assert.NoError(t, err)
// assert.Len(t, searchRes, 1)
// assert.Equal(t, searchRes[0], "abcdefg-123")
//
// _ = os.RemoveAll(dataDir)
//}
//
//func TestCS3UniqueIndexSearch(t *testing.T) {
// dataDir, err := WriteIndexTestData(Data, "ID", cs3RootFolder)
// assert.NoError(t, err)
// cfg := config.Config{
// Repo: config.Repo{
// Disk: config.Disk{
// Path: "",
// },
// CS3: config.CS3{
// ProviderAddr: "0.0.0.0:9215",
// DataURL: "http://localhost:9216",
// DataPrefix: "data",
// JWTSecret: "Pive-Fumkiu4",
// },
// },
// }
//
// sut := NewUniqueIndexWithOptions(
// option.WithTypeName(GetTypeFQN(User{})),
// option.WithIndexBy("UserName"),
// option.WithFilesDir(path.Join(cfg.Repo.Disk.Path, "/meta")),
// option.WithDataDir(cfg.Repo.Disk.Path),
// option.WithDataURL(cfg.Repo.CS3.DataURL),
// option.WithDataPrefix(cfg.Repo.CS3.DataPrefix),
// option.WithJWTSecret(cfg.Repo.CS3.JWTSecret),
// option.WithProviderAddr(cfg.Repo.CS3.ProviderAddr),
// )
//
// err = sut.Init()
// assert.NoError(t, err)
//
// _, err = sut.Add("hijklmn-456", "mikey")
// assert.NoError(t, err)
//
// _, err = sut.Add("ewf4ofk-555", "jacky")
// assert.NoError(t, err)
//
// res, err := sut.Search("*y")
// assert.NoError(t, err)
// t.Log(res)
//
// _ = os.RemoveAll(dataDir)
//}

View File

@@ -0,0 +1,262 @@
package disk
import (
"errors"
"os"
"path"
"path/filepath"
"reflect"
"sort"
"strconv"
"strings"
idxerrs "github.com/owncloud/ocis/accounts/pkg/indexer/errors"
"github.com/owncloud/ocis/accounts/pkg/indexer/index"
"github.com/owncloud/ocis/accounts/pkg/indexer/option"
"github.com/owncloud/ocis/accounts/pkg/indexer/registry"
)
// Autoincrement are fields for an index of type autoincrement.
type Autoincrement struct {
indexBy string
typeName string
filesDir string
indexBaseDir string
indexRootDir string
bound *option.Bound
}
// - Creating an autoincrement index has to be thread safe.
// - Validation: autoincrement indexes should only work on integers.
func init() {
registry.IndexConstructorRegistry["disk"]["autoincrement"] = NewAutoincrementIndex
}
// NewAutoincrementIndex instantiates a new AutoincrementIndex instance. Init() should be
// called afterward to ensure correct on-disk structure.
func NewAutoincrementIndex(o ...option.Option) index.Index {
opts := &option.Options{}
for _, opt := range o {
opt(opts)
}
// validate the field
if opts.Entity == nil {
panic("invalid autoincrement index: configured without entity")
}
k, err := getKind(opts.Entity, opts.IndexBy)
if !isValidKind(k) || err != nil {
panic("invalid autoincrement index: configured on non-numeric field")
}
return &Autoincrement{
indexBy: opts.IndexBy,
typeName: opts.TypeName,
filesDir: opts.FilesDir,
bound: opts.Bound,
indexBaseDir: path.Join(opts.DataDir, "index.disk"),
indexRootDir: path.Join(path.Join(opts.DataDir, "index.disk"), strings.Join([]string{"autoincrement", opts.TypeName, opts.IndexBy}, ".")),
}
}
var (
validKinds = []reflect.Kind{
reflect.Int,
reflect.Int8,
reflect.Int16,
reflect.Int32,
reflect.Int64,
}
)
// Init initializes an autoincrement index.
func (idx *Autoincrement) Init() error {
if _, err := os.Stat(idx.filesDir); err != nil {
return err
}
if err := os.MkdirAll(idx.indexRootDir, 0777); err != nil {
return err
}
return nil
}
// Lookup exact lookup by value.
func (idx *Autoincrement) Lookup(v string) ([]string, error) {
searchPath := path.Join(idx.indexRootDir, v)
if err := isValidSymlink(searchPath); err != nil {
if os.IsNotExist(err) {
err = &idxerrs.NotFoundErr{TypeName: idx.typeName, Key: idx.indexBy, Value: v}
}
return nil, err
}
p, err := os.Readlink(searchPath)
if err != nil {
return []string{}, nil
}
return []string{p}, err
}
// Add a new value to the index.
func (idx *Autoincrement) Add(id, v string) (string, error) {
nextID, err := idx.next()
if err != nil {
return "", err
}
oldName := filepath.Join(idx.filesDir, id)
var newName string
if v == "" {
newName = filepath.Join(idx.indexRootDir, strconv.Itoa(nextID))
} else {
newName = filepath.Join(idx.indexRootDir, v)
}
err = os.Symlink(oldName, newName)
if errors.Is(err, os.ErrExist) {
return "", &idxerrs.AlreadyExistsErr{TypeName: idx.typeName, Key: idx.indexBy, Value: v}
}
return newName, err
}
// Remove a value v from an index.
func (idx *Autoincrement) Remove(id string, v string) error {
if v == "" {
return nil
}
searchPath := path.Join(idx.indexRootDir, v)
return os.Remove(searchPath)
}
// Update index from <oldV> to <newV>.
func (idx *Autoincrement) Update(id, oldV, newV string) error {
oldPath := path.Join(idx.indexRootDir, oldV)
if err := isValidSymlink(oldPath); err != nil {
if os.IsNotExist(err) {
return &idxerrs.NotFoundErr{TypeName: idx.TypeName(), Key: idx.IndexBy(), Value: oldV}
}
return err
}
newPath := path.Join(idx.indexRootDir, newV)
err := isValidSymlink(newPath)
if err == nil {
return &idxerrs.AlreadyExistsErr{TypeName: idx.typeName, Key: idx.indexBy, Value: newV}
}
if os.IsNotExist(err) {
err = os.Rename(oldPath, newPath)
}
return err
}
// Search allows for glob search on the index.
func (idx *Autoincrement) Search(pattern string) ([]string, error) {
paths, err := filepath.Glob(path.Join(idx.indexRootDir, pattern))
if err != nil {
return nil, err
}
if len(paths) == 0 {
return nil, &idxerrs.NotFoundErr{TypeName: idx.typeName, Key: idx.indexBy, Value: pattern}
}
res := make([]string, 0)
for _, p := range paths {
if err := isValidSymlink(p); err != nil {
return nil, err
}
src, err := os.Readlink(p)
if err != nil {
return nil, err
}
res = append(res, src)
}
return res, nil
}
// CaseInsensitive undocumented.
func (idx *Autoincrement) CaseInsensitive() bool {
return false
}
// IndexBy undocumented.
func (idx *Autoincrement) IndexBy() string {
return idx.indexBy
}
// TypeName undocumented.
func (idx *Autoincrement) TypeName() string {
return idx.typeName
}
// FilesDir undocumented.
func (idx *Autoincrement) FilesDir() string {
return idx.filesDir
}
func isValidKind(k reflect.Kind) bool {
for _, v := range validKinds {
if k == v {
return true
}
}
return false
}
func getKind(i interface{}, field string) (reflect.Kind, error) {
r := reflect.ValueOf(i)
return reflect.Indirect(r).FieldByName(field).Kind(), nil
}
func readDir(dirname string) ([]os.FileInfo, error) {
f, err := os.Open(dirname)
if err != nil {
return nil, err
}
list, err := f.Readdir(-1)
f.Close()
if err != nil {
return nil, err
}
sort.Slice(list, func(i, j int) bool {
a, _ := strconv.Atoi(list[i].Name())
b, _ := strconv.Atoi(list[j].Name())
return a < b
})
return list, nil
}
func (idx *Autoincrement) next() (int, error) {
files, err := readDir(idx.indexRootDir)
if err != nil {
return -1, err
}
if len(files) == 0 {
return int(idx.bound.Lower), nil
}
latest, err := strconv.Atoi(path.Base(files[len(files)-1].Name()))
if err != nil {
return -1, err
}
if int64(latest) < idx.bound.Lower {
return int(idx.bound.Lower), nil
}
return latest + 1, nil
}

View File

@@ -0,0 +1,299 @@
package disk
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/owncloud/ocis/accounts/pkg/indexer/option"
//. "github.com/owncloud/ocis/accounts/pkg/indexer/test"
"github.com/owncloud/ocis/accounts/pkg/proto/v0"
"github.com/stretchr/testify/assert"
)
func TestIsValidKind(t *testing.T) {
scenarios := []struct {
panics bool
name string
indexBy string
entity struct {
Number int
Name string
NumberFloat float32
}
}{
{
name: "valid autoincrement index",
panics: false,
indexBy: "Number",
entity: struct {
Number int
Name string
NumberFloat float32
}{
Name: "tesy-mc-testace",
},
},
{
name: "create autoincrement index on a non-existing field",
panics: true,
indexBy: "Age",
entity: struct {
Number int
Name string
NumberFloat float32
}{
Name: "tesy-mc-testace",
},
},
{
name: "attempt to create an autoincrement index with no entity",
panics: true,
indexBy: "Age",
},
{
name: "create autoincrement index on a non-numeric field",
panics: true,
indexBy: "Name",
entity: struct {
Number int
Name string
NumberFloat float32
}{
Name: "tesy-mc-testace",
},
},
}
for _, scenario := range scenarios {
t.Run(scenario.name, func(t *testing.T) {
if scenario.panics {
assert.Panics(t, func() {
_ = NewAutoincrementIndex(
option.WithEntity(scenario.entity),
option.WithIndexBy(scenario.indexBy),
)
})
} else {
assert.NotPanics(t, func() {
_ = NewAutoincrementIndex(
option.WithEntity(scenario.entity),
option.WithIndexBy(scenario.indexBy),
)
})
}
})
}
}
func TestNext(t *testing.T) {
scenarios := []struct {
name string
expected int
indexBy string
entity interface{}
}{
{
name: "get next value",
expected: 0,
indexBy: "Number",
entity: struct {
Number int
Name string
NumberFloat float32
}{
Name: "tesy-mc-testace",
},
},
}
for _, scenario := range scenarios {
t.Run(scenario.name, func(t *testing.T) {
tmpDir, err := createTmpDirStr()
assert.NoError(t, err)
err = os.MkdirAll(filepath.Join(tmpDir, "data"), 0777)
assert.NoError(t, err)
i := NewAutoincrementIndex(
option.WithBounds(&option.Bound{
Lower: 0,
Upper: 0,
}),
option.WithDataDir(tmpDir),
option.WithFilesDir(filepath.Join(tmpDir, "data")),
option.WithEntity(scenario.entity),
option.WithTypeName("LambdaType"),
option.WithIndexBy(scenario.indexBy),
)
err = i.Init()
assert.NoError(t, err)
tmpFile, err := os.Create(filepath.Join(tmpDir, "data", "test-example"))
assert.NoError(t, err)
assert.NoError(t, tmpFile.Close())
oldName, err := i.Add("test-example", "")
assert.NoError(t, err)
assert.Equal(t, "0", filepath.Base(oldName))
oldName, err = i.Add("test-example", "")
assert.NoError(t, err)
assert.Equal(t, "1", filepath.Base(oldName))
oldName, err = i.Add("test-example", "")
assert.NoError(t, err)
assert.Equal(t, "2", filepath.Base(oldName))
t.Log(oldName)
_ = os.RemoveAll(tmpDir)
})
}
}
func TestLowerBound(t *testing.T) {
scenarios := []struct {
name string
expected int
indexBy string
entity interface{}
}{
{
name: "get next value with a lower bound specified",
expected: 0,
indexBy: "Number",
entity: struct {
Number int
Name string
NumberFloat float32
}{
Name: "tesy-mc-testace",
},
},
}
for _, scenario := range scenarios {
t.Run(scenario.name, func(t *testing.T) {
tmpDir, err := createTmpDirStr()
assert.NoError(t, err)
err = os.MkdirAll(filepath.Join(tmpDir, "data"), 0777)
assert.NoError(t, err)
i := NewAutoincrementIndex(
option.WithBounds(&option.Bound{
Lower: 1000,
}),
option.WithDataDir(tmpDir),
option.WithFilesDir(filepath.Join(tmpDir, "data")),
option.WithEntity(scenario.entity),
option.WithTypeName("LambdaType"),
option.WithIndexBy(scenario.indexBy),
)
err = i.Init()
assert.NoError(t, err)
tmpFile, err := os.Create(filepath.Join(tmpDir, "data", "test-example"))
assert.NoError(t, err)
assert.NoError(t, tmpFile.Close())
oldName, err := i.Add("test-example", "")
assert.NoError(t, err)
assert.Equal(t, "1000", filepath.Base(oldName))
oldName, err = i.Add("test-example", "")
assert.NoError(t, err)
assert.Equal(t, "1001", filepath.Base(oldName))
oldName, err = i.Add("test-example", "")
assert.NoError(t, err)
assert.Equal(t, "1002", filepath.Base(oldName))
t.Log(oldName)
_ = os.RemoveAll(tmpDir)
})
}
}
func TestAdd(t *testing.T) {
tmpDir, err := createTmpDirStr()
assert.NoError(t, err)
err = os.MkdirAll(filepath.Join(tmpDir, "data"), 0777)
assert.NoError(t, err)
tmpFile, err := os.Create(filepath.Join(tmpDir, "data", "test-example"))
assert.NoError(t, err)
assert.NoError(t, tmpFile.Close())
i := NewAutoincrementIndex(
option.WithBounds(&option.Bound{
Lower: 0,
Upper: 0,
}),
option.WithDataDir(tmpDir),
option.WithFilesDir(filepath.Join(tmpDir, "data")),
option.WithEntity(&proto.Account{}),
option.WithTypeName("owncloud.Account"),
option.WithIndexBy("UidNumber"),
)
err = i.Init()
assert.NoError(t, err)
_, err = i.Add("test-example", "")
if err != nil {
t.Error(err)
}
}
func BenchmarkAdd(b *testing.B) {
tmpDir, err := createTmpDirStr()
assert.NoError(b, err)
err = os.MkdirAll(filepath.Join(tmpDir, "data"), 0777)
assert.NoError(b, err)
tmpFile, err := os.Create(filepath.Join(tmpDir, "data", "test-example"))
assert.NoError(b, err)
assert.NoError(b, tmpFile.Close())
i := NewAutoincrementIndex(
option.WithBounds(&option.Bound{
Lower: 0,
Upper: 0,
}),
option.WithDataDir(tmpDir),
option.WithFilesDir(filepath.Join(tmpDir, "data")),
option.WithEntity(struct {
Number int
Name string
NumberFloat float32
}{}),
option.WithTypeName("LambdaType"),
option.WithIndexBy("Number"),
)
err = i.Init()
assert.NoError(b, err)
for n := 0; n < b.N; n++ {
_, err := i.Add("test-example", "")
if err != nil {
b.Error(err)
}
assert.NoError(b, err)
}
}
func createTmpDirStr() (string, error) {
name, err := ioutil.TempDir("/var/tmp", "testfiles-*")
if err != nil {
return "", err
}
return name, nil
}

View File

@@ -0,0 +1,235 @@
package disk
import (
"errors"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
idxerrs "github.com/owncloud/ocis/accounts/pkg/indexer/errors"
"github.com/owncloud/ocis/accounts/pkg/indexer/index"
"github.com/owncloud/ocis/accounts/pkg/indexer/option"
"github.com/owncloud/ocis/accounts/pkg/indexer/registry"
)
// NonUnique is able to index an document by a key which might contain non-unique values
//
// /var/tmp/testfiles-395764020/index.disk/PetByColor/
// ├── Brown
// │ └── rebef-123 -> /var/tmp/testfiles-395764020/pets/rebef-123
// ├── Green
// │ ├── goefe-789 -> /var/tmp/testfiles-395764020/pets/goefe-789
// │ └── xadaf-189 -> /var/tmp/testfiles-395764020/pets/xadaf-189
// └── White
// └── wefwe-456 -> /var/tmp/testfiles-395764020/pets/wefwe-456
type NonUnique struct {
caseInsensitive bool
indexBy string
typeName string
filesDir string
indexBaseDir string
indexRootDir string
}
func init() {
registry.IndexConstructorRegistry["disk"]["non_unique"] = NewNonUniqueIndexWithOptions
}
// NewNonUniqueIndexWithOptions instantiates a new UniqueIndex instance. Init() should be
// called afterward to ensure correct on-disk structure.
func NewNonUniqueIndexWithOptions(o ...option.Option) index.Index {
opts := &option.Options{}
for _, opt := range o {
opt(opts)
}
return &NonUnique{
caseInsensitive: opts.CaseInsensitive,
indexBy: opts.IndexBy,
typeName: opts.TypeName,
filesDir: opts.FilesDir,
indexBaseDir: path.Join(opts.DataDir, "index.disk"),
indexRootDir: path.Join(path.Join(opts.DataDir, "index.disk"), strings.Join([]string{"non_unique", opts.TypeName, opts.IndexBy}, ".")),
}
}
// Init initializes a unique index.
func (idx *NonUnique) Init() error {
if _, err := os.Stat(idx.filesDir); err != nil {
return err
}
if err := os.MkdirAll(idx.indexRootDir, 0777); err != nil {
return err
}
return nil
}
// Lookup exact lookup by value.
func (idx *NonUnique) Lookup(v string) ([]string, error) {
if idx.caseInsensitive {
v = strings.ToLower(v)
}
searchPath := path.Join(idx.indexRootDir, v)
fi, err := ioutil.ReadDir(searchPath)
if os.IsNotExist(err) {
return []string{}, &idxerrs.NotFoundErr{TypeName: idx.typeName, Key: idx.indexBy, Value: v}
}
if err != nil {
return []string{}, err
}
var ids []string = nil
for _, f := range fi {
ids = append(ids, f.Name())
}
if len(ids) == 0 {
return []string{}, &idxerrs.NotFoundErr{TypeName: idx.typeName, Key: idx.indexBy, Value: v}
}
return ids, nil
}
// Add adds a value to the index, returns the path to the root-document
func (idx *NonUnique) Add(id, v string) (string, error) {
if v == "" {
return "", nil
}
if idx.caseInsensitive {
v = strings.ToLower(v)
}
oldName := path.Join(idx.filesDir, id)
newName := path.Join(idx.indexRootDir, v, id)
if err := os.MkdirAll(path.Join(idx.indexRootDir, v), 0777); err != nil {
return "", err
}
err := os.Symlink(oldName, newName)
if errors.Is(err, os.ErrExist) {
return "", &idxerrs.AlreadyExistsErr{TypeName: idx.typeName, Key: idx.indexBy, Value: v}
}
return newName, err
}
// Remove a value v from an index.
func (idx *NonUnique) Remove(id string, v string) error {
if v == "" {
return nil
}
if idx.caseInsensitive {
v = strings.ToLower(v)
}
res, err := filepath.Glob(path.Join(idx.indexRootDir, "/*/", id))
if err != nil {
return err
}
for _, p := range res {
if err := os.Remove(p); err != nil {
return err
}
}
// Remove value directory if it is empty
valueDir := path.Join(idx.indexRootDir, v)
fi, err := ioutil.ReadDir(valueDir)
if err != nil {
return err
}
if len(fi) == 0 {
if err := os.RemoveAll(valueDir); err != nil {
return err
}
}
return nil
}
// Update index from <oldV> to <newV>.
func (idx *NonUnique) Update(id, oldV, newV string) (err error) {
if idx.caseInsensitive {
oldV = strings.ToLower(oldV)
newV = strings.ToLower(newV)
}
oldDir := path.Join(idx.indexRootDir, oldV)
oldPath := path.Join(oldDir, id)
newDir := path.Join(idx.indexRootDir, newV)
newPath := path.Join(newDir, id)
if _, err = os.Stat(oldPath); os.IsNotExist(err) {
return &idxerrs.NotFoundErr{TypeName: idx.typeName, Key: idx.indexBy, Value: oldV}
}
if err != nil {
return
}
if err = os.MkdirAll(newDir, 0777); err != nil {
return
}
if err = os.Rename(oldPath, newPath); err != nil {
return
}
di, err := ioutil.ReadDir(oldDir)
if err != nil {
return err
}
if len(di) == 0 {
err = os.RemoveAll(oldDir)
if err != nil {
return
}
}
return
}
// Search allows for glob search on the index.
func (idx *NonUnique) Search(pattern string) ([]string, error) {
if idx.caseInsensitive {
pattern = strings.ToLower(pattern)
}
paths, err := filepath.Glob(path.Join(idx.indexRootDir, pattern, "*"))
if err != nil {
return nil, err
}
if len(paths) == 0 {
return nil, &idxerrs.NotFoundErr{TypeName: idx.typeName, Key: idx.indexBy, Value: pattern}
}
return paths, nil
}
// CaseInsensitive undocumented.
func (idx *NonUnique) CaseInsensitive() bool {
return idx.caseInsensitive
}
// IndexBy undocumented.
func (idx *NonUnique) IndexBy() string {
return idx.indexBy
}
// TypeName undocumented.
func (idx *NonUnique) TypeName() string {
return idx.typeName
}
// FilesDir undocumented.
func (idx *NonUnique) FilesDir() string {
return idx.filesDir
}

View File

@@ -0,0 +1,113 @@
package disk
import (
"fmt"
"os"
"path"
"testing"
"github.com/owncloud/ocis/accounts/pkg/config"
"github.com/owncloud/ocis/accounts/pkg/indexer/errors"
"github.com/owncloud/ocis/accounts/pkg/indexer/index"
"github.com/owncloud/ocis/accounts/pkg/indexer/option"
. "github.com/owncloud/ocis/accounts/pkg/indexer/test"
"github.com/stretchr/testify/assert"
)
func TestNonUniqueIndexAdd(t *testing.T) {
sut, dataPath := getNonUniqueIdxSut(t, Pet{}, "Color")
ids, err := sut.Lookup("Green")
assert.NoError(t, err)
assert.EqualValues(t, []string{"goefe-789", "xadaf-189"}, ids)
ids, err = sut.Lookup("White")
assert.NoError(t, err)
assert.EqualValues(t, []string{"wefwe-456"}, ids)
ids, err = sut.Lookup("Cyan")
assert.Error(t, err)
assert.EqualValues(t, []string{}, ids)
_ = os.RemoveAll(dataPath)
}
func TestNonUniqueIndexUpdate(t *testing.T) {
sut, dataPath := getNonUniqueIdxSut(t, Pet{}, "Color")
err := sut.Update("goefe-789", "Green", "Black")
assert.NoError(t, err)
err = sut.Update("xadaf-189", "Green", "Black")
assert.NoError(t, err)
assert.DirExists(t, path.Join(dataPath, fmt.Sprintf("index.disk/non_unique.%v.Color/Black", GetTypeFQN(Pet{}))))
assert.NoDirExists(t, path.Join(dataPath, fmt.Sprintf("index.disk/non_unique.%v.Color/Green", GetTypeFQN(Pet{}))))
_ = os.RemoveAll(dataPath)
}
func TestNonUniqueIndexDelete(t *testing.T) {
sut, dataPath := getNonUniqueIdxSut(t, Pet{}, "Color")
assert.FileExists(t, path.Join(dataPath, fmt.Sprintf("index.disk/non_unique.%v.Color/Green/goefe-789", GetTypeFQN(Pet{}))))
err := sut.Remove("goefe-789", "Green")
assert.NoError(t, err)
assert.NoFileExists(t, path.Join(dataPath, fmt.Sprintf("index.disk/non_unique.%v.Color/Green/goefe-789", GetTypeFQN(Pet{}))))
assert.FileExists(t, path.Join(dataPath, fmt.Sprintf("index.disk/non_unique.%v.Color/Green/xadaf-189", GetTypeFQN(Pet{}))))
_ = os.RemoveAll(dataPath)
}
func TestNonUniqueIndexSearch(t *testing.T) {
sut, dataPath := getNonUniqueIdxSut(t, Pet{}, "Email")
res, err := sut.Search("Gr*")
assert.NoError(t, err)
assert.Len(t, res, 2)
assert.Equal(t, "goefe-789", path.Base(res[0]))
assert.Equal(t, "xadaf-189", path.Base(res[1]))
_, err = sut.Search("does-not-exist@example.com")
assert.Error(t, err)
assert.IsType(t, &errors.NotFoundErr{}, err)
_ = os.RemoveAll(dataPath)
}
// entity: used to get the fully qualified name for the index root path.
func getNonUniqueIdxSut(t *testing.T, entity interface{}, indexBy string) (index.Index, string) {
dataPath, _ := WriteIndexTestData(Data, "ID", "")
cfg := config.Config{
Repo: config.Repo{
Disk: config.Disk{
Path: dataPath,
},
},
}
sut := NewNonUniqueIndexWithOptions(
option.WithTypeName(GetTypeFQN(entity)),
option.WithIndexBy(indexBy),
option.WithFilesDir(path.Join(cfg.Repo.Disk.Path, "pets")),
option.WithDataDir(cfg.Repo.Disk.Path),
)
err := sut.Init()
if err != nil {
t.Fatal(err)
}
for _, u := range Data["pets"] {
pkVal := ValueOf(u, "ID")
idxByVal := ValueOf(u, "Color")
_, err := sut.Add(pkVal, idxByVal)
if err != nil {
t.Fatal(err)
}
}
return sut, dataPath
}

View File

@@ -0,0 +1,222 @@
package disk
import (
"errors"
"fmt"
"os"
"path"
"path/filepath"
"strings"
idxerrs "github.com/owncloud/ocis/accounts/pkg/indexer/errors"
"github.com/owncloud/ocis/accounts/pkg/indexer/index"
"github.com/owncloud/ocis/accounts/pkg/indexer/option"
"github.com/owncloud/ocis/accounts/pkg/indexer/registry"
)
// Unique ensures that only one document of the same type and key-value combination can exist in the index.
//
// Modeled by creating a indexer-folder per entity and key with symlinks which point to respective documents which contain
// the link-filename as value.
//
// Directory Layout
//
// /var/data/index.disk/UniqueUserByEmail/
// ├── jacky@example.com -> /var/data/users/ewf4ofk-555
// ├── jones@example.com -> /var/data/users/rulan54-777
// └── mikey@example.com -> /var/data/users/abcdefg-123
//
// Example user
//
// {
// "Id": "ewf4ofk-555",
// "UserName": "jacky",
// "Email": "jacky@example.com"
// }
//
type Unique struct {
caseInsensitive bool
indexBy string
typeName string
filesDir string
indexBaseDir string
indexRootDir string
}
func init() {
registry.IndexConstructorRegistry["disk"]["unique"] = NewUniqueIndexWithOptions
}
// NewUniqueIndexWithOptions instantiates a new UniqueIndex instance. Init() should be
// called afterward to ensure correct on-disk structure.
func NewUniqueIndexWithOptions(o ...option.Option) index.Index {
opts := &option.Options{}
for _, opt := range o {
opt(opts)
}
return &Unique{
caseInsensitive: opts.CaseInsensitive,
indexBy: opts.IndexBy,
typeName: opts.TypeName,
filesDir: opts.FilesDir,
indexBaseDir: path.Join(opts.DataDir, "index.disk"),
indexRootDir: path.Join(path.Join(opts.DataDir, "index.disk"), strings.Join([]string{"unique", opts.TypeName, opts.IndexBy}, ".")),
}
}
// Init initializes a unique index.
func (idx *Unique) Init() error {
if _, err := os.Stat(idx.filesDir); err != nil {
return err
}
if err := os.MkdirAll(idx.indexRootDir, 0777); err != nil {
return err
}
return nil
}
// Add adds a value to the index, returns the path to the root-document
func (idx *Unique) Add(id, v string) (string, error) {
if v == "" {
return "", nil
}
if idx.caseInsensitive {
v = strings.ToLower(v)
}
oldName := path.Join(idx.filesDir, id)
newName := path.Join(idx.indexRootDir, v)
err := os.Symlink(oldName, newName)
if errors.Is(err, os.ErrExist) {
return "", &idxerrs.AlreadyExistsErr{TypeName: idx.typeName, Key: idx.indexBy, Value: v}
}
return newName, err
}
// Remove a value v from an index.
func (idx *Unique) Remove(id string, v string) (err error) {
if v == "" {
return nil
}
if idx.caseInsensitive {
v = strings.ToLower(v)
}
searchPath := path.Join(idx.indexRootDir, v)
return os.Remove(searchPath)
}
// Lookup exact lookup by value.
func (idx *Unique) Lookup(v string) (resultPath []string, err error) {
if idx.caseInsensitive {
v = strings.ToLower(v)
}
searchPath := path.Join(idx.indexRootDir, v)
if err = isValidSymlink(searchPath); err != nil {
if os.IsNotExist(err) {
err = &idxerrs.NotFoundErr{TypeName: idx.typeName, Key: idx.indexBy, Value: v}
}
return
}
p, err := os.Readlink(searchPath)
if err != nil {
return []string{}, nil
}
return []string{p}, err
}
// Update index from <oldV> to <newV>.
func (idx *Unique) Update(id, oldV, newV string) (err error) {
if idx.caseInsensitive {
oldV = strings.ToLower(oldV)
newV = strings.ToLower(newV)
}
oldPath := path.Join(idx.indexRootDir, oldV)
if err = isValidSymlink(oldPath); err != nil {
if os.IsNotExist(err) {
return &idxerrs.NotFoundErr{TypeName: idx.TypeName(), Key: idx.IndexBy(), Value: oldV}
}
return
}
newPath := path.Join(idx.indexRootDir, newV)
if err = isValidSymlink(newPath); err == nil {
return &idxerrs.AlreadyExistsErr{TypeName: idx.typeName, Key: idx.indexBy, Value: newV}
}
if os.IsNotExist(err) {
err = os.Rename(oldPath, newPath)
}
return
}
// Search allows for glob search on the index.
func (idx *Unique) Search(pattern string) ([]string, error) {
if idx.caseInsensitive {
pattern = strings.ToLower(pattern)
}
paths, err := filepath.Glob(path.Join(idx.indexRootDir, pattern))
if err != nil {
return nil, err
}
if len(paths) == 0 {
return nil, &idxerrs.NotFoundErr{TypeName: idx.typeName, Key: idx.indexBy, Value: pattern}
}
res := make([]string, 0)
for _, p := range paths {
if err := isValidSymlink(p); err != nil {
return nil, err
}
src, err := os.Readlink(p)
if err != nil {
return nil, err
}
res = append(res, src)
}
return res, nil
}
// CaseInsensitive undocumented.
func (idx *Unique) CaseInsensitive() bool {
return idx.caseInsensitive
}
// IndexBy undocumented.
func (idx *Unique) IndexBy() string {
return idx.indexBy
}
// TypeName undocumented.
func (idx *Unique) TypeName() string {
return idx.typeName
}
// FilesDir undocumented.
func (idx *Unique) FilesDir() string {
return idx.filesDir
}
func isValidSymlink(path string) (err error) {
var symInfo os.FileInfo
if symInfo, err = os.Lstat(path); err != nil {
return
}
if symInfo.Mode()&os.ModeSymlink == 0 {
err = fmt.Errorf("%s is not a valid symlink (bug/corruption?)", path)
return
}
return
}

View File

@@ -0,0 +1,133 @@
package disk
import (
"os"
"path"
"testing"
"github.com/owncloud/ocis/accounts/pkg/config"
"github.com/owncloud/ocis/accounts/pkg/indexer/errors"
"github.com/owncloud/ocis/accounts/pkg/indexer/index"
"github.com/owncloud/ocis/accounts/pkg/indexer/option"
. "github.com/owncloud/ocis/accounts/pkg/indexer/test"
"github.com/stretchr/testify/assert"
)
func TestUniqueLookupSingleEntry(t *testing.T) {
uniq, dataDir := getUniqueIdxSut(t, "Email", User{})
filesDir := path.Join(dataDir, "users")
t.Log("existing lookup")
resultPath, err := uniq.Lookup("mikey@example.com")
assert.NoError(t, err)
assert.Equal(t, []string{path.Join(filesDir, "abcdefg-123")}, resultPath)
t.Log("non-existing lookup")
resultPath, err = uniq.Lookup("doesnotExists@example.com")
assert.Error(t, err)
assert.IsType(t, &errors.NotFoundErr{}, err)
assert.Empty(t, resultPath)
_ = os.RemoveAll(dataDir)
}
func TestUniqueUniqueConstraint(t *testing.T) {
uniq, dataDir := getUniqueIdxSut(t, "Email", User{})
_, err := uniq.Add("abcdefg-123", "mikey@example.com")
assert.Error(t, err)
assert.IsType(t, &errors.AlreadyExistsErr{}, err)
_ = os.RemoveAll(dataDir)
}
func TestUniqueRemove(t *testing.T) {
uniq, dataDir := getUniqueIdxSut(t, "Email", User{})
err := uniq.Remove("", "mikey@example.com")
assert.NoError(t, err)
_, err = uniq.Lookup("mikey@example.com")
assert.Error(t, err)
assert.IsType(t, &errors.NotFoundErr{}, err)
_ = os.RemoveAll(dataDir)
}
func TestUniqueUpdate(t *testing.T) {
uniq, dataDir := getUniqueIdxSut(t, "Email", User{})
t.Log("successful update")
err := uniq.Update("", "mikey@example.com", "mikey2@example.com")
assert.NoError(t, err)
t.Log("failed update because already exists")
err = uniq.Update("", "mikey2@example.com", "mikey2@example.com")
assert.Error(t, err)
assert.IsType(t, &errors.AlreadyExistsErr{}, err)
t.Log("failed update because not found")
err = uniq.Update("", "nonexisting@example.com", "something2@example.com")
assert.Error(t, err)
assert.IsType(t, &errors.NotFoundErr{}, err)
_ = os.RemoveAll(dataDir)
}
func TestUniqueIndexSearch(t *testing.T) {
sut, dataDir := getUniqueIdxSut(t, "Email", User{})
res, err := sut.Search("j*@example.com")
assert.NoError(t, err)
assert.Len(t, res, 2)
assert.Equal(t, "ewf4ofk-555", path.Base(res[0]))
assert.Equal(t, "rulan54-777", path.Base(res[1]))
_, err = sut.Search("does-not-exist@example.com")
assert.Error(t, err)
assert.IsType(t, &errors.NotFoundErr{}, err)
_ = os.RemoveAll(dataDir)
}
func TestErrors(t *testing.T) {
assert.True(t, errors.IsAlreadyExistsErr(&errors.AlreadyExistsErr{}))
assert.True(t, errors.IsNotFoundErr(&errors.NotFoundErr{}))
}
func getUniqueIdxSut(t *testing.T, indexBy string, entityType interface{}) (index.Index, string) {
dataPath, _ := WriteIndexTestData(Data, "ID", "")
cfg := config.Config{
Repo: config.Repo{
Disk: config.Disk{
Path: dataPath,
},
},
}
sut := NewUniqueIndexWithOptions(
option.WithTypeName(GetTypeFQN(entityType)),
option.WithIndexBy(indexBy),
option.WithFilesDir(path.Join(cfg.Repo.Disk.Path, "users")),
option.WithDataDir(cfg.Repo.Disk.Path),
)
err := sut.Init()
if err != nil {
t.Fatal(err)
}
for _, u := range Data["users"] {
pkVal := ValueOf(u, "ID")
idxByVal := ValueOf(u, "Email")
_, err := sut.Add(pkVal, idxByVal)
if err != nil {
t.Fatal(err)
}
}
return sut, dataPath
}

View File

@@ -0,0 +1,16 @@
package index
// Index can be implemented to create new indexer-strategies. See Unique for example.
// Each indexer implementation is bound to one data-column (IndexBy) and a data-type (TypeName)
type Index interface {
Init() error
Lookup(v string) ([]string, error)
Add(id, v string) (string, error)
Remove(id string, v string) error
Update(id, oldV, newV string) error
Search(pattern string) ([]string, error)
CaseInsensitive() bool
IndexBy() string
TypeName() string
FilesDir() string
}

View File

@@ -0,0 +1,222 @@
// Package indexer provides symlink-based indexer for on-disk document-directories.
package indexer
import (
"fmt"
"path"
"github.com/iancoleman/strcase"
"github.com/owncloud/ocis/accounts/pkg/config"
"github.com/owncloud/ocis/accounts/pkg/indexer/errors"
"github.com/owncloud/ocis/accounts/pkg/indexer/index"
_ "github.com/owncloud/ocis/accounts/pkg/indexer/index/cs3" // to populate index
_ "github.com/owncloud/ocis/accounts/pkg/indexer/index/disk" // to populate index
"github.com/owncloud/ocis/accounts/pkg/indexer/option"
"github.com/owncloud/ocis/accounts/pkg/indexer/registry"
)
// Indexer is a facade to configure and query over multiple indices.
type Indexer struct {
config *config.Config
indices typeMap
}
// IdxAddResult represents the result of an Add call on an index
type IdxAddResult struct {
Field, Value string
}
// CreateIndexer creates a new Indexer.
func CreateIndexer(cfg *config.Config) *Indexer {
return &Indexer{
config: cfg,
indices: typeMap{},
}
}
func getRegistryStrategy(cfg *config.Config) string {
if cfg.Repo.Disk.Path != "" {
return "disk"
}
return "cs3"
}
// AddIndex adds a new index to the indexer receiver.
func (i Indexer) AddIndex(t interface{}, indexBy, pkName, entityDirName, indexType string, bound *option.Bound, caseInsensitive bool) error {
strategy := getRegistryStrategy(i.config)
f := registry.IndexConstructorRegistry[strategy][indexType]
var idx index.Index
if strategy == "disk" {
idx = f(
option.CaseInsensitive(caseInsensitive),
option.WithEntity(t),
option.WithBounds(bound),
option.WithTypeName(getTypeFQN(t)),
option.WithIndexBy(indexBy),
option.WithFilesDir(path.Join(i.config.Repo.Disk.Path, entityDirName)),
option.WithDataDir(i.config.Repo.Disk.Path),
)
} else if strategy == "cs3" {
idx = f(
option.CaseInsensitive(caseInsensitive),
option.WithEntity(t),
option.WithBounds(bound),
option.WithTypeName(getTypeFQN(t)),
option.WithIndexBy(indexBy),
option.WithDataURL(i.config.Repo.CS3.DataURL),
option.WithDataPrefix(i.config.Repo.CS3.DataPrefix),
option.WithJWTSecret(i.config.Repo.CS3.JWTSecret),
option.WithProviderAddr(i.config.Repo.CS3.ProviderAddr),
option.WithServiceUserUUID(i.config.ServiceUser.UUID),
option.WithServiceUserName(i.config.ServiceUser.Username),
)
}
i.indices.addIndex(getTypeFQN(t), pkName, idx)
return idx.Init()
}
// Add a new entry to the indexer
func (i Indexer) Add(t interface{}) ([]IdxAddResult, error) {
typeName := getTypeFQN(t)
var results []IdxAddResult
if fields, ok := i.indices[typeName]; ok {
for _, indices := range fields.IndicesByField {
for _, idx := range indices {
pkVal := valueOf(t, fields.PKFieldName)
idxByVal := valueOf(t, idx.IndexBy())
value, err := idx.Add(pkVal, idxByVal)
if err != nil {
return []IdxAddResult{}, err
}
if value == "" {
continue
}
results = append(results, IdxAddResult{Field: idx.IndexBy(), Value: value})
}
}
}
return results, nil
}
// FindBy finds a value on an index by field and value.
func (i Indexer) FindBy(t interface{}, field string, val string) ([]string, error) {
typeName := getTypeFQN(t)
resultPaths := make([]string, 0)
if fields, ok := i.indices[typeName]; ok {
for _, idx := range fields.IndicesByField[strcase.ToCamel(field)] {
idxVal := val
res, err := idx.Lookup(idxVal)
if err != nil {
if errors.IsNotFoundErr(err) {
continue
}
if err != nil {
return nil, err
}
}
resultPaths = append(resultPaths, res...)
}
}
result := make([]string, 0, len(resultPaths))
for _, v := range resultPaths {
result = append(result, path.Base(v))
}
return result, nil
}
// Delete deletes all indexed fields of a given type t on the Indexer.
func (i Indexer) Delete(t interface{}) error {
typeName := getTypeFQN(t)
if fields, ok := i.indices[typeName]; ok {
for _, indices := range fields.IndicesByField {
for _, idx := range indices {
pkVal := valueOf(t, fields.PKFieldName)
idxByVal := valueOf(t, idx.IndexBy())
if err := idx.Remove(pkVal, idxByVal); err != nil {
return err
}
}
}
}
return nil
}
// FindByPartial allows for glob search across all indexes.
func (i Indexer) FindByPartial(t interface{}, field string, pattern string) ([]string, error) {
typeName := getTypeFQN(t)
resultPaths := make([]string, 0)
if fields, ok := i.indices[typeName]; ok {
for _, idx := range fields.IndicesByField[strcase.ToCamel(field)] {
res, err := idx.Search(pattern)
if err != nil {
if errors.IsNotFoundErr(err) {
continue
}
if err != nil {
return nil, err
}
}
resultPaths = append(resultPaths, res...)
}
}
result := make([]string, 0, len(resultPaths))
for _, v := range resultPaths {
result = append(result, path.Base(v))
}
return result, nil
}
// Update updates all indexes on a value <from> to a value <to>.
func (i Indexer) Update(from, to interface{}) error {
typeNameFrom := getTypeFQN(from)
typeNameTo := getTypeFQN(to)
if typeNameFrom != typeNameTo {
return fmt.Errorf("update types do not match: from %v to %v", typeNameFrom, typeNameTo)
}
if fields, ok := i.indices[typeNameFrom]; ok {
for fName, indices := range fields.IndicesByField {
oldV := valueOf(from, fName)
newV := valueOf(to, fName)
pkVal := valueOf(from, fields.PKFieldName)
for _, idx := range indices {
if oldV == newV {
continue
}
if oldV == "" {
if _, err := idx.Add(pkVal, newV); err != nil {
return err
}
continue
}
if newV == "" {
if err := idx.Remove(pkVal, oldV); err != nil {
return err
}
continue
}
if err := idx.Update(pkVal, oldV, newV); err != nil {
return err
}
}
}
}
return nil
}

View File

@@ -0,0 +1,275 @@
package indexer
import (
"os"
"path"
"testing"
"github.com/owncloud/ocis/accounts/pkg/indexer/option"
"github.com/owncloud/ocis/accounts/pkg/config"
_ "github.com/owncloud/ocis/accounts/pkg/indexer/index/cs3"
_ "github.com/owncloud/ocis/accounts/pkg/indexer/index/disk"
. "github.com/owncloud/ocis/accounts/pkg/indexer/test"
"github.com/stretchr/testify/assert"
)
const cs3RootFolder = "/var/tmp/ocis/storage/users/data"
func TestIndexer_CS3_AddWithUniqueIndex(t *testing.T) {
dataDir, err := WriteIndexTestData(Data, "ID", cs3RootFolder)
assert.NoError(t, err)
indexer := createCs3Indexer()
err = indexer.AddIndex(&User{}, "UserName", "ID", "users", "unique", nil, false)
assert.NoError(t, err)
u := &User{ID: "abcdefg-123", UserName: "mikey", Email: "mikey@example.com"}
_, err = indexer.Add(u)
assert.NoError(t, err)
_ = os.RemoveAll(dataDir)
}
func TestIndexer_CS3_AddWithNonUniqueIndex(t *testing.T) {
dataDir, err := WriteIndexTestData(Data, "ID", cs3RootFolder)
assert.NoError(t, err)
indexer := createCs3Indexer()
err = indexer.AddIndex(&User{}, "UserName", "ID", "users", "non_unique", nil, false)
assert.NoError(t, err)
u := &User{ID: "abcdefg-123", UserName: "mikey", Email: "mikey@example.com"}
_, err = indexer.Add(u)
assert.NoError(t, err)
_ = os.RemoveAll(dataDir)
}
func TestIndexer_Disk_FindByWithUniqueIndex(t *testing.T) {
dataDir, err := WriteIndexTestData(Data, "ID", "")
assert.NoError(t, err)
indexer := createDiskIndexer(dataDir)
err = indexer.AddIndex(&User{}, "UserName", "ID", "users", "unique", nil, false)
assert.NoError(t, err)
u := &User{ID: "abcdefg-123", UserName: "mikey", Email: "mikey@example.com"}
_, err = indexer.Add(u)
assert.NoError(t, err)
res, err := indexer.FindBy(User{}, "UserName", "mikey")
assert.NoError(t, err)
t.Log(res)
_ = os.RemoveAll(dataDir)
}
func TestIndexer_Disk_AddWithUniqueIndex(t *testing.T) {
dataDir, err := WriteIndexTestData(Data, "ID", "")
assert.NoError(t, err)
indexer := createDiskIndexer(dataDir)
err = indexer.AddIndex(&User{}, "UserName", "ID", "users", "unique", nil, false)
assert.NoError(t, err)
u := &User{ID: "abcdefg-123", UserName: "mikey", Email: "mikey@example.com"}
_, err = indexer.Add(u)
assert.NoError(t, err)
_ = os.RemoveAll(dataDir)
}
func TestIndexer_Disk_AddWithNonUniqueIndex(t *testing.T) {
dataDir, err := WriteIndexTestData(Data, "ID", "")
assert.NoError(t, err)
indexer := createDiskIndexer(dataDir)
err = indexer.AddIndex(&Pet{}, "Kind", "ID", "pets", "non_unique", nil, false)
assert.NoError(t, err)
pet1 := Pet{ID: "goefe-789", Kind: "Hog", Color: "Green", Name: "Dicky"}
pet2 := Pet{ID: "xadaf-189", Kind: "Hog", Color: "Green", Name: "Ricky"}
_, err = indexer.Add(pet1)
assert.NoError(t, err)
_, err = indexer.Add(pet2)
assert.NoError(t, err)
res, err := indexer.FindBy(Pet{}, "Kind", "Hog")
assert.NoError(t, err)
t.Log(res)
_ = os.RemoveAll(dataDir)
}
func TestIndexer_Disk_AddWithAutoincrementIndex(t *testing.T) {
dataDir, err := WriteIndexTestData(Data, "ID", "")
assert.NoError(t, err)
indexer := createDiskIndexer(dataDir)
err = indexer.AddIndex(&User{}, "UID", "ID", "users", "autoincrement", &option.Bound{Lower: 5}, false)
assert.NoError(t, err)
res1, err := indexer.Add(Data["users"][0])
assert.NoError(t, err)
assert.Equal(t, "UID", res1[0].Field)
assert.Equal(t, "5", path.Base(res1[0].Value))
res2, err := indexer.Add(Data["users"][1])
assert.NoError(t, err)
assert.Equal(t, "UID", res2[0].Field)
assert.Equal(t, "6", path.Base(res2[0].Value))
resFindBy, err := indexer.FindBy(User{}, "UID", "6")
assert.NoError(t, err)
assert.Equal(t, "hijklmn-456", resFindBy[0])
t.Log(resFindBy)
_ = os.RemoveAll(dataDir)
}
func TestIndexer_Disk_DeleteWithNonUniqueIndex(t *testing.T) {
dataDir, err := WriteIndexTestData(Data, "ID", "")
assert.NoError(t, err)
indexer := createDiskIndexer(dataDir)
err = indexer.AddIndex(&Pet{}, "Kind", "ID", "pets", "non_unique", nil, false)
assert.NoError(t, err)
pet1 := Pet{ID: "goefe-789", Kind: "Hog", Color: "Green", Name: "Dicky"}
pet2 := Pet{ID: "xadaf-189", Kind: "Hog", Color: "Green", Name: "Ricky"}
_, err = indexer.Add(pet1)
assert.NoError(t, err)
_, err = indexer.Add(pet2)
assert.NoError(t, err)
err = indexer.Delete(pet2)
assert.NoError(t, err)
_ = os.RemoveAll(dataDir)
}
func TestIndexer_Disk_SearchWithNonUniqueIndex(t *testing.T) {
dataDir, err := WriteIndexTestData(Data, "ID", "")
assert.NoError(t, err)
indexer := createDiskIndexer(dataDir)
err = indexer.AddIndex(&Pet{}, "Name", "ID", "pets", "non_unique", nil, false)
assert.NoError(t, err)
pet1 := Pet{ID: "goefe-789", Kind: "Hog", Color: "Green", Name: "Dicky"}
pet2 := Pet{ID: "xadaf-189", Kind: "Hog", Color: "Green", Name: "Ricky"}
_, err = indexer.Add(pet1)
assert.NoError(t, err)
_, err = indexer.Add(pet2)
assert.NoError(t, err)
res, err := indexer.FindByPartial(pet2, "Name", "*ky")
assert.NoError(t, err)
t.Log(res)
_ = os.RemoveAll(dataDir)
}
func TestIndexer_Disk_UpdateWithUniqueIndex(t *testing.T) {
dataDir, err := WriteIndexTestData(Data, "ID", "")
assert.NoError(t, err)
indexer := createDiskIndexer(dataDir)
err = indexer.AddIndex(&User{}, "UserName", "ID", "users", "unique", nil, false)
assert.NoError(t, err)
err = indexer.AddIndex(&User{}, "Email", "ID", "users", "unique", nil, false)
assert.NoError(t, err)
user1 := &User{ID: "abcdefg-123", UserName: "mikey", Email: "mikey@example.com"}
user2 := &User{ID: "hijklmn-456", UserName: "frank", Email: "frank@example.com"}
_, err = indexer.Add(user1)
assert.NoError(t, err)
_, err = indexer.Add(user2)
assert.NoError(t, err)
err = indexer.Update(user1, &User{
ID: "abcdefg-123",
UserName: "mikey-new",
Email: "mikey@example.com",
})
assert.NoError(t, err)
v, err1 := indexer.FindBy(&User{}, "UserName", "mikey-new")
assert.NoError(t, err1)
assert.Len(t, v, 1)
v, err2 := indexer.FindBy(&User{}, "UserName", "mikey")
assert.NoError(t, err2)
assert.Len(t, v, 0)
err1 = indexer.Update(&User{
ID: "abcdefg-123",
UserName: "mikey-new",
Email: "mikey@example.com",
}, &User{
ID: "abcdefg-123",
UserName: "mikey-newest",
Email: "mikey-new@example.com",
})
assert.NoError(t, err1)
fbUserName, err2 := indexer.FindBy(&User{}, "UserName", "mikey-newest")
assert.NoError(t, err2)
assert.Len(t, fbUserName, 1)
fbEmail, err3 := indexer.FindBy(&User{}, "Email", "mikey-new@example.com")
assert.NoError(t, err3)
assert.Len(t, fbEmail, 1)
_ = os.RemoveAll(dataDir)
}
func TestIndexer_Disk_UpdateWithNonUniqueIndex(t *testing.T) {
dataDir, err := WriteIndexTestData(Data, "ID", "")
assert.NoError(t, err)
indexer := createDiskIndexer(dataDir)
err = indexer.AddIndex(&Pet{}, "Name", "ID", "pets", "non_unique", nil, false)
assert.NoError(t, err)
pet1 := Pet{ID: "goefe-789", Kind: "Hog", Color: "Green", Name: "Dicky"}
pet2 := Pet{ID: "xadaf-189", Kind: "Hog", Color: "Green", Name: "Ricky"}
_, err = indexer.Add(pet1)
assert.NoError(t, err)
_, err = indexer.Add(pet2)
assert.NoError(t, err)
_ = os.RemoveAll(dataDir)
}
func createCs3Indexer() *Indexer {
return CreateIndexer(&config.Config{
Repo: config.Repo{
CS3: config.CS3{
ProviderAddr: "0.0.0.0:9215",
DataURL: "http://localhost:9216",
DataPrefix: "data",
JWTSecret: "Pive-Fumkiu4",
},
},
})
}
func createDiskIndexer(dataDir string) *Indexer {
return CreateIndexer(&config.Config{
Repo: config.Repo{
Disk: config.Disk{
Path: dataDir,
},
},
})
}

View File

@@ -0,0 +1,27 @@
package indexer
import "github.com/owncloud/ocis/accounts/pkg/indexer/index"
// typeMap stores the indexer layout at runtime.
type typeMap map[tName]typeMapping
type tName = string
type fieldName = string
type typeMapping struct {
PKFieldName string
IndicesByField map[fieldName][]index.Index
}
func (m typeMap) addIndex(typeName string, pkName string, idx index.Index) {
if val, ok := m[typeName]; ok {
val.IndicesByField[idx.IndexBy()] = append(val.IndicesByField[idx.IndexBy()], idx)
return
}
m[typeName] = typeMapping{
PKFieldName: pkName,
IndicesByField: map[string][]index.Index{
idx.IndexBy(): {idx},
},
}
}

View File

@@ -0,0 +1,132 @@
package option
// Option defines a single option function.
type Option func(o *Options)
// Bound represents a lower and upper bound range for an index.
// todo: if we would like to provide an upper bound then we would need to deal with ranges, in which case this is why the
// upper bound attribute is here.
type Bound struct {
Lower, Upper int64
}
// Options defines the available options for this package.
type Options struct {
CaseInsensitive bool
Bound *Bound
// Disk Options
TypeName string
IndexBy string
FilesDir string
IndexBaseDir string
DataDir string
EntityDirName string
Entity interface{}
// CS3 options
DataURL string
DataPrefix string
JWTSecret string
ProviderAddr string
ServiceUserUUID string
ServiceUserName string
}
// CaseInsensitive sets the CaseInsensitive field.
func CaseInsensitive(val bool) Option {
return func(o *Options) {
o.CaseInsensitive = val
}
}
// WithBounds sets the Bounds field.
func WithBounds(val *Bound) Option {
return func(o *Options) {
o.Bound = val
}
}
// WithEntity sets the Entity field.
func WithEntity(val interface{}) Option {
return func(o *Options) {
o.Entity = val
}
}
// WithJWTSecret sets the JWTSecret field.
func WithJWTSecret(val string) Option {
return func(o *Options) {
o.JWTSecret = val
}
}
// WithDataURL sets the DataURl field.
func WithDataURL(val string) Option {
return func(o *Options) {
o.DataURL = val
}
}
// WithDataPrefix sets the DataPrefix field.
func WithDataPrefix(val string) Option {
return func(o *Options) {
o.DataPrefix = val
}
}
// WithEntityDirName sets the EntityDirName field.
func WithEntityDirName(val string) Option {
return func(o *Options) {
o.EntityDirName = val
}
}
// WithDataDir sets the DataDir option.
func WithDataDir(val string) Option {
return func(o *Options) {
o.DataDir = val
}
}
// WithTypeName sets the TypeName option.
func WithTypeName(val string) Option {
return func(o *Options) {
o.TypeName = val
}
}
// WithIndexBy sets the option IndexBy.
func WithIndexBy(val string) Option {
return func(o *Options) {
o.IndexBy = val
}
}
// WithFilesDir sets the option FilesDir.
func WithFilesDir(val string) Option {
return func(o *Options) {
o.FilesDir = val
}
}
// WithProviderAddr sets the option ProviderAddr.
func WithProviderAddr(val string) Option {
return func(o *Options) {
o.ProviderAddr = val
}
}
// WithServiceUserUUID sets the option ServiceUserUUID.
func WithServiceUserUUID(val string) Option {
return func(o *Options) {
o.ServiceUserUUID = val
}
}
// WithServiceUserName sets the option ServiceUserName.
func WithServiceUserName(val string) Option {
return func(o *Options) {
o.ServiceUserName = val
}
}

View File

@@ -0,0 +1,41 @@
package indexer
import (
"errors"
"path"
"reflect"
"strconv"
"strings"
)
func getType(v interface{}) (reflect.Value, error) {
rv := reflect.ValueOf(v)
for rv.Kind() == reflect.Ptr || rv.Kind() == reflect.Interface {
rv = rv.Elem()
}
if !rv.IsValid() {
return reflect.Value{}, errors.New("failed to read value via reflection")
}
return rv, nil
}
func getTypeFQN(t interface{}) string {
typ, _ := getType(t)
typeName := path.Join(typ.Type().PkgPath(), typ.Type().Name())
typeName = strings.ReplaceAll(typeName, "/", ".")
return typeName
}
func valueOf(v interface{}, field string) string {
r := reflect.ValueOf(v)
f := reflect.Indirect(r).FieldByName(field)
if f.Kind() == reflect.String {
return f.String()
}
if f.IsZero() {
return ""
}
return strconv.Itoa(int(f.Int()))
}

View File

@@ -0,0 +1,53 @@
package indexer
import (
"testing"
)
func Test_getTypeFQN(t *testing.T) {
type someT struct{}
type args struct {
t interface{}
}
tests := []struct {
name string
args args
want string
}{
{name: "ByValue", args: args{&someT{}}, want: "github.com.owncloud.ocis.accounts.pkg.indexer.someT"},
{name: "ByRef", args: args{someT{}}, want: "github.com.owncloud.ocis.accounts.pkg.indexer.someT"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := getTypeFQN(tt.args.t); got != tt.want {
t.Errorf("getTypeFQN() = %v, want %v", got, tt.want)
}
})
}
}
func Test_valueOf(t *testing.T) {
type someT struct {
val string
}
type args struct {
v interface{}
field string
}
tests := []struct {
name string
args args
want string
}{
{name: "ByValue", args: args{v: someT{val: "hello"}, field: "val"}, want: "hello"},
{name: "ByRef", args: args{v: &someT{val: "hello"}, field: "val"}, want: "hello"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := valueOf(tt.args.v, tt.args.field); got != tt.want {
t.Errorf("valueOf() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -0,0 +1,15 @@
package registry
import (
"github.com/owncloud/ocis/accounts/pkg/indexer/index"
"github.com/owncloud/ocis/accounts/pkg/indexer/option"
)
// IndexConstructor is a constructor function for creating index.Index.
type IndexConstructor func(o ...option.Option) index.Index
// IndexConstructorRegistry undocumented.
var IndexConstructorRegistry = map[string]map[string]IndexConstructor{
"disk": {},
"cs3": {},
}

View File

@@ -0,0 +1,92 @@
package test
import (
"encoding/json"
"io/ioutil"
"os"
"path"
)
// User is a user.
type User struct {
ID, UserName, Email string
UID int
}
// Pet is a pet.
type Pet struct {
ID, Kind, Color, Name string
UID int
}
// Data mock data.
var Data = map[string][]interface{}{
"users": {
User{ID: "abcdefg-123", UserName: "mikey", Email: "mikey@example.com"},
User{ID: "hijklmn-456", UserName: "frank", Email: "frank@example.com"},
User{ID: "ewf4ofk-555", UserName: "jacky", Email: "jacky@example.com"},
User{ID: "rulan54-777", UserName: "jones", Email: "jones@example.com"},
},
"pets": {
Pet{ID: "rebef-123", Kind: "Dog", Color: "Brown", Name: "Waldo"},
Pet{ID: "wefwe-456", Kind: "Cat", Color: "White", Name: "Snowy"},
Pet{ID: "goefe-789", Kind: "Hog", Color: "Green", Name: "Dicky"},
Pet{ID: "xadaf-189", Kind: "Hog", Color: "Green", Name: "Ricky"},
},
}
// WriteIndexTestData writes mock data to disk.
func WriteIndexTestData(m map[string][]interface{}, privateKey, dir string) (string, error) {
rootDir, err := getRootDir(dir)
if err != nil {
return "", err
}
err = writeData(m, privateKey, rootDir)
if err != nil {
return "", err
}
return rootDir, nil
}
// getRootDir allows for some minimal behavior on destination on disk. Testing the cs3 api behavior locally means
// keeping track of where the cs3 data lives on disk, this function allows for multiplexing whether or not to use a
// temporary folder or an already defined one.
func getRootDir(dir string) (string, error) {
var rootDir string
var err error
if dir != "" {
rootDir = dir
} else {
rootDir, err = CreateTmpDir()
if err != nil {
return "", err
}
}
return rootDir, nil
}
// writeData writes test data to disk on rootDir location Marshaled as json.
func writeData(m map[string][]interface{}, privateKey string, rootDir string) error {
for dirName := range m {
fileTypePath := path.Join(rootDir, dirName)
if err := os.MkdirAll(fileTypePath, 0777); err != nil {
return err
}
for _, u := range m[dirName] {
data, err := json.Marshal(u)
if err != nil {
return err
}
pkVal := ValueOf(u, privateKey)
if err := ioutil.WriteFile(path.Join(fileTypePath, pkVal), data, 0777); err != nil {
return err
}
}
}
return nil
}

View File

@@ -0,0 +1,48 @@
package test
import (
"errors"
"io/ioutil"
"path"
"reflect"
"strings"
)
// CreateTmpDir creates a temporary dir for tests data.
func CreateTmpDir() (string, error) {
name, err := ioutil.TempDir("/var/tmp", "testfiles-")
if err != nil {
return "", err
}
return name, nil
}
// ValueOf gets the value of a type v on a given field <field>.
func ValueOf(v interface{}, field string) string {
r := reflect.ValueOf(v)
f := reflect.Indirect(r).FieldByName(field)
return f.String()
}
func getType(v interface{}) (reflect.Value, error) {
rv := reflect.ValueOf(v)
for rv.Kind() == reflect.Ptr || rv.Kind() == reflect.Interface {
rv = rv.Elem()
}
if !rv.IsValid() {
return reflect.Value{}, errors.New("failed to read value via reflection")
}
return rv, nil
}
// GetTypeFQN formats a valid name from a type <t>. This is a duplication of the already existing function in the
// indexer package, but since there is a circular dependency we chose to duplicate it.
func GetTypeFQN(t interface{}) string {
typ, _ := getType(t)
typeName := path.Join(typ.Type().PkgPath(), typ.Type().Name())
typeName = strings.ReplaceAll(typeName, "/", ".")
return typeName
}

View File

@@ -0,0 +1,23 @@
package test
import (
"context"
"flag"
"github.com/micro/cli/v2"
"github.com/owncloud/ocis/storage/pkg/command"
mcfg "github.com/owncloud/ocis/storage/pkg/config"
)
func init() {
go setupMetadataStorage()
}
func setupMetadataStorage() {
cfg := mcfg.New()
app := cli.App{
Name: "storage-metadata-for-tests",
Commands: []*cli.Command{command.StorageMetadata(cfg)},
}
_ = app.Command("storage-metadata").Run(cli.NewContext(&app, &flag.FlagSet{}, &cli.Context{Context: context.Background()}))
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
@@ -25,51 +26,88 @@ import (
var service = grpc.Service{}
const dataPath = "./accounts-store"
var dataPath = createTmpDir()
var newCreatedAccounts = []string{}
var newCreatedGroups = []string{}
var mockedRoleAssignment = map[string]string{}
var (
user1 = proto.Account{
Id: "f9149a32-2b8e-4f04-9e8d-937d81712b9a",
AccountEnabled: true,
IsResourceAccount: true,
CreationType: "",
DisplayName: "User One",
PreferredName: "user1",
OnPremisesSamAccountName: "user1",
UidNumber: 20009,
GidNumber: 30000,
Mail: "user1@example.com",
Identities: []*proto.Identities{nil},
PasswordProfile: &proto.PasswordProfile{Password: "heysdjfsdlk"},
MemberOf: []*proto.Group{
{Id: "509a9dcd-bb37-4f4f-a01a-19dca27d9cfa"}, // users
},
}
user2 = proto.Account{
Id: "e9149a32-2b8e-4f04-9e8d-937d81712b9a",
AccountEnabled: true,
IsResourceAccount: true,
CreationType: "",
DisplayName: "User Two",
PreferredName: "user2",
OnPremisesSamAccountName: "user2",
UidNumber: 20010,
GidNumber: 30000,
Mail: "user2@example.com",
Identities: []*proto.Identities{nil},
PasswordProfile: &proto.PasswordProfile{Password: "hello123"},
MemberOf: []*proto.Group{
{Id: "509a9dcd-bb37-4f4f-a01a-19dca27d9cfa"}, // users
},
}
)
func init() {
service = grpc.NewService(
grpc.Namespace("com.owncloud.api"),
grpc.Name("accounts"),
grpc.Address("localhost:9180"),
)
cfg := config.New()
cfg.Server.AccountsDataPath = dataPath
cfg.Repo.Disk.Path = dataPath
var hdlr *svc.Service
var err error
if hdlr, err = svc.New(svc.Logger(command.NewLogger(cfg)), svc.Config(cfg), svc.RoleService(buildRoleServiceMock())); err != nil {
log.Fatalf("Could not create new service")
}
err = proto.RegisterAccountsServiceHandler(service.Server(), hdlr)
if err != nil {
log.Fatal("could not register the Accounts handler")
}
err = proto.RegisterGroupsServiceHandler(service.Server(), hdlr)
if err != nil {
log.Fatal("could not register the Groups handler")
}
err = service.Server().Start()
if err != nil {
log.Fatal(err)
}
}
func getAccount(user string) *proto.Account {
switch user {
case "user1":
return &proto.Account{
Id: "f9149a32-2b8e-4f04-9e8d-937d81712b9a",
AccountEnabled: true,
IsResourceAccount: true,
CreationType: "",
DisplayName: "User One",
PreferredName: "user1",
OnPremisesSamAccountName: "user1",
UidNumber: 20009,
GidNumber: 30000,
Mail: "user1@example.com",
Identities: []*proto.Identities{nil},
PasswordProfile: &proto.PasswordProfile{Password: "heysdjfsdlk"},
MemberOf: []*proto.Group{
{Id: "509a9dcd-bb37-4f4f-a01a-19dca27d9cfa"}, // users
},
}
return &user1
case "user2":
return &proto.Account{
Id: "e9149a32-2b8e-4f04-9e8d-937d81712b9a",
AccountEnabled: true,
IsResourceAccount: true,
CreationType: "",
DisplayName: "User Two",
PreferredName: "user2",
OnPremisesSamAccountName: "user2",
UidNumber: 20009,
GidNumber: 30000,
Mail: "user2@example.com",
Identities: []*proto.Identities{nil},
PasswordProfile: &proto.PasswordProfile{Password: "hello123"},
MemberOf: []*proto.Group{
{Id: "509a9dcd-bb37-4f4f-a01a-19dca27d9cfa"}, // users
},
}
return &user2
default:
return &proto.Account{
Id: fmt.Sprintf("new-id-%s", user),
@@ -154,38 +192,6 @@ func getTestGroups(group string) *proto.Group {
return nil
}
func init() {
service = grpc.NewService(
grpc.Namespace("com.owncloud.api"),
grpc.Name("accounts"),
grpc.Address("localhost:9180"),
)
cfg := config.New()
cfg.Server.AccountsDataPath = dataPath
cfg.Repo.Disk.Path = dataPath
var hdlr *svc.Service
var err error
if hdlr, err = svc.New(svc.Logger(command.NewLogger(cfg)), svc.Config(cfg), svc.RoleService(buildRoleServiceMock())); err != nil {
log.Fatalf("Could not create new service")
}
err = proto.RegisterAccountsServiceHandler(service.Server(), hdlr)
if err != nil {
log.Fatal("could not register the Accounts handler")
}
err = proto.RegisterGroupsServiceHandler(service.Server(), hdlr)
if err != nil {
log.Fatal("could not register the Groups handler")
}
err = service.Server().Start()
if err != nil {
log.Fatal(err)
}
}
func buildRoleServiceMock() settings.RoleService {
return settings.MockRoleService{
AssignRoleToUserFunc: func(ctx context.Context, req *settings.AssignRoleToUserRequest, opts ...client.CallOption) (res *settings.AssignRoleToUserResponse, err error) {
@@ -208,8 +214,7 @@ func cleanUp(t *testing.T) {
if _, err := os.Stat(path); os.IsNotExist(err) {
continue
}
_, err := deleteAccount(t, id)
checkError(t, err)
_, _ = deleteAccount(t, id)
}
datastore = filepath.Join(dataPath, "groups")
@@ -219,8 +224,7 @@ func cleanUp(t *testing.T) {
if _, err := os.Stat(path); os.IsNotExist(err) {
continue
}
_, err := deleteGroup(t, id)
checkError(t, err)
_, _ = deleteGroup(t, id)
}
newCreatedAccounts = []string{}
@@ -309,12 +313,6 @@ func assertGroupHasMember(t *testing.T, grp *proto.Group, memberId string) {
t.Fatalf("Member with id %s expected to be in group '%s', but not found", memberId, grp.DisplayName)
}
func checkError(t *testing.T, err error) {
if err != nil {
t.Fatalf("Expected Error to be nil but got %s", err)
}
}
func createAccount(t *testing.T, user string) (*proto.Account, error) {
client := service.Client()
cl := proto.NewAccountsService("com.owncloud.api.accounts", client)
@@ -368,7 +366,7 @@ func listGroups(t *testing.T) *proto.ListGroupsResponse {
cl := proto.NewGroupsService("com.owncloud.api.accounts", client)
response, err := cl.ListGroups(context.Background(), request)
checkError(t, err)
assert.NoError(t, err)
return response
}
@@ -390,18 +388,27 @@ func deleteGroup(t *testing.T, id string) (*empty.Empty, error) {
return res, err
}
// createTmpDir creates a temporary dir for tests data.
func createTmpDir() string {
name, err := ioutil.TempDir("/var/tmp", "ocis-accounts-store-")
if err != nil {
panic(err)
}
return name
}
// https://github.com/owncloud/ocis/accounts/issues/61
func TestCreateAccount(t *testing.T) {
resp, err := createAccount(t, "user1")
checkError(t, err)
assert.NoError(t, err)
assertUserExists(t, getAccount("user1"))
assert.IsType(t, &proto.Account{}, resp)
// Account is not returned in response
// assertAccountsSame(t, getAccount("user1"), resp)
resp, err = createAccount(t, "user2")
checkError(t, err)
assert.NoError(t, err)
assertUserExists(t, getAccount("user2"))
assert.IsType(t, &proto.Account{}, resp)
// Account is not returned in response
@@ -410,24 +417,25 @@ func TestCreateAccount(t *testing.T) {
cleanUp(t)
}
// https://github.com/owncloud/ocis/accounts/issues/62
// https://github.com/owncloud/ocis-accounts/issues/62
func TestCreateExistingUser(t *testing.T) {
createAccount(t, "user1")
_, err := createAccount(t, "user1")
var err error
_, err = createAccount(t, "user1")
assert.NoError(t, err)
// Should give error but it does not
checkError(t, err)
_, err = createAccount(t, "user1")
assert.Error(t, err)
assertUserExists(t, getAccount("user1"))
cleanUp(t)
}
// All tests fail after running this
// https://github.com/owncloud/ocis/accounts/issues/62
// https://github.com/owncloud/ocis/accounts-issues/62
func TestCreateAccountInvalidUserName(t *testing.T) {
resp, err := listAccounts(t)
checkError(t, err)
assert.NoError(t, err)
numAccounts := len(resp.GetAccounts())
testData := []string{
@@ -448,7 +456,7 @@ func TestCreateAccountInvalidUserName(t *testing.T) {
// resp should have the same number of accounts
resp, err = listAccounts(t)
checkError(t, err)
assert.NoError(t, err)
assert.Equal(t, numAccounts, len(resp.GetAccounts()))
@@ -456,57 +464,58 @@ func TestCreateAccountInvalidUserName(t *testing.T) {
}
func TestUpdateAccount(t *testing.T) {
_, _ = createAccount(t, "user1")
tests := []struct {
name string
userAccount *proto.Account
name string
userAccount *proto.Account
expectedErrOnUpdate error
}{
{
"Update user (demonstration of updatable fields)",
&proto.Account{
DisplayName: "Alice Hansen",
PreferredName: "Wonderful Alice",
OnPremisesDistinguishedName: "Alice",
UidNumber: 20010,
GidNumber: 30001,
Mail: "alice@example.com",
DisplayName: "Alice Hansen",
PreferredName: "Wonderful-Alice",
OnPremisesSamAccountName: "Alice",
UidNumber: 20010,
GidNumber: 30001,
Mail: "alice@example.com",
},
nil,
},
{
"Update user with unicode data",
&proto.Account{
DisplayName: "एलिस हेन्सेन",
PreferredName: "अद्भुत एलिस",
OnPremisesDistinguishedName: "एलिस",
UidNumber: 20010,
GidNumber: 30001,
Mail: "एलिस@उदाहरण.com",
DisplayName: "एलिस हेन्सेन",
PreferredName: "अद्भुत-एलिस",
OnPremisesSamAccountName: "एलिस",
UidNumber: 20010,
GidNumber: 30001,
Mail: "एलिस@उदाहरण.com",
},
merrors.BadRequest(".", "preferred_name 'अद्भुत-एलिस' must be at least the local part of an email"),
},
{
"Update user with empty data values",
&proto.Account{
DisplayName: "",
PreferredName: "",
OnPremisesDistinguishedName: "",
UidNumber: 0,
GidNumber: 0,
Mail: "",
DisplayName: "",
PreferredName: "",
OnPremisesSamAccountName: "",
UidNumber: 0,
GidNumber: 0,
Mail: "",
},
merrors.BadRequest(".", "preferred_name '' must be at least the local part of an email"),
},
{
"Update user with strange data",
&proto.Account{
DisplayName: "12345",
PreferredName: "12345",
OnPremisesDistinguishedName: "54321",
UidNumber: 1000,
GidNumber: 1000,
// No email validation
// https://github.com/owncloud/ocis/accounts/issues/77
Mail: "1.2@3.c_@",
DisplayName: "12345",
PreferredName: "a12345",
OnPremisesSamAccountName: "a54321",
UidNumber: 1000,
GidNumber: 1000,
Mail: "1.2@3.c_@",
},
merrors.BadRequest(".", "mail '1.2@3.c_@' must be a valid email"),
},
}
@@ -524,20 +533,25 @@ func TestUpdateAccount(t *testing.T) {
}
t.Run(tt.name, func(t *testing.T) {
tt.userAccount.Id = "f9149a32-2b8e-4f04-9e8d-937d81712b9a"
acc, err := createAccount(t, "user1")
assert.NoError(t, err)
tt.userAccount.Id = acc.Id
tt.userAccount.AccountEnabled = false
tt.userAccount.IsResourceAccount = false
resp, err := updateAccount(t, tt.userAccount, updateMask)
checkError(t, err)
assert.IsType(t, &proto.Account{}, resp)
assertAccountsSame(t, tt.userAccount, resp)
assertUserExists(t, tt.userAccount)
if tt.expectedErrOnUpdate != nil {
assert.Error(t, err)
assert.Equal(t, tt.expectedErrOnUpdate, err)
} else {
assert.NoError(t, err)
assert.IsType(t, &proto.Account{}, resp)
assertAccountsSame(t, tt.userAccount, resp)
assertUserExists(t, tt.userAccount)
}
cleanUp(t)
})
}
cleanUp(t)
}
func TestUpdateNonUpdatableFieldsInAccount(t *testing.T) {
@@ -554,6 +568,7 @@ func TestUpdateNonUpdatableFieldsInAccount(t *testing.T) {
"CreationType",
},
&proto.Account{
Id: user1.Id,
CreationType: "Type Test",
},
},
@@ -563,6 +578,7 @@ func TestUpdateNonUpdatableFieldsInAccount(t *testing.T) {
"PasswordProfile",
},
&proto.Account{
Id: user1.Id,
PasswordProfile: &proto.PasswordProfile{Password: "new password"},
},
},
@@ -572,6 +588,7 @@ func TestUpdateNonUpdatableFieldsInAccount(t *testing.T) {
"MemberOf",
},
&proto.Account{
Id: user1.Id,
MemberOf: []*proto.Group{
{Id: "509a9dcd-bb37-4f4f-a01a-19dca27d9cfa"},
},
@@ -580,7 +597,6 @@ func TestUpdateNonUpdatableFieldsInAccount(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.userAccount.Id = "f9149a32-2b8e-4f04-9e8d-937d81712b9a"
res, err := updateAccount(t, tt.userAccount, tt.updateMask)
if err == nil {
t.Fatalf("Expected error while updating non updatable field, but found none.")
@@ -602,6 +618,8 @@ func TestUpdateNonUpdatableFieldsInAccount(t *testing.T) {
}
})
}
cleanUp(t)
}
func TestListAccounts(t *testing.T) {
@@ -609,7 +627,7 @@ func TestListAccounts(t *testing.T) {
createAccount(t, "user2")
resp, err := listAccounts(t)
checkError(t, err)
assert.NoError(t, err)
assert.IsType(t, &proto.ListAccountsResponse{}, resp)
assert.Equal(t, 8, len(resp.Accounts))
@@ -622,31 +640,128 @@ func TestListAccounts(t *testing.T) {
func TestListWithoutUserCreation(t *testing.T) {
resp, err := listAccounts(t)
checkError(t, err)
assert.NoError(t, err)
// Only 5 default users
assert.Equal(t, 6, len(resp.Accounts))
cleanUp(t)
}
func TestListAccountsWithFilterQuery(t *testing.T) {
scenarios := []struct {
name string
query string
expectedIDs []string
}{
// FIXME: disabled test scenarios need to be supported when implementing OData support
// OData implementation tracked in https://github.com/owncloud/ocis/issues/716
//{
// name: "ListAccounts with exact match on preferred_name",
// query: "preferred_name eq 'user1'",
// expectedIDs: []string{user1.Id},
//},
{
name: "ListAccounts with exact match on on_premises_sam_account_name",
query: "on_premises_sam_account_name eq 'user1'",
expectedIDs: []string{user1.Id},
},
{
name: "ListAccounts with exact match on mail",
query: "mail eq 'user1@example.com'",
expectedIDs: []string{user1.Id},
},
//{
// name: "ListAccounts with exact match on id",
// query: "id eq 'f9149a32-2b8e-4f04-9e8d-937d81712b9a'",
// expectedIDs: []string{user1.Id},
//},
//{
// name: "ListAccounts without match on preferred_name",
// query: "preferred_name eq 'wololo'",
// expectedIDs: []string{},
//},
//{
// name: "ListAccounts with exact match on preferred_name AND mail",
// query: "preferred_name eq 'user1' and mail eq 'user1@example.com'",
// expectedIDs: []string{user1.Id},
//},
//{
// name: "ListAccounts without match on preferred_name AND mail",
// query: "preferred_name eq 'user1' and mail eq 'wololo@example.com'",
// expectedIDs: []string{},
//},
//{
// name: "ListAccounts with exact match on preferred_name OR mail, preferred_name exists, mail exists",
// query: "preferred_name eq 'user1' or mail eq 'user1@example.com'",
// expectedIDs: []string{user1.Id},
//},
//{
// name: "ListAccounts with exact match on preferred_name OR mail, preferred_name exists, mail does not exist",
// query: "preferred_name eq 'user1' or mail eq 'wololo@example.com'",
// expectedIDs: []string{user1.Id},
//},
//{
// name: "ListAccounts with exact match on preferred_name OR mail, preferred_name does not exists, mail exists",
// query: "preferred_name eq 'wololo' or mail eq 'user1@example.com'",
// expectedIDs: []string{user1.Id},
//},
//{
// name: "ListAccounts without match on preferred_name OR mail, preferred_name and mail do not exist",
// query: "preferred_name eq 'wololo' or mail eq 'wololo@example.com'",
// expectedIDs: []string{},
//},
//{
// name: "ListAccounts with multiple matches on preferred_name",
// query: "startswith(preferred_name,'user*')",
// expectedIDs: []string{user1.Id, user2.Id},
//},
//{
// name: "ListAccounts with multiple matches on on_premises_sam_account_name",
// query: "startswith(on_premises_sam_account_name,'user*')",
// expectedIDs: []string{user1.Id, user2.Id},
//},
}
cl := proto.NewAccountsService("com.owncloud.api.accounts", service.Client())
for _, scenario := range scenarios {
t.Run(scenario.name, func(t *testing.T) {
_, err := createAccount(t, "user1")
assert.NoError(t, err)
_, err = createAccount(t, "user2")
assert.NoError(t, err)
req := &proto.ListAccountsRequest{Query: scenario.query}
res, err := cl.ListAccounts(context.Background(), req)
assert.NoError(t, err)
ids := make([]string, 0)
for _, acc := range res.Accounts {
ids = append(ids, acc.Id)
}
assert.Equal(t, scenario.expectedIDs, ids)
cleanUp(t)
})
}
}
func TestGetAccount(t *testing.T) {
createAccount(t, "user1")
req := &proto.GetAccountRequest{Id: getAccount("user1").Id}
client := service.Client()
cl := proto.NewAccountsService("com.owncloud.api.accounts", client)
cl := proto.NewAccountsService("com.owncloud.api.accounts", service.Client())
resp, err := cl.GetAccount(context.Background(), req)
checkError(t, err)
assert.NoError(t, err)
assert.IsType(t, &proto.Account{}, resp)
assertAccountsSame(t, getAccount("user1"), resp)
cleanUp(t)
}
//TODO: This segfaults! WIP
func TestDeleteAccount(t *testing.T) {
createAccount(t, "user1")
createAccount(t, "user2")
@@ -657,7 +772,7 @@ func TestDeleteAccount(t *testing.T) {
cl := proto.NewAccountsService("com.owncloud.api.accounts", client)
resp, err := cl.DeleteAccount(context.Background(), req)
checkError(t, err)
assert.NoError(t, err)
assert.IsType(t, resp, &empty.Empty{})
// Check the account doesn't exists anymore
@@ -675,9 +790,9 @@ func TestListGroups(t *testing.T) {
cl := proto.NewGroupsService("com.owncloud.api.accounts", client)
resp, err := cl.ListGroups(context.Background(), req)
checkError(t, err)
assert.NoError(t, err)
assert.IsType(t, &proto.ListGroupsResponse{}, resp)
assert.Equal(t, len(resp.Groups), 9)
assert.Equal(t, 9, len(resp.Groups))
groups := []string{
"sysusers",
@@ -718,7 +833,7 @@ func TestGetGroups(t *testing.T) {
req := &proto.GetGroupRequest{Id: group.Id}
resp, err := cl.GetGroup(context.Background(), req)
checkError(t, err)
assert.NoError(t, err)
assert.IsType(t, &proto.Group{}, resp)
assertGroupsSame(t, group, resp)
}
@@ -733,7 +848,7 @@ func TestCreateGroup(t *testing.T) {
}}
res, err := createGroup(t, group)
checkError(t, err)
assert.NoError(t, err)
assert.IsType(t, &proto.Group{}, res)
@@ -772,12 +887,12 @@ func TestDeleteGroup(t *testing.T) {
req := &proto.DeleteGroupRequest{Id: grp1.Id}
res, err := cl.DeleteGroup(context.Background(), req)
assert.IsType(t, res, &empty.Empty{})
checkError(t, err)
assert.NoError(t, err)
req = &proto.DeleteGroupRequest{Id: grp2.Id}
res, err = cl.DeleteGroup(context.Background(), req)
assert.IsType(t, res, &empty.Empty{})
checkError(t, err)
assert.NoError(t, err)
groupsResponse := listGroups(t)
assertResponseNotContainsGroup(t, groupsResponse, grp1)
@@ -870,7 +985,7 @@ func TestAddMember(t *testing.T) {
req := &proto.AddMemberRequest{GroupId: grp1.Id, AccountId: account.Id}
res, err := cl.AddMember(context.Background(), req)
checkError(t, err)
assert.NoError(t, err)
assert.IsType(t, &proto.Group{}, res)
@@ -904,7 +1019,7 @@ func TestAddMemberAlreadyInGroup(t *testing.T) {
res, err := cl.AddMember(context.Background(), req)
// Should Give Error
checkError(t, err)
assert.NoError(t, err)
assert.IsType(t, &proto.Group{}, res)
//assert.Equal(t, proto.Group{}, *res)
//assertGroupsSame(t, updatedGroup, res)
@@ -975,7 +1090,7 @@ func TestRemoveMember(t *testing.T) {
req := &proto.RemoveMemberRequest{GroupId: grp1.Id, AccountId: account.Id}
res, err := cl.RemoveMember(context.Background(), req)
checkError(t, err)
assert.NoError(t, err)
assert.IsType(t, &proto.Group{}, res)
//assert.Equal(t, proto.Group{}, *res)
@@ -1034,7 +1149,7 @@ func TestRemoveMemberNotInGroup(t *testing.T) {
res, err := cl.RemoveMember(context.Background(), req)
// Should give an error
checkError(t, err)
assert.NoError(t, err)
assert.IsType(t, &proto.Group{}, res)
//assert.Error(t, err)
@@ -1071,7 +1186,7 @@ func TestListMembers(t *testing.T) {
req := &proto.ListMembersRequest{Id: expectedGroup.Id}
res, err := cl.ListMembers(context.Background(), req)
checkError(t, err)
assert.NoError(t, err)
assert.Equal(t, len(res.Members), len(expectedGroup.Members))
@@ -1104,7 +1219,7 @@ func TestListMembersEmptyGroup(t *testing.T) {
res, err := cl.ListMembers(context.Background(), req)
checkError(t, err)
assert.NoError(t, err)
assert.Empty(t, res.Members)
cleanUp(t)
@@ -1120,12 +1235,12 @@ func TestAccountUpdateMask(t *testing.T) {
Account: &proto.Account{
Id: user1.Id,
DisplayName: "ShouldBeUpdated",
PreferredName: "ShouldStaySame",
PreferredName: "ShouldStaySame And Is Invalid Anyway",
}}
cl := proto.NewAccountsService("com.owncloud.api.accounts", client)
res, err := cl.UpdateAccount(context.Background(), req)
checkError(t, err)
assert.NoError(t, err)
assert.Equal(t, "ShouldBeUpdated", res.DisplayName)
assert.Equal(t, user1.PreferredName, res.PreferredName)

View File

@@ -1,13 +0,0 @@
package proto
// BleveAccount wraps the generated Account and adds a bleve type that is used to distinguish documents in the index
type BleveAccount struct {
Account
BleveType string `json:"bleve_type"`
}
// BleveGroup wraps the generated Group and adds a bleve type that is used to distinguish documents in the index
type BleveGroup struct {
Group
BleveType string `json:"bleve_type"`
}

View File

@@ -1,128 +0,0 @@
package provider
import (
"errors"
"fmt"
"strconv"
"strings"
"github.com/CiscoM31/godata"
"github.com/blevesearch/bleve"
"github.com/blevesearch/bleve/search/query"
)
func init() {
// add (ap)prox filter
godata.GlobalFilterTokenizer = FilterTokenizer()
godata.GlobalFilterParser.DefineOperator("ap", 2, godata.OpAssociationLeft, 4, false)
}
// BuildBleveQuery converts a GoDataFilterQuery into a bleve query
func BuildBleveQuery(r *godata.GoDataFilterQuery) (query.Query, error) {
return recursiveBuildQuery(r.Tree)
}
// Builds the filter recursively using DFS
func recursiveBuildQuery(n *godata.ParseNode) (query.Query, error) {
if n.Token.Type == godata.FilterTokenFunc {
switch n.Token.Value {
case "startswith":
if len(n.Children) != 2 {
return nil, errors.New("startswith match must have two children")
}
if n.Children[0].Token.Type != godata.FilterTokenLiteral {
return nil, errors.New("startswith expected a literal as the first param")
}
if n.Children[1].Token.Type != godata.FilterTokenString {
return nil, errors.New("startswith expected a string as the second param")
} // remove enclosing ' of string tokens (looks like 'some ol'' string')
value := n.Children[1].Token.Value[1 : len(n.Children[1].Token.Value)-1]
// unescape '' as '
unescaped := strings.ReplaceAll(value, "''", "'")
q := bleve.NewPrefixQuery(unescaped)
q.SetField(n.Children[0].Token.Value)
return q, nil
// TODO contains as regex?
// TODO endswith as regex?
default:
return nil, godata.NotImplementedError(n.Token.Value + " is not implemented.")
}
}
if n.Token.Type == godata.FilterTokenLogical {
switch n.Token.Value {
case "eq":
if len(n.Children) != 2 {
return nil, errors.New("equality match must have two children")
}
if n.Children[0].Token.Type != godata.FilterTokenLiteral {
return nil, errors.New("equality expected a literal on the lhs")
}
if n.Children[1].Token.Type == godata.FilterTokenString {
// for escape rules see http://docs.oasis-open.org/odata/odata/v4.01/cs01/part2-url-conventions/odata-v4.01-cs01-part2-url-conventions.html#sec_URLComponents
// remove enclosing ' of string tokens (looks like 'some ol'' string')
value := n.Children[1].Token.Value[1 : len(n.Children[1].Token.Value)-1]
// unescape '' as '
unescaped := strings.ReplaceAll(value, "''", "'")
// use a match query, so the field mapping, e.g. lowercase is applied to the value
// remember we defined the field mapping for `preferred_name` to be lowercase
// a term query like `preferred_name eq 'Artur'` would use `Artur` to search in the index and come up empty
// a match query will apply the field mapping (lowercasing `Artur` to `artur`) before doing the search
// TODO there is a mismatch between the LDAP and odata filters:
// - LDAP matching rules depend on the attribute: see https://ldapwiki.com/wiki/MatchingRule
// - odata has functions like `startswith`, `contains`, `tolower`, `toupper`, `matchesPattern` andy more: see http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-protocol.html#sec_BuiltinQueryFunctions
// - ocis-glauth should do the mapping between LDAP and odata filter
q := bleve.NewMatchQuery(unescaped)
q.SetField(n.Children[0].Token.Value)
return q, nil
} else if n.Children[1].Token.Type == godata.FilterTokenInteger {
v, err := strconv.ParseFloat(n.Children[1].Token.Value, 64)
if err != nil {
return nil, err
}
incl := true
q := bleve.NewNumericRangeInclusiveQuery(&v, &v, &incl, &incl)
q.SetField(n.Children[0].Token.Value)
return q, nil
}
return nil, fmt.Errorf("equality expected a string or int on the rhs, got %d", n.Children[1].Token.Type)
case "and":
q := query.NewConjunctionQuery([]query.Query{})
for _, child := range n.Children {
subQuery, err := recursiveBuildQuery(child)
if err != nil {
return nil, err
}
if subQuery != nil {
q.AddQuery(subQuery)
}
}
return q, nil
case "or":
q := query.NewDisjunctionQuery([]query.Query{})
for _, child := range n.Children {
subQuery, err := recursiveBuildQuery(child)
if err != nil {
return nil, err
}
if subQuery != nil {
q.AddQuery(subQuery)
}
}
return q, nil
case "Not":
if len(n.Children) != 1 {
return nil, errors.New("not filter must have only one child")
}
subQuery, err := recursiveBuildQuery(n.Children[0])
if err != nil {
return nil, err
}
q := query.NewBooleanQuery(nil, nil, []query.Query{subQuery})
return q, nil
default:
return nil, godata.NotImplementedError(n.Token.Value + " is not implemented.")
}
}
return nil, godata.NotImplementedError(n.Token.Value + " is not implemented.")
}

View File

@@ -1,38 +0,0 @@
package provider
import "github.com/CiscoM31/godata"
// FilterTokenizer creates a tokenizer capable of tokenizing filter statements
// TODO disable tokens we don't handle anyway
func FilterTokenizer() *godata.Tokenizer {
t := godata.Tokenizer{}
t.Add("^[0-9]{4,4}-[0-9]{2,2}-[0-9]{2,2}T[0-9]{2,2}:[0-9]{2,2}(:[0-9]{2,2}(.[0-9]+)?)?(Z|[+-][0-9]{2,2}:[0-9]{2,2})", godata.FilterTokenDateTime)
t.Add("^-?[0-9]{4,4}-[0-9]{2,2}-[0-9]{2,2}", godata.FilterTokenDate)
t.Add("^[0-9]{2,2}:[0-9]{2,2}(:[0-9]{2,2}(.[0-9]+)?)?", godata.FilterTokenTime)
t.Add("^\\(", godata.FilterTokenOpenParen)
t.Add("^\\)", godata.FilterTokenCloseParen)
t.Add("^/", godata.FilterTokenNav)
t.Add("^:", godata.FilterTokenColon)
t.Add("^,", godata.FilterTokenComma)
t.Add("^(geo.distance|geo.intersects|geo.length)", godata.FilterTokenFunc)
t.Add("^(substringof|substring|length|indexof)", godata.FilterTokenFunc)
// only change from the global tokenizer is the added ap
t.Add("^(eq|ne|gt|ge|lt|le|and|or|not|has|in|ap)", godata.FilterTokenLogical)
t.Add("^(add|sub|mul|divby|div|mod)", godata.FilterTokenOp)
t.Add("^(contains|endswith|startswith|tolower|toupper|"+
"trim|concat|year|month|day|hour|minute|second|fractionalseconds|date|"+
"time|totaloffsetminutes|now|maxdatetime|mindatetime|totalseconds|round|"+
"floor|ceiling|isof|cast)", godata.FilterTokenFunc)
t.Add("^(any|all)", godata.FilterTokenLambda)
t.Add("^null", godata.FilterTokenNull)
t.Add("^\\$it", godata.FilterTokenIt)
t.Add("^\\$root", godata.FilterTokenRoot)
t.Add("^-?[0-9]+\\.[0-9]+", godata.FilterTokenFloat)
t.Add("^-?[0-9]+", godata.FilterTokenInteger)
t.Add("^'(''|[^'])*'", godata.FilterTokenString)
t.Add("^(true|false)", godata.FilterTokenBoolean)
t.Add("^@*[a-zA-Z][a-zA-Z0-9_.]*", godata.FilterTokenLiteral) // The optional '@' character is used to identify parameter aliases
t.Ignore("^ ", godata.FilterTokenWhitespace)
return &t
}

View File

@@ -3,19 +3,19 @@ package service
import (
"context"
"fmt"
"path/filepath"
"path"
"regexp"
"strconv"
"sync"
"time"
"github.com/CiscoM31/godata"
"github.com/blevesearch/bleve"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/gofrs/uuid"
"github.com/golang/protobuf/ptypes/empty"
fieldmask_utils "github.com/mennanov/fieldmask-utils"
merrors "github.com/micro/go-micro/v2/errors"
"github.com/owncloud/ocis/accounts/pkg/proto/v0"
"github.com/owncloud/ocis/accounts/pkg/provider"
"github.com/owncloud/ocis/accounts/pkg/storage"
"github.com/owncloud/ocis/ocis-pkg/roles"
settings "github.com/owncloud/ocis/settings/pkg/proto/v0"
@@ -35,22 +35,6 @@ import (
// accLock mutually exclude readers from writers on account files
var accLock sync.Mutex
func (s Service) indexAccount(id string) error {
a := &proto.BleveAccount{
BleveType: "account",
}
if err := s.repo.LoadAccount(context.Background(), id, &a.Account); err != nil {
s.log.Error().Err(err).Str("account", id).Msg("could not load account")
return err
}
s.log.Debug().Interface("account", a).Msg("found account")
if err := s.index.Index(a.Id, a); err != nil {
s.log.Error().Err(err).Interface("account", a).Msg("could not index account")
return err
}
return nil
}
// an auth request is currently hardcoded and has to match this regex
// login eq \"teddy\" and password eq \"F&1!b90t111!\"
var authQuery = regexp.MustCompile(`^login eq '(.*)' and password eq '(.*)'$`) // TODO how is ' escaped in the password?
@@ -74,17 +58,6 @@ func (s Service) expandMemberOf(a *proto.Account) {
a.MemberOf = expanded
}
func (s Service) passwordIsValid(hash string, pwd string) (ok bool) {
defer func() {
if r := recover(); r != nil {
s.log.Error().Err(fmt.Errorf("%s", r)).Str("hash", hash).Msg("password lib panicked")
}
}()
c := crypt.NewFromHash(hash)
return c.Verify(hash, []byte(pwd)) == nil
}
func (s Service) hasAccountManagementPermissions(ctx context.Context) bool {
// get roles from context
roleIDs, ok := roles.ReadRoleIDsFromContext(ctx)
@@ -104,15 +77,12 @@ func (s Service) hasAccountManagementPermissions(ctx context.Context) bool {
// serviceUserToIndex temporarily adds a service user to the index, which is supposed to be removed before the lock on the handler function is released
func (s Service) serviceUserToIndex() (teardownServiceUser func()) {
if s.Config.ServiceUser.Username != "" && s.Config.ServiceUser.UUID != "" {
err := s.index.Index(s.Config.ServiceUser.UUID, &proto.BleveAccount{
BleveType: "account",
Account: s.getInMemoryServiceUser(),
})
_, err := s.index.Add(s.getInMemoryServiceUser())
if err != nil {
s.log.Logger.Err(err).Msg("service user was configured but failed to be added to the index")
} else {
return func() {
_ = s.index.Delete(s.Config.ServiceUser.UUID)
_ = s.index.Delete(s.getInMemoryServiceUser())
}
}
}
@@ -140,83 +110,56 @@ func (s Service) ListAccounts(ctx context.Context, in *proto.ListAccountsRequest
accLock.Lock()
defer accLock.Unlock()
var password string
teardownServiceUser := s.serviceUserToIndex()
defer teardownServiceUser()
// check if this looks like an auth request
match := authQuery.FindStringSubmatch(in.Query)
if len(match) == 3 {
in.Query = fmt.Sprintf("on_premises_sam_account_name eq '%s'", match[1]) // todo fetch email? make query configurable
password = match[2]
if password == "" {
return merrors.Unauthorized(s.id, "password must not be empty")
}
}
// only search for accounts
tq := bleve.NewTermQuery("account")
tq.SetField("bleve_type")
query := bleve.NewConjunctionQuery(tq)
if in.Query != "" {
// parse the query like an odata filter
var q *godata.GoDataFilterQuery
if q, err = godata.ParseFilterString(in.Query); err != nil {
s.log.Error().Err(err).Msg("could not parse query")
return merrors.InternalServerError(s.id, "could not parse query: %v", err.Error())
match, authRequest := getAuthQueryMatch(in.Query)
if authRequest {
password := match[2]
if len(password) == 0 {
return merrors.Unauthorized(s.id, "account not found or invalid credentials")
}
// convert to bleve query
bq, err := provider.BuildBleveQuery(q)
if err != nil {
s.log.Error().Err(err).Msg("could not build bleve query")
return merrors.InternalServerError(s.id, "could not build bleve query: %v", err.Error())
ids, err := s.index.FindBy(&proto.Account{}, "OnPremisesSamAccountName", match[1])
if err != nil || len(ids) > 1 {
return merrors.Unauthorized(s.id, "account not found or invalid credentials")
}
if len(ids) == 0 {
ids, err = s.index.FindBy(&proto.Account{}, "Mail", match[1])
if err != nil || len(ids) != 1 {
return merrors.Unauthorized(s.id, "account not found or invalid credentials")
}
}
query.AddQuery(bq)
}
s.log.Debug().Interface("query", query).Msg("using query")
searchRequest := bleve.NewSearchRequest(query)
var searchResult *bleve.SearchResult
searchResult, err = s.index.Search(searchRequest)
if err != nil {
s.log.Error().Err(err).Msg("could not execute bleve search")
return merrors.InternalServerError(s.id, "could not execute bleve search: %v", err.Error())
}
s.log.Debug().Interface("result", searchResult).Msg("result")
out.Accounts = make([]*proto.Account, 0)
for _, hit := range searchResult.Hits {
a := &proto.Account{}
if hit.ID == s.Config.ServiceUser.UUID {
err = s.repo.LoadAccount(ctx, ids[0], a)
if err != nil || a.PasswordProfile == nil || len(a.PasswordProfile.Password) == 0 {
return merrors.Unauthorized(s.id, "account not found or invalid credentials")
}
if !isPasswordValid(s.log, a.PasswordProfile.Password, password) {
return merrors.Unauthorized(s.id, "account not found or invalid credentials")
}
a.PasswordProfile.Password = ""
out.Accounts = []*proto.Account{a}
return nil
}
searchResults, err := s.findAccountsByQuery(ctx, in.Query)
out.Accounts = make([]*proto.Account, 0, len(searchResults))
for _, hit := range searchResults {
a := &proto.Account{}
if hit == s.Config.ServiceUser.UUID {
acc := s.getInMemoryServiceUser()
a = &acc
} else if err = s.repo.LoadAccount(ctx, hit.ID, a); err != nil {
s.log.Error().Err(err).Str("account", hit.ID).Msg("could not load account, skipping")
} else if err = s.repo.LoadAccount(ctx, hit, a); err != nil {
s.log.Error().Err(err).Str("account", hit).Msg("could not load account, skipping")
continue
}
var currentHash string
if a.PasswordProfile != nil {
currentHash = a.PasswordProfile.Password
}
s.debugLogAccount(a).Msg("found account")
if password != "" {
if a.PasswordProfile == nil {
s.debugLogAccount(a).Msg("no password profile")
return merrors.Unauthorized(s.id, "invalid password")
}
if !s.passwordIsValid(currentHash, password) {
return merrors.Unauthorized(s.id, "invalid password")
}
}
// TODO add groups if requested
// if in.FieldMask ...
s.expandMemberOf(a)
@@ -232,6 +175,90 @@ func (s Service) ListAccounts(ctx context.Context, in *proto.ListAccountsRequest
return
}
func (s Service) findAccountsByQuery(ctx context.Context, query string) ([]string, error) {
var searchResults []string
var err error
if query == "" {
return s.index.FindByPartial(&proto.Account{}, "Mail", "*")
}
// TODO: more explicit queries have to be on top
var onPremOrMailQuery = regexp.MustCompile(`^on_premises_sam_account_name eq '(.*)' or mail eq '(.*)'$`)
match := onPremOrMailQuery.FindStringSubmatch(query)
if len(match) == 3 {
resSam, err := s.index.FindByPartial(&proto.Account{}, "OnPremisesSamAccountName", match[1]+"*")
if err != nil {
return nil, err
}
resMail, err := s.index.FindByPartial(&proto.Account{}, "Mail", match[2]+"*")
if err != nil {
return nil, err
}
searchResults = append(resSam, resMail...)
return unique(searchResults), nil
}
// startswith(on_premises_sam_account_name,'mar') or startswith(display_name,'mar') or startswith(mail,'mar')
var searchQuery = regexp.MustCompile(`^startswith\(on_premises_sam_account_name,'(.*)'\) or startswith\(display_name,'(.*)'\) or startswith\(mail,'(.*)'\)$`)
match = searchQuery.FindStringSubmatch(query)
if len(match) == 4 {
resSam, err := s.index.FindByPartial(&proto.Account{}, "OnPremisesSamAccountName", match[1]+"*")
if err != nil {
return nil, err
}
resDisp, err := s.index.FindByPartial(&proto.Account{}, "DisplayName", match[2]+"*")
if err != nil {
return nil, err
}
resMail, err := s.index.FindByPartial(&proto.Account{}, "Mail", match[3]+"*")
if err != nil {
return nil, err
}
searchResults = append(resSam, append(resDisp, resMail...)...)
return unique(searchResults), nil
}
// id eq 'marie' or on_premises_sam_account_name eq 'marie'
// id eq 'f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c' or on_premises_sam_account_name eq 'f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c'
var idOrQuery = regexp.MustCompile(`^id eq '(.*)' or on_premises_sam_account_name eq '(.*)'$`)
match = idOrQuery.FindStringSubmatch(query)
if len(match) == 3 {
qID, qSam := match[1], match[2]
tmp := &proto.Account{}
err = s.repo.LoadAccount(ctx, qID, tmp)
if err != nil {
return nil, err
}
searchResults, err = s.index.FindBy(&proto.Account{}, "OnPremisesSamAccountName", qSam)
if err != nil {
return nil, err
}
if tmp.Id != "" {
searchResults = append(searchResults, tmp.Id)
}
return unique(searchResults), nil
}
var onPremQuery = regexp.MustCompile(`^on_premises_sam_account_name eq '(.*)'$`) // TODO how is ' escaped in the password?
match = onPremQuery.FindStringSubmatch(query)
if len(match) == 2 {
return s.index.FindBy(&proto.Account{}, "OnPremisesSamAccountName", match[1])
}
var mailQuery = regexp.MustCompile(`^mail eq '(.*)'$`)
match = mailQuery.FindStringSubmatch(query)
if len(match) == 2 {
return s.index.FindBy(&proto.Account{}, "Mail", match[1])
}
return nil, merrors.BadRequest(s.id, "unsupported query %s", query)
}
// GetAccount implements the AccountsServiceHandler interface
func (s Service) GetAccount(ctx context.Context, in *proto.GetAccountRequest, out *proto.Account) (err error) {
if !s.hasAccountManagementPermissions(ctx) {
@@ -277,35 +304,43 @@ func (s Service) CreateAccount(ctx context.Context, in *proto.CreateAccountReque
accLock.Lock()
defer accLock.Unlock()
var id string
var acc = in.Account
if acc == nil {
return merrors.BadRequest(s.id, "account missing")
}
if acc.Id == "" {
acc.Id = uuid.Must(uuid.NewV4()).String()
}
if !s.isValidUsername(acc.PreferredName) {
return merrors.BadRequest(s.id, "preferred_name '%s' must be at least the local part of an email", acc.PreferredName)
}
if !s.isValidEmail(acc.Mail) {
return merrors.BadRequest(s.id, "mail '%s' must be a valid email", acc.Mail)
if in.Account == nil {
return merrors.InternalServerError(s.id, "invalid account: empty")
}
if id, err = cleanupID(acc.Id); err != nil {
out.XXX_Merge(in.Account)
if out.Id == "" {
out.Id = uuid.Must(uuid.NewV4()).String()
}
if err = validateAccount(s.id, out); err != nil {
return err
}
if id, err = cleanupID(out.Id); err != nil {
return merrors.InternalServerError(s.id, "could not clean up account id: %v", err.Error())
}
if acc.PasswordProfile != nil {
if acc.PasswordProfile.Password != "" {
exists, err := s.accountExists(ctx, out.PreferredName, out.Mail, out.Id)
if err != nil {
return merrors.InternalServerError(s.id, "could not check if account exists: %v", err.Error())
}
if exists {
return merrors.BadRequest(s.id, "account already exists")
}
if out.PasswordProfile != nil {
if out.PasswordProfile.Password != "" {
// encrypt password
c := crypt.New(crypt.SHA512)
if acc.PasswordProfile.Password, err = c.Generate([]byte(acc.PasswordProfile.Password), nil); err != nil {
if out.PasswordProfile.Password, err = c.Generate([]byte(out.PasswordProfile.Password), nil); err != nil {
s.log.Error().Err(err).Str("id", id).Msg("could not hash password")
return merrors.InternalServerError(s.id, "could not hash password: %v", err.Error())
}
}
if err := passwordPoliciesValid(acc.PasswordProfile.PasswordPolicies); err != nil {
if err := passwordPoliciesValid(out.PasswordProfile.PasswordPolicies); err != nil {
return merrors.BadRequest(s.id, "%s", err)
}
}
@@ -314,27 +349,54 @@ func (s Service) CreateAccount(ctx context.Context, in *proto.CreateAccountReque
// TODO groups should be ignored during create, use groups.AddMember? return error?
// write and index account - note: don't do anything else in between!
if err = s.repo.WriteAccount(ctx, acc); err != nil {
if err = s.repo.WriteAccount(ctx, out); err != nil {
s.log.Error().Err(err).Str("id", id).Msg("could not persist new account")
s.debugLogAccount(acc).Msg("could not persist new account")
s.debugLogAccount(out).Msg("could not persist new account")
return merrors.InternalServerError(s.id, "could not persist new account: %v", err.Error())
}
if err = s.indexAccount(acc.Id); err != nil {
return merrors.InternalServerError(s.id, "could not index new account: %v", err.Error())
}
s.log.Debug().Interface("account", acc).Msg("account after indexing")
indexResults, err := s.index.Add(out)
if err != nil {
s.rollbackCreateAccount(ctx, out)
return merrors.BadRequest(s.id, "Account already exists %v", err.Error())
if acc.PasswordProfile != nil {
acc.PasswordProfile.Password = ""
}
s.log.Debug().Interface("account", out).Msg("account after indexing")
for _, r := range indexResults {
if r.Field == "UidNumber" {
id, err := strconv.Atoi(path.Base(r.Value))
if err != nil {
s.rollbackCreateAccount(ctx, out)
return err
}
out.UidNumber = int64(id)
break
}
}
{
out.Id = acc.Id
out.Mail = acc.Mail
out.PreferredName = acc.PreferredName
out.AccountEnabled = acc.AccountEnabled
out.DisplayName = acc.DisplayName
out.OnPremisesSamAccountName = acc.OnPremisesSamAccountName
if out.GidNumber == 0 {
out.GidNumber = userDefaultGID
}
r := proto.ListGroupsResponse{}
err = s.ListGroups(ctx, &proto.ListGroupsRequest{}, &r)
if err != nil {
// rollback account creation
return err
}
for _, group := range r.Groups {
if group.GidNumber == out.GidNumber {
out.MemberOf = append(out.MemberOf, group)
}
}
//acc.MemberOf = append(acc.MemberOf, &group)
if err := s.repo.WriteAccount(context.Background(), out); err != nil {
return err
}
if out.PasswordProfile != nil {
out.PasswordProfile.Password = ""
}
// TODO: assign user role to all new users for now, as create Account request does not have any role field
@@ -342,7 +404,7 @@ func (s Service) CreateAccount(ctx context.Context, in *proto.CreateAccountReque
return merrors.InternalServerError(s.id, "could not assign role to account: roleService not configured")
}
if _, err = s.RoleService.AssignRoleToUser(ctx, &settings.AssignRoleToUserRequest{
AccountUuid: acc.Id,
AccountUuid: out.Id,
RoleId: settings_svc.BundleUUIDRoleUser,
}); err != nil {
return merrors.InternalServerError(s.id, "could not assign role to account: %v", err.Error())
@@ -351,6 +413,18 @@ func (s Service) CreateAccount(ctx context.Context, in *proto.CreateAccountReque
return
}
// rollbackCreateAccount tries to rollback changes made by `CreateAccount` if parts of it failed.
func (s Service) rollbackCreateAccount(ctx context.Context, acc *proto.Account) {
err := s.index.Delete(acc)
if err != nil {
s.log.Err(err).Msg("failed to rollback account from indices")
}
err = s.repo.DeleteAccount(ctx, acc.Id)
if err != nil {
s.log.Err(err).Msg("failed to rollback account from repo")
}
}
// UpdateAccount implements the AccountsServiceHandler interface
// read only fields are ignored
// TODO how can we unset specific values? using the update mask
@@ -373,8 +447,6 @@ func (s Service) UpdateAccount(ctx context.Context, in *proto.UpdateAccountReque
return merrors.InternalServerError(s.id, "could not clean up account id: %v", err.Error())
}
path := filepath.Join(s.Config.Server.AccountsDataPath, "accounts", id)
if err = s.repo.LoadAccount(ctx, id, out); err != nil {
if storage.IsNotFoundErr(err) {
return merrors.NotFound(s.id, "account not found: %v", err.Error())
@@ -396,6 +468,24 @@ func (s Service) UpdateAccount(ctx context.Context, in *proto.UpdateAccountReque
return merrors.BadRequest(s.id, "%s", err)
}
if _, exists := validMask.Filter("PreferredName"); exists {
if err = validateAccountPreferredName(s.id, in.Account); err != nil {
return err
}
}
if _, exists := validMask.Filter("OnPremisesSamAccountName"); exists {
if err = validateAccountOnPremisesSamAccountName(s.id, in.Account); err != nil {
return err
}
}
if _, exists := validMask.Filter("Mail"); exists {
if in.Account.Mail != "" {
if err = validateAccountEmail(s.id, in.Account); err != nil {
return err
}
}
}
if err := fieldmask_utils.StructToStruct(validMask, in.Account, out); err != nil {
return merrors.InternalServerError(s.id, "%s", err)
}
@@ -434,13 +524,20 @@ func (s Service) UpdateAccount(ctx context.Context, in *proto.UpdateAccountReque
out.ExternalUserStateChangeDateTime = tsnow
}
// We need to reload the old account state to be able to compute the update
old := &proto.Account{}
if err = s.repo.LoadAccount(ctx, id, old); err != nil {
s.log.Error().Err(err).Str("id", out.Id).Msg("could not load old account representation during update, maybe the account got deleted meanwhile?")
return merrors.InternalServerError(s.id, "could not load current account for update: %v", err.Error())
}
if err = s.repo.WriteAccount(ctx, out); err != nil {
s.log.Error().Err(err).Str("id", out.Id).Msg("could not persist updated account")
return merrors.InternalServerError(s.id, "could not persist updated account: %v", err.Error())
}
if err = s.indexAccount(id); err != nil {
s.log.Error().Err(err).Str("id", id).Str("path", path).Msg("could not index new account")
if err = s.index.Update(old, out); err != nil {
s.log.Error().Err(err).Str("id", id).Msg("could not index new account")
return merrors.InternalServerError(s.id, "could not index updated account: %v", err.Error())
}
@@ -514,7 +611,7 @@ func (s Service) DeleteAccount(ctx context.Context, in *proto.DeleteAccountReque
return merrors.InternalServerError(s.id, "could not remove account: %v", err.Error())
}
if err = s.index.Delete(id); err != nil {
if err = s.index.Delete(a); err != nil {
s.log.Error().Err(err).Str("id", id).Str("accountId", id).Msg("could not remove account from index")
return merrors.InternalServerError(s.id, "could not remove account from index: %v", err.Error())
}
@@ -523,12 +620,46 @@ func (s Service) DeleteAccount(ctx context.Context, in *proto.DeleteAccountReque
return
}
func validateAccount(serviceID string, a *proto.Account) error {
if err := validateAccountPreferredName(serviceID, a); err != nil {
return err
}
if err := validateAccountOnPremisesSamAccountName(serviceID, a); err != nil {
return err
}
if err := validateAccountEmail(serviceID, a); err != nil {
return err
}
return nil
}
func validateAccountPreferredName(serviceID string, a *proto.Account) error {
if !isValidUsername(a.PreferredName) {
return merrors.BadRequest(serviceID, "preferred_name '%s' must be at least the local part of an email", a.PreferredName)
}
return nil
}
func validateAccountOnPremisesSamAccountName(serviceID string, a *proto.Account) error {
if !isValidUsername(a.OnPremisesSamAccountName) {
return merrors.BadRequest(serviceID, "on_premises_sam_account_name '%s' must be at least the local part of an email", a.OnPremisesSamAccountName)
}
return nil
}
func validateAccountEmail(serviceID string, a *proto.Account) error {
if !isValidEmail(a.Mail) {
return merrors.BadRequest(serviceID, "mail '%s' must be a valid email", a.Mail)
}
return nil
}
// We want to allow email addresses as usernames so they show up when using them in ACLs on storages that allow intergration with our glauth LDAP service
// so we are adding a few restrictions from https://stackoverflow.com/questions/6949667/what-are-the-real-rules-for-linux-usernames-on-centos-6-and-rhel-6
// names should not start with numbers
var usernameRegex = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]*(@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)*$")
func (s Service) isValidUsername(e string) bool {
func isValidUsername(e string) bool {
if len(e) < 1 && len(e) > 254 {
return false
}
@@ -538,7 +669,7 @@ func (s Service) isValidUsername(e string) bool {
// regex from https://www.w3.org/TR/2016/REC-html51-20161101/sec-forms.html#valid-e-mail-address
var emailRegex = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
func (s Service) isValidEmail(e string) bool {
func isValidEmail(e string) bool {
if len(e) < 3 && len(e) > 254 {
return false
}
@@ -613,3 +744,68 @@ func (s Service) debugLogAccount(a *proto.Account) *zerolog.Event {
"DeletedDateTime": a.DeletedDateTime,
})
}
func unique(strSlice []string) []string {
keys := make(map[string]bool)
list := []string{}
for _, entry := range strSlice {
if _, value := keys[entry]; !value {
keys[entry] = true
list = append(list, entry)
}
}
return list
}
func (s Service) accountExists(ctx context.Context, username, mail, id string) (exists bool, err error) {
var ids []string
ids, err = s.index.FindBy(&proto.Account{}, "preferred_name", username)
if err != nil {
return false, err
}
if len(ids) > 0 {
return true, nil
}
ids, err = s.index.FindBy(&proto.Account{}, "on_premises_sam_account_name", username)
if err != nil {
return false, err
}
if len(ids) > 0 {
return true, nil
}
ids, err = s.index.FindBy(&proto.Account{}, "mail", mail)
if err != nil {
return false, err
}
if len(ids) > 0 {
return true, nil
}
a := &proto.Account{}
err = s.repo.LoadAccount(ctx, id, a)
if err == nil {
return true, nil
}
if !storage.IsNotFoundErr(err) {
return true, err
}
return false, nil
}
func getAuthQueryMatch(query string) (match []string, authRequest bool) {
match = authQuery.FindStringSubmatch(query)
return match, len(match) == 3
}
func isPasswordValid(logger log.Logger, hash string, pwd string) (ok bool) {
defer func() {
if r := recover(); r != nil {
logger.Error().Err(fmt.Errorf("%s", r)).Str("hash", hash).Msg("password lib panicked")
}
}()
c := crypt.NewFromHash(hash)
return c.Verify(hash, []byte(pwd)) == nil
}

View File

@@ -2,34 +2,18 @@ package service
import (
"context"
"github.com/owncloud/ocis/accounts/pkg/storage"
"path"
"path/filepath"
"strconv"
"github.com/owncloud/ocis/accounts/pkg/storage"
"github.com/CiscoM31/godata"
"github.com/blevesearch/bleve"
"github.com/gofrs/uuid"
"github.com/golang/protobuf/ptypes/empty"
merrors "github.com/micro/go-micro/v2/errors"
"github.com/owncloud/ocis/accounts/pkg/proto/v0"
"github.com/owncloud/ocis/accounts/pkg/provider"
)
func (s Service) indexGroup(id string) error {
g := &proto.BleveGroup{
BleveType: "group",
}
if err := s.repo.LoadGroup(context.Background(), id, &g.Group); err != nil {
s.log.Error().Err(err).Str("group", id).Msg("could not load group")
return err
}
s.log.Debug().Interface("group", g).Msg("found group")
if err := s.index.Index(g.Id, g); err != nil {
s.log.Error().Err(err).Interface("group", g).Msg("could not index group")
return err
}
return nil
}
func (s Service) expandMembers(g *proto.Group) {
if g == nil {
return
@@ -41,7 +25,7 @@ func (s Service) expandMembers(g *proto.Group) {
if err := s.repo.LoadAccount(context.Background(), g.Members[i].Id, a); err == nil {
expanded = append(expanded, a)
} else {
// log errors but continue execution for now
// log errors but con/var/tmp/ocis-accounts-store-408341811tinue execution for now
s.log.Error().Err(err).Str("id", g.Members[i].Id).Msg("could not load account")
}
}
@@ -67,49 +51,25 @@ func (s Service) deflateMembers(g *proto.Group) {
// ListGroups implements the GroupsServiceHandler interface
func (s Service) ListGroups(c context.Context, in *proto.ListGroupsRequest, out *proto.ListGroupsResponse) (err error) {
// only search for groups
tq := bleve.NewTermQuery("group")
tq.SetField("bleve_type")
query := bleve.NewConjunctionQuery(tq)
if in.Query != "" {
// parse the query like an odata filter
var q *godata.GoDataFilterQuery
if q, err = godata.ParseFilterString(in.Query); err != nil {
s.log.Error().Err(err).Msg("could not parse query")
return merrors.InternalServerError(s.id, "could not parse query: %v", err.Error())
}
// convert to bleve query
bq, err := provider.BuildBleveQuery(q)
if err != nil {
s.log.Error().Err(err).Msg("could not build bleve query")
return merrors.InternalServerError(s.id, "could not build bleve query: %v", err.Error())
}
query.AddQuery(bq)
}
s.log.Debug().Interface("query", query).Msg("using query")
searchRequest := bleve.NewSearchRequest(query)
var searchResult *bleve.SearchResult
searchResult, err = s.index.Search(searchRequest)
if err != nil {
s.log.Error().Err(err).Msg("could not execute bleve search")
return merrors.InternalServerError(s.id, "could not execute bleve search: %v", err.Error())
}
s.log.Debug().Interface("result", searchResult).Msg("result")
var searchResults []string
out.Groups = make([]*proto.Group, 0)
if in.Query == "" {
searchResults, _ = s.index.FindByPartial(&proto.Group{}, "DisplayName", "*")
}
for _, hit := range searchResult.Hits {
/*
var startsWithIDQuery = regexp.MustCompile(`^startswith\(id,'(.*)'\)$`)
match := startsWithIDQuery.FindStringSubmatch(in.Query)
if len(match) == 2 {
searchResults = []string{match[1]}
}
*/
for _, hit := range searchResults {
g := &proto.Group{}
if err = s.repo.LoadGroup(c, hit.ID, g); err != nil {
s.log.Error().Err(err).Str("group", hit.ID).Msg("could not load group, skipping")
if err = s.repo.LoadGroup(c, hit, g); err != nil {
s.log.Error().Err(err).Str("group", hit).Msg("could not load group, skipping")
continue
}
s.log.Debug().Interface("group", g).Msg("found group")
@@ -150,33 +110,59 @@ func (s Service) GetGroup(c context.Context, in *proto.GetGroupRequest, out *pro
// CreateGroup implements the GroupsServiceHandler interface
func (s Service) CreateGroup(c context.Context, in *proto.CreateGroupRequest, out *proto.Group) (err error) {
var id string
if in.Group == nil {
return merrors.BadRequest(s.id, "account missing")
return merrors.InternalServerError(s.id, "invalid group: empty")
}
if in.Group.Id == "" {
in.Group.Id = uuid.Must(uuid.NewV4()).String()
out.XXX_Merge(in.Group)
if out.Id == "" {
out.Id = uuid.Must(uuid.NewV4()).String()
}
if id, err = cleanupID(in.Group.Id); err != nil {
if _, err = cleanupID(out.Id); err != nil {
return merrors.InternalServerError(s.id, "could not clean up account id: %v", err.Error())
}
// extract member id
s.deflateMembers(in.Group)
s.deflateMembers(out)
if err = s.repo.WriteGroup(c, in.Group); err != nil {
s.log.Error().Err(err).Interface("group", in.Group).Msg("could not persist new group")
if err = s.repo.WriteGroup(c, out); err != nil {
s.log.Error().Err(err).Interface("group", out).Msg("could not persist new group")
return merrors.InternalServerError(s.id, "could not persist new group: %v", err.Error())
}
if err = s.indexGroup(id); err != nil {
indexResults, err := s.index.Add(out)
if err != nil {
s.rollbackCreateGroup(c, out)
return merrors.InternalServerError(s.id, "could not index new group: %v", err.Error())
}
for _, r := range indexResults {
if r.Field == "GidNumber" {
gid, err := strconv.Atoi(path.Base(r.Value))
if err != nil {
s.rollbackCreateGroup(c, out)
return err
}
out.GidNumber = int64(gid)
return s.repo.WriteGroup(context.Background(), out)
}
}
return
}
// rollbackCreateGroup tries to rollback changes made by `CreateGroup` if parts of it failed.
func (s Service) rollbackCreateGroup(ctx context.Context, group *proto.Group) {
err := s.index.Delete(group)
if err != nil {
s.log.Err(err).Msg("failed to rollback group from indices")
}
err = s.repo.DeleteGroup(ctx, group.Id)
if err != nil {
s.log.Err(err).Msg("failed to rollback group from repo")
}
}
// UpdateGroup implements the GroupsServiceHandler interface
func (s Service) UpdateGroup(c context.Context, in *proto.UpdateGroupRequest, out *proto.Group) (err error) {
return merrors.InternalServerError(s.id, "not implemented")
@@ -217,7 +203,7 @@ func (s Service) DeleteGroup(c context.Context, in *proto.DeleteGroupRequest, ou
return merrors.InternalServerError(s.id, "could not load group: %v", err.Error())
}
if err = s.index.Delete(id); err != nil {
if err = s.index.Delete(g); err != nil {
s.log.Error().Err(err).Str("id", id).Str("path", path).Msg("could not remove group from index")
return merrors.InternalServerError(s.id, "could not remove group from index: %v", err.Error())
}

View File

@@ -3,21 +3,20 @@ package service
import (
"context"
"errors"
"github.com/owncloud/ocis/accounts/pkg/storage"
"os"
"path"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/blevesearch/bleve"
"github.com/blevesearch/bleve/analysis/analyzer/custom"
"github.com/blevesearch/bleve/analysis/analyzer/keyword"
"github.com/blevesearch/bleve/analysis/analyzer/simple"
"github.com/blevesearch/bleve/analysis/analyzer/standard"
"github.com/blevesearch/bleve/analysis/token/lowercase"
"github.com/blevesearch/bleve/analysis/tokenizer/unicode"
"github.com/owncloud/ocis/accounts/pkg/indexer/option"
"github.com/owncloud/ocis/accounts/pkg/indexer"
"github.com/owncloud/ocis/accounts/pkg/storage"
mclient "github.com/micro/go-micro/v2/client"
"github.com/owncloud/ocis/accounts/pkg/config"
idxerrs "github.com/owncloud/ocis/accounts/pkg/indexer/errors"
"github.com/owncloud/ocis/accounts/pkg/proto/v0"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/ocis-pkg/roles"
@@ -25,6 +24,9 @@ import (
settings_svc "github.com/owncloud/ocis/settings/pkg/service/v0"
)
// userDefaultGID is the default integer representing the "users" group.
const userDefaultGID = 30000
// New returns a new instance of Service
func New(opts ...Option) (s *Service, err error) {
options := newOptions(opts...)
@@ -72,92 +74,50 @@ func New(opts ...Option) (s *Service, err error) {
return
}
func (s Service) buildIndex() (index bleve.Index, err error) {
indexDir := filepath.Join(s.Config.Server.AccountsDataPath, "index.bleve")
if index, err = bleve.Open(indexDir); err != nil {
if err != bleve.ErrorIndexPathDoesNotExist {
s.log.Error().Err(err).Msg("failed to read index")
return
}
func (s Service) buildIndex() (*indexer.Indexer, error) {
idx := indexer.CreateIndexer(s.Config)
indexMapping := bleve.NewIndexMapping()
// keep all symbols in terms to allow exact maching, eg. emails
indexMapping.DefaultAnalyzer = keyword.Name
// TODO don't bother to store fields as we will load the account from disk
// Reusable mapping for text
standardTextFieldMapping := bleve.NewTextFieldMapping()
standardTextFieldMapping.Analyzer = standard.Name
standardTextFieldMapping.Store = false
// Reusable mapping for text, uses english stop word removal
simpleTextFieldMapping := bleve.NewTextFieldMapping()
simpleTextFieldMapping.Analyzer = simple.Name
simpleTextFieldMapping.Store = false
// Reusable mapping for keyword text
keywordFieldMapping := bleve.NewTextFieldMapping()
keywordFieldMapping.Analyzer = keyword.Name
keywordFieldMapping.Store = false
// Reusable mapping for lowercase text
err = indexMapping.AddCustomAnalyzer("lowercase",
map[string]interface{}{
"type": custom.Name,
"tokenizer": unicode.Name,
"token_filters": []string{
lowercase.Name,
},
})
if err != nil {
return
}
lowercaseTextFieldMapping := bleve.NewTextFieldMapping()
lowercaseTextFieldMapping.Analyzer = "lowercase"
lowercaseTextFieldMapping.Store = true
// accounts
accountMapping := bleve.NewDocumentMapping()
indexMapping.AddDocumentMapping("account", accountMapping)
// Text
accountMapping.AddFieldMappingsAt("display_name", standardTextFieldMapping)
accountMapping.AddFieldMappingsAt("description", standardTextFieldMapping)
// Lowercase
accountMapping.AddFieldMappingsAt("on_premises_sam_account_name", lowercaseTextFieldMapping)
accountMapping.AddFieldMappingsAt("preferred_name", lowercaseTextFieldMapping)
// Keywords
accountMapping.AddFieldMappingsAt("mail", keywordFieldMapping)
// groups
groupMapping := bleve.NewDocumentMapping()
indexMapping.AddDocumentMapping("group", groupMapping)
// Text
groupMapping.AddFieldMappingsAt("display_name", standardTextFieldMapping)
groupMapping.AddFieldMappingsAt("description", standardTextFieldMapping)
// Lowercase
groupMapping.AddFieldMappingsAt("on_premises_sam_account_name", lowercaseTextFieldMapping)
// Tell blevesearch how to determine the type of the structs that are indexed.
// The referenced field needs to match the struct field exactly and it must be public.
// See pkg/proto/v0/bleve.go how we wrap the generated Account and Group to add a
// BleveType property which is indexed as `bleve_type` so we can also distinguish the
// documents in the index by querying for that property.
indexMapping.TypeField = "BleveType"
// for now recreate index on every start
if err = os.RemoveAll(indexDir); err != nil {
return
}
if index, err = bleve.New(indexDir, indexMapping); err != nil {
return nil, err
}
// Accounts
if err := idx.AddIndex(&proto.Account{}, "DisplayName", "Id", "accounts", "non_unique", nil, true); err != nil {
return nil, err
}
return
if err := idx.AddIndex(&proto.Account{}, "Mail", "Id", "accounts", "unique", nil, true); err != nil {
return nil, err
}
if err := idx.AddIndex(&proto.Account{}, "OnPremisesSamAccountName", "Id", "accounts", "unique", nil, true); err != nil {
return nil, err
}
if err := idx.AddIndex(&proto.Account{}, "PreferredName", "Id", "accounts", "unique", nil, true); err != nil {
return nil, err
}
if err := idx.AddIndex(&proto.Account{}, "UidNumber", "Id", "accounts", "autoincrement", &option.Bound{
Lower: s.Config.Index.UID.Lower,
Upper: s.Config.Index.UID.Upper,
}, false); err != nil {
return nil, err
}
// Groups
if err := idx.AddIndex(&proto.Group{}, "OnPremisesSamAccountName", "Id", "groups", "unique", nil, true); err != nil {
return nil, err
}
if err := idx.AddIndex(&proto.Group{}, "DisplayName", "Id", "groups", "non_unique", nil, true); err != nil {
return nil, err
}
if err := idx.AddIndex(&proto.Group{}, "GidNumber", "Id", "groups", "autoincrement", &option.Bound{
Lower: s.Config.Index.GID.Lower,
Upper: s.Config.Index.GID.Upper,
}, false); err != nil {
return nil, err
}
return idx, nil
}
func (s Service) createDefaultAccounts() (err error) {
@@ -275,8 +235,35 @@ func (s Service) createDefaultAccounts() (err error) {
return err
}
if err := s.indexAccount(accounts[i].Id); err != nil {
return err
results, err := s.index.Add(&accounts[i])
if err != nil {
if idxerrs.IsAlreadyExistsErr(err) {
continue
} else {
return err
}
}
// TODO: can be removed again as soon as we respect the predefined UIDs and GIDs from the account. Then no autoincrement is happening, therefore we don't need to update accounts.
changed := false
for _, r := range results {
if r.Field == "UidNumber" || r.Field == "GidNumber" {
id, err := strconv.ParseInt(path.Base(r.Value), 10, 0)
if err != nil {
return err
}
if r.Field == "UidNumber" {
accounts[i].UidNumber = id
} else {
accounts[i].GidNumber = id
}
changed = true
}
}
if changed {
if err := s.repo.WriteAccount(context.Background(), &accounts[i]); err != nil {
return err
}
}
}
@@ -337,8 +324,28 @@ func (s Service) createDefaultGroups() (err error) {
return err
}
if err := s.indexGroup(groups[i].Id); err != nil {
return err
results, err := s.index.Add(&groups[i])
if err != nil {
if idxerrs.IsAlreadyExistsErr(err) {
continue
} else {
return err
}
}
// TODO: can be removed again as soon as we respect the predefined GIDs from the group. Then no autoincrement is happening, therefore we don't need to update groups.
for _, r := range results {
if r.Field == "GidNumber" {
gid, err := strconv.ParseInt(path.Base(r.Value), 10, 0)
if err != nil {
return err
}
groups[i].GidNumber = gid
if err := s.repo.WriteGroup(context.Background(), &groups[i]); err != nil {
return err
}
break
}
}
}
return nil
@@ -374,7 +381,7 @@ type Service struct {
id string
log log.Logger
Config *config.Config
index bleve.Index
index *indexer.Indexer
RoleService settings.RoleService
RoleManager *roles.Manager
repo storage.Repo

View File

@@ -73,8 +73,14 @@ func (r CS3Repo) WriteAccount(ctx context.Context, a *proto.Account) (err error)
return err
}
_, err = r.dataProvider.put(r.accountURL(a.Id), bytes.NewReader(by), t)
return err
resp, err := r.dataProvider.put(r.accountURL(a.Id), bytes.NewReader(by), t)
if err != nil {
return err
}
if err = resp.Body.Close(); err != nil {
return err
}
return nil
}
// LoadAccount loads an account via cs3 by id and writes it to the provided account
@@ -147,8 +153,14 @@ func (r CS3Repo) WriteGroup(ctx context.Context, g *proto.Group) (err error) {
return err
}
_, err = r.dataProvider.put(r.groupURL(g.Id), bytes.NewReader(by), t)
return err
resp, err := r.dataProvider.put(r.groupURL(g.Id), bytes.NewReader(by), t)
if err != nil {
return err
}
if err = resp.Body.Close(); err != nil {
return err
}
return nil
}
// LoadGroup loads a group via cs3 by id and writes it to the provided group

View File

@@ -127,7 +127,7 @@ func (r DiskRepo) DeleteGroup(ctx context.Context, id string) (err error) {
}
}
return nil
return
//r.log.Error().Err(err).Str("id", id).Str("path", path).Msg("could not remove group")
//return merrors.InternalServerError(r.serviceID, "could not remove group: %v", err.Error())

View File

@@ -1,16 +0,0 @@
---
# OpenID Connect client registry.
clients:
- id: phoenix
name: OCIS
application_type: web
insecure: yes
trusted: yes
redirect_uris:
- https://ocis-server:9200/oidc-callback.html
- https://ocis-server:9200/
origins:
- https://ocis-server:9200
authorities:

View File

@@ -1,27 +0,0 @@
{
"server": "https://ocis-server:9200",
"theme": "owncloud",
"version": "0.1.0",
"openIdConnect": {
"metadata_url": "https://ocis-server:9200/.well-known/openid-configuration",
"authority": "https://ocis-server:9200",
"client_id": "phoenix",
"response_type": "code",
"scope": "openid profile email"
},
"apps": [
"files",
"draw-io",
"markdown-editor",
"media-viewer"
],
"external_apps": [
{
"id": "accounts",
"path": "https://ocis-server:9200/accounts.js",
"config": {
"url": "https://ocis-server:9200"
}
}
]
}

View File

@@ -0,0 +1,15 @@
Change: Filesystem based index
Tags: accounts, storage
We replaced `bleve` with a new filesystem based index implementation. There is an `indexer` which is capable of
orchestrating different index types to build indices on documents by field. You can choose from the index types `unique`,
`non-unique` or `autoincrement`. Indices can be utilized to run search queries (full matches or globbing) on document
fields. The accounts service is using this index internally to run the search queries coming in via `ListAccounts` and
`ListGroups` and to generate UIDs for new accounts as well as GIDs for new groups.
The accounts service can be configured to store the index on the local FS / a NFS (`disk` implementation of the index)
or to use an arbitrary storage ( `cs3` implementation of the index). `cs3` is the new default, which is configured to
use the `metadata` storage.
https://github.com/owncloud/ocis/pull/709

View File

@@ -0,0 +1,9 @@
Change: Remove username field in OCS
Tags: ocs
We use the incoming userid as both the `id` and the `on_premises_sam_account_name` for new accounts in the accounts
service. The userid in OCS requests is in fact the username, not our internal account id. We need to enforce the userid
as our internal account id though, because the account id is part of various `path` formats.
https://github.com/owncloud/ocis/pull/709

View File

@@ -0,0 +1,7 @@
Bugfix: Don't create account if id/mail/username already taken
Tags: accounts
We don't allow anymore to create a new account if the provided id/mail/username is already taken.
https://github.com/owncloud/ocis/pull/709

View File

@@ -190,7 +190,7 @@ If you prefer to configure the service with commandline flags you can see the av
: Version, defaults to `0.1.0`
--web-config-app
: Provide multiple apps, defaults to `""`. Usage: `phoenix --web-config-app files --web-config-app pdf-viewer`
: Provide multiple apps, defaults to `""`. Usage: `phoenix --web-config-app files --web-config-app media-viewer`
--oidc-metadata-url
: OpenID Connect metadata URL, defaults to `http://localhost:9130/.well-known/openid-configuration`

View File

@@ -110,12 +110,14 @@ github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:l
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 h1:zV3ejI06GQ59hwDQAvmK1qxOQGB3WuVTRoY0okPTAv0=
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
github.com/ascarter/requestid v0.0.0-20170313220838-5b76ab3d4aee h1:3T/l+vMotQ7cDSLWNAn2Vg1SAQ3mdyLgBWWBitSS3uU=
github.com/ascarter/requestid v0.0.0-20170313220838-5b76ab3d4aee/go.mod h1:u7Wtt4WATGGgae9mURNGQQqxAudPKrxfsbSDSGOso+g=
github.com/aws/aws-sdk-go v1.20.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.23.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.23.19/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.33.19/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.34.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-xray-sdk-go v0.9.4/go.mod h1:XtMKdBQfpVut+tJEwI7+dJFRxxRdxHDyVNp2tHXRq04=
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
@@ -155,6 +157,7 @@ github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+Wji
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/bwmarrin/discordgo v0.20.2/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
github.com/c-bata/go-prompt v0.2.3/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=
github.com/caddyserver/certmagic v0.10.6/go.mod h1:Y8jcUBctgk/IhpAzlHKfimZNyXCkfGgRTC0orl8gROQ=
github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
@@ -170,6 +173,7 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
github.com/cheggaaa/pb v1.0.28/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s=
github.com/cheggaaa/pb v1.0.29/go.mod h1:W40334L7FMC5JKWldsTWbdGjLo0RxUKK73K+TuPxX30=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -220,10 +224,13 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cs3org/cato v0.0.0-20200626150132-28a40e643719/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4=
github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4=
github.com/cs3org/go-cs3apis v0.0.0-20200730121022-c4f3d4f7ddfd h1:uMaudkC7znaiIKT9rxIhoRYzrhTg1Nc78X7XEqhmjSk=
github.com/cs3org/go-cs3apis v0.0.0-20200730121022-c4f3d4f7ddfd/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/go-cs3apis v0.0.0-20200810113633-b00aca449666/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/reva v1.1.0 h1:Gih6ECHvMMGSx523SFluFlDmNMuhYelXYShdWvjvW38=
github.com/cs3org/reva v1.1.0/go.mod h1:fBzTrNuAKdQ62ybjpdu8nyhBin90/3/3s6DGQDCdBp4=
github.com/cs3org/reva v1.2.2-0.20200924071957-e6676516e61e/go.mod h1:DOV5SjpOBKN+aWfOHLdA4KiLQkpyC786PQaXEdRAZ0M=
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d h1:SwD98825d6bdB+pEuTxWOXiSjBrHdOl/UVp75eI7JT8=
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8=
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 h1:iwZdTE0PVqJCos1vaoKsclOGD3ADKpshg3SRtYBbwso=
@@ -233,8 +240,12 @@ github.com/cznic/strutil v0.0.0-20181122101858-275e90344537/go.mod h1:AHHPPPXTw0
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgraph-io/ristretto v0.0.1/go.mod h1:T40EBc7CJke8TkpiYfGGKAeFjSaxuFXhuXRyumBd6RE=
github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
github.com/dnaeon/go-vcr v0.0.0-20180814043457-aafff18a5cc2/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
@@ -267,6 +278,7 @@ github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqL
github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk=
github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
@@ -274,6 +286,7 @@ github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI
github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c/go.mod h1:pFdJbAhRf7rh6YYMUdIQGyzne6zYL1tCUW8QV2B3UfY=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsouza/go-dockerclient v1.6.0/go.mod h1:YWwtNPuL4XTX1SKJQk86cWPmmqwx+4np9qfPbb+znGc=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
@@ -568,11 +581,13 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gopherjs/gopherjs v0.0.0-20181004151105-1babbf986f6f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw=
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
@@ -597,6 +612,7 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 h1:THDBEeQ9xZ8JEaCLyLQqXMMdR
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.0 h1:0IKlLyQ3Hs9nDaiK5cSHAGmcQEIC8l2Ts1u6x5Dfrqg=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.0/go.mod h1:mJzapYve32yjrKlk9GbyCZHuPgZsrbyIbyKhSzOpg6s=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
@@ -699,6 +715,7 @@ github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f26
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -751,11 +768,14 @@ github.com/marten-seemann/qtls v0.4.1 h1:YlT8QP3WCCvvok7MGEZkMldXbyqgr8oFg5/n8Gt
github.com/marten-seemann/qtls v0.4.1/go.mod h1:pxVXcHHw1pNIt8Qo0pwSYQEoZ8yYOOPXTCZLQQunvRc=
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
@@ -769,6 +789,7 @@ github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW
github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
github.com/mattn/goveralls v0.0.5/go.mod h1:Xg2LHi51faXLyKXwsndxiW6uxEEQT9+3sjGzzwU4xy0=
github.com/mattn/goveralls v0.0.6/go.mod h1:h8b4ow6FxSPMQHF6o2ve3qsclnffZjYTNEKmLesRwqw=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mennanov/fieldmask-utils v0.3.2 h1:AkHXYBEOoyvocl8YhzoStATRnto5OH1PY4Rj78I5Cuc=
@@ -806,6 +827,7 @@ github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
@@ -890,15 +912,19 @@ github.com/oracle/oci-go-sdk v7.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukw
github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs=
github.com/ory/fosite v0.29.0/go.mod h1:0atSZmXO7CAcs6NPMI/Qtot8tmZYj04Nddoold4S2h0=
github.com/ory/fosite v0.32.2/go.mod h1:UeBhRgW6nAjTcd8S7kAo0IFsY/rTPyOXPq/t8N20Q8I=
github.com/ory/fosite v0.33.0/go.mod h1:h+ize9gk0GvRyGjabriqSEmTkMhny+O95cijb8DVqPE=
github.com/ory/go-acc v0.0.0-20181118080137-ddc355013f90/go.mod h1:sxnvPCxChFuSmTJGj8FdMupeq1BezCiEpDjTUXQ4hf4=
github.com/ory/go-acc v0.2.1/go.mod h1:0omgy2aa3nDBJ45VAKeLHH8ccPBudxLeic4xiDRtug0=
github.com/ory/go-acc v0.2.5/go.mod h1:4Kb/UnPcT8qRAk3IAxta+hvVapdxTLWtrr7bFLlEgpw=
github.com/ory/go-convenience v0.1.0/go.mod h1:uEY/a60PL5c12nYz4V5cHY03IBmwIAEm8TWB0yn9KNs=
github.com/ory/gojsonreference v0.0.0-20190720135523-6b606c2d8ee8/go.mod h1:wsH1C4nIeeQClDtD5AH7kF1uTS6zWyqfjVDTmB0Em7A=
github.com/ory/gojsonschema v1.1.1-0.20190919112458-f254ca73d5e9/go.mod h1:BNZpdJgB74KOLSsWFvzw6roXg1I6O51WO8roMmW+T7Y=
github.com/ory/herodot v0.6.2/go.mod h1:3BOneqcyBsVybCPAJoi92KN2BpJHcmDqAMcAAaJiJow=
github.com/ory/viper v1.5.6/go.mod h1:TYmpFpKLxjQwvT4f0QPpkOn4sDXU1kDgAwJpgLYiQ28=
github.com/ory/viper v1.7.5/go.mod h1:ypOuyJmEUb3oENywQZRgeAMwqgOyDqwboO1tj3DjTaM=
github.com/ory/x v0.0.85/go.mod h1:s44V8t3xyjWZREcU+mWlp4h302rTuM4aLXcW+y5FbQ8=
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ=
github.com/owncloud/flaex v0.0.0-20200411150708-dce59891a203/go.mod h1:jip86t4OVURJTf8CM/0e2qcji/Y4NG3l2lR8kex4JWw=
github.com/owncloud/ocis-pkg/v2 v2.4.0/go.mod h1:FSzIvhx9HcZcq4jgNaDowNvM7PTX/XCyoMvyfzidUpE=
github.com/owncloud/ocis-pkg/v2 v2.4.1-0.20200902134813-1e87c6173ada h1:iVknnuT/z8QCAeBpHEcbI/AiQ9FOBvF5aOAFT3TIM+I=
github.com/owncloud/ocis-pkg/v2 v2.4.1-0.20200902134813-1e87c6173ada/go.mod h1:WdcVM54z0X7aQzS8eyGl7S5sjEMVBtLpfpzsPX3Z+Pw=
@@ -906,6 +932,7 @@ github.com/owncloud/ocis-settings v0.3.2-0.20200828091056-47af10a0e872 h1:VGWM/e
github.com/owncloud/ocis-settings v0.3.2-0.20200828091056-47af10a0e872/go.mod h1:vRge9QDkOsc6j76gPBmZs1Z5uOPrV4DIkZCgZCEFwBA=
github.com/owncloud/ocis/settings v0.0.0-20200918114005-1a0ddd2190ee h1:LaKP3hCTJ6WwB3W40m5UhddvokMRIbOXrjogxON4jAI=
github.com/owncloud/ocis/settings v0.0.0-20200918114005-1a0ddd2190ee/go.mod h1:5w91idmyOd8LgYK3eGuqsFBOfVJnSDeEp7S6dHheW14=
github.com/owncloud/ocis/storage v0.0.0-20201015120921-38358ba4d4df/go.mod h1:s9kJvxtBlHEi5qc1TuPAdz2bprk9yGFe+FSOeC76Pbs=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
github.com/parnurzeal/gorequest v0.2.15/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE=
@@ -917,6 +944,7 @@ github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg=
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs=
github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
@@ -927,6 +955,8 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pkg/term v0.0.0-20200520122047-c3ffed290a03/go.mod h1:Z9+Ul5bCbBKnbCvdOWbLqTHhJiYV414CURZJba6L8qA=
github.com/pkg/xattr v0.4.1/go.mod h1:W2cGD0TBEus7MkUgv0tNZ9JutLtVO3cXu+IBRuHqnFs=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -1043,6 +1073,7 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B
github.com/spf13/afero v1.2.0/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/afero v1.3.2/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
@@ -1050,6 +1081,7 @@ github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
@@ -1061,6 +1093,7 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/spf13/viper v1.2.1/go.mod h1:P4AexN0a+C9tGAnUFNwDMYYZv3pjFuvmeiMyKRaNVlI=
github.com/spf13/viper v1.3.1/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/spf13/viper v1.6.3 h1:pDDu1OyEDTKzpJwdq4TiuLyMsUgRa/BT5cn5O62NoHs=
github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw=
github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM=
@@ -1080,6 +1113,7 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/studio-b12/gowebdav v0.0.0-20200303150724-9380631c29a1/go.mod h1:gCcfDlA1Y7GqOaeEKw5l9dOGx1VLdc/HuQSlQAaZ30s=
github.com/subosito/gotenv v1.1.1/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
@@ -1142,6 +1176,7 @@ github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63M
github.com/yaegashi/msgraph.go v0.1.1-0.20200221123608-2d438cf2a7cc h1:ejaC8rvIvCWmsaFrvmGOxhBuMxxhBB1xRshuM98XQ7M=
github.com/yaegashi/msgraph.go v0.1.1-0.20200221123608-2d438cf2a7cc/go.mod h1:tso14hwzqX4VbnWTNsxiL0DvMb2OwbGISFA7jDibdWc=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
@@ -1196,17 +1231,20 @@ golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaE
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200320181102-891825fb96df/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 h1:3zb4D3T4G8jdExgVU/95+vQXfpEPiMdCaZgmGVxjNHM=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1219,6 +1257,7 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@@ -1287,6 +1326,7 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2 h1:eDrdRpKgkcCqKZQwyZRyeFZgfqt37SL7Kv3tok06cKE=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
@@ -1361,7 +1401,9 @@ golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1369,6 +1411,7 @@ golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c h1:jceGD5YNJGgGMkJz79agzOln1K9TaZUjv5ird16qniQ=
@@ -1378,15 +1421,19 @@ golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121 h1:rITEj+UZHYC927n8GT97eC3zrpzXdb/voyeOuVKS46o=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0 h1:xQwXv67TxFo9nC1GJFyab5eq/5B590r6RlnL/G8Sz7w=
@@ -1456,6 +1503,8 @@ golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200721223218-6123e77877b2/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200811215021-48a8ffc5b207 h1:8Kg+JssU1jBZs8GIrL5pl4nVyaqyyhdmHAR4D1zGErg=
golang.org/x/tools v0.0.0-20200811215021-48a8ffc5b207/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1515,6 +1564,7 @@ google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece h1:1YM0uhfumvoDu9sx8+RyWwTI63zoCQvI23IYFRlvte0=
@@ -1562,6 +1612,7 @@ gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mail.v2 v2.0.0-20180731213649-a0242b2233b4/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
gopkg.in/ns1/ns1-go.v2 v2.0.0-20190730140822-b51389932cbc/go.mod h1:VV+3haRsgDiVLxyifmMBrBIuCWFBPYKbRssXB9z67Hw=
gopkg.in/resty.v1 v1.9.1/go.mod h1:vo52Hzryw9PnPHcJfPsBiFW62XhNx5OczbV9y+IMpgc=
@@ -1572,6 +1623,7 @@ gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.5.0 h1:OZ4sdq+Y+SHfYB7vfthi1Ei8b0vkP8ZPQgUfUwdUSqo=
gopkg.in/square/go-jose.v2 v2.5.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/telegram-bot-api.v4 v4.6.4/go.mod h1:5DpGO5dbumb40px+dXcwCpcjmeHNYLpk0bp3XRNvWDM=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
@@ -1585,6 +1637,8 @@ gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo=
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -22,8 +22,10 @@ func newAccountOptions(opts ...account.Option) account.Options {
// AccountID serves as key for the account uuid in the context
const AccountID string = "Account-Id"
// RoleIDs serves as key for the roles in the context
const RoleIDs string = "Role-Ids"
// UUIDKey serves as key for the account uuid in the context
// Deprecated: UUIDKey exists for compatibility reasons. Use AccountID instead.
var UUIDKey struct{}

View File

@@ -24,7 +24,7 @@ require (
github.com/owncloud/ocis/ocs v0.0.0-00010101000000-000000000000
github.com/owncloud/ocis/proxy v0.0.0-00010101000000-000000000000
github.com/owncloud/ocis/settings v0.0.0-20200918114005-1a0ddd2190ee
github.com/owncloud/ocis/storage v0.0.0-00010101000000-000000000000
github.com/owncloud/ocis/storage v0.0.0-20201015120921-38358ba4d4df
github.com/owncloud/ocis/store v0.0.0-20200918125107-fcca9faa81c8
github.com/owncloud/ocis/thumbnails v0.1.6
github.com/owncloud/ocis/webdav v0.0.0-00010101000000-000000000000

View File

@@ -126,8 +126,10 @@ github.com/aws/aws-sdk-go v1.23.19/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpi
github.com/aws/aws-sdk-go v1.28.2/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.33.19/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.34.2/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.34.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.35.0 h1:Pxqn1MWNfBCNcX7jrXCCTfsKpg5ms2IMUMmmcGtYJuo=
github.com/aws/aws-sdk-go v1.35.0/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
github.com/aws/aws-sdk-go v1.35.9 h1:b1HiUpdkFLJyoOQ7zas36YHzjNHH0ivHx/G5lWBeg+U=
github.com/aws/aws-sdk-go v1.35.9/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k=
github.com/aws/aws-xray-sdk-go v0.9.4/go.mod h1:XtMKdBQfpVut+tJEwI7+dJFRxxRdxHDyVNp2tHXRq04=
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
@@ -268,11 +270,13 @@ github.com/cs3org/go-cs3apis v0.0.0-20200929101248-821df597ec8d/go.mod h1:UXha4T
github.com/cs3org/reva v0.0.2-0.20200115110931-4c7513415ec5/go.mod h1:Hk3eCcdhtv4eIhKvRK736fQuOyS1HuHnUcz0Dq6NK1A=
github.com/cs3org/reva v1.1.0/go.mod h1:fBzTrNuAKdQ62ybjpdu8nyhBin90/3/3s6DGQDCdBp4=
github.com/cs3org/reva v1.2.1-0.20200826162318-c0f54e1f37ea/go.mod h1:FvYB+UPpuPCw0hH42qHVR1R2atZyy69METZI/zEaST8=
github.com/cs3org/reva v1.2.2-0.20200924071957-e6676516e61e/go.mod h1:DOV5SjpOBKN+aWfOHLdA4KiLQkpyC786PQaXEdRAZ0M=
github.com/cs3org/reva v1.2.2-0.20201006093611-4a9be347ac29 h1:bGdr8WQI3khh8/Uo7icnWOvIyGxnGUVvSSLvtEliuIE=
github.com/cs3org/reva v1.2.2-0.20201006093611-4a9be347ac29/go.mod h1:c0MYy0goE5OGC8WPb5LLMZtCqymwSk2fiKVQANzy0zg=
github.com/cs3org/reva v1.2.2-0.20201007135248-bccddc4b5a48 h1:ICRTh96BemJ+oOSgp8j4EM32Ye10jh+UWjMxKbVr30g=
github.com/cs3org/reva v1.2.2-0.20201007135248-bccddc4b5a48/go.mod h1:A4Q/nQ8Vs+HeAduSFnM37fqxEM3uXVxhaHrNL+gWcBY=
github.com/cs3org/reva v1.3.1-0.20201021065855-dc400f81ecbc/go.mod h1:rTJhfVoZggB5iSPH5oWqQSO+W1iTQIxNmaX/ueS9GAU=
github.com/cs3org/reva v1.3.1-0.20201021130722-dd3a8c0f3881 h1:xhpamvgyDr0jCtjXZCTk8qOdnslxhz8dHym5KLh7gl8=
github.com/cs3org/reva v1.3.1-0.20201021130722-dd3a8c0f3881/go.mod h1:NplJavkhPZvy8/9K9m95g6uddq3pATO62bovvevpsBw=
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d h1:SwD98825d6bdB+pEuTxWOXiSjBrHdOl/UVp75eI7JT8=
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8=
@@ -393,6 +397,7 @@ github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
github.com/go-ldap/ldap/v3 v3.1.7/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q=
github.com/go-ldap/ldap/v3 v3.2.3 h1:FBt+5w3q/vPVPb4eYMQSn+pOiz4zewPamYhlGMmc7yM=
github.com/go-ldap/ldap/v3 v3.2.3/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
github.com/go-ldap/ldap/v3 v3.2.4 h1:PFavAq2xTgzo/loE8qNXcQaofAaqIpI4WgaLdv+1l3E=
github.com/go-ldap/ldap/v3 v3.2.4/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
github.com/go-log/log v0.1.0/go.mod h1:4mBwpdRMFLiuXZDCwU2lKQFsoSCo72j3HqBK9d81N2M=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
@@ -636,6 +641,7 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
@@ -1063,9 +1069,11 @@ github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnh
github.com/ory/fosite v0.29.0/go.mod h1:0atSZmXO7CAcs6NPMI/Qtot8tmZYj04Nddoold4S2h0=
github.com/ory/fosite v0.30.2/go.mod h1:Lq9qQ9Sl6mcea2Tt8J7PU+wUeFYPZ+vg7N3zPVKGbN8=
github.com/ory/fosite v0.32.2/go.mod h1:UeBhRgW6nAjTcd8S7kAo0IFsY/rTPyOXPq/t8N20Q8I=
github.com/ory/fosite v0.33.0/go.mod h1:h+ize9gk0GvRyGjabriqSEmTkMhny+O95cijb8DVqPE=
github.com/ory/fosite v0.34.0 h1:lCUX4f5BoiXBIRUYKeTne+aRl0v6StgWpyYKq+7ILw0=
github.com/ory/fosite v0.34.0/go.mod h1:h+ize9gk0GvRyGjabriqSEmTkMhny+O95cijb8DVqPE=
github.com/ory/fosite v0.35.0/go.mod h1:h+ize9gk0GvRyGjabriqSEmTkMhny+O95cijb8DVqPE=
github.com/ory/fosite v0.35.1 h1:mGPcwVGwHA7Yy9wr/7LDps6BEXyavL32NxizL9eH53Q=
github.com/ory/fosite v0.35.1/go.mod h1:h+ize9gk0GvRyGjabriqSEmTkMhny+O95cijb8DVqPE=
github.com/ory/go-acc v0.0.0-20181118080137-ddc355013f90/go.mod h1:sxnvPCxChFuSmTJGj8FdMupeq1BezCiEpDjTUXQ4hf4=
github.com/ory/go-acc v0.2.1/go.mod h1:0omgy2aa3nDBJ45VAKeLHH8ccPBudxLeic4xiDRtug0=
@@ -1385,6 +1393,7 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=

View File

@@ -161,7 +161,6 @@ apiProvisioning-v2/enableUser.feature:31
apiProvisioning-v2/enableUser.feature:32
apiProvisioning-v2/getUser.feature:34
apiProvisioning-v2/getUser.feature:35
apiProvisioning-v1/addUser.feature:118
#
# https://github.com/owncloud/ocis-accounts/issues/80
# Creating an already existing user works
@@ -177,29 +176,16 @@ apiProvisioning-v2/addUser.feature:39
apiProvisioning-v1/addUser.feature:69
apiProvisioning-v2/addUser.feature:69
#
# https://github.com/owncloud/product/issues/237 etags are not quoted in PROPFIND
#
apiSharePublicLink1/createPublicLinkShare.feature:793
apiSharePublicLink1/createPublicLinkShare.feature:804
#
# https://github.com/owncloud/ocis-accounts/issues/128
# Username is case sensitive
#
apiProvisioning-v1/addUser.feature:96
apiProvisioning-v1/addUser.feature:97
apiProvisioning-v1/addUser.feature:98
apiProvisioning-v1/addUser.feature:99
apiProvisioning-v1/addUser.feature:100
apiProvisioning-v1/addUser.feature:102
apiProvisioning-v1/getUser.feature:37
apiProvisioning-v1/getUser.feature:113
apiProvisioning-v1/getUser.feature:124
apiProvisioning-v2/addUser.feature:96
apiProvisioning-v2/addUser.feature:97
apiProvisioning-v2/addUser.feature:98
apiProvisioning-v2/addUser.feature:99
apiProvisioning-v2/addUser.feature:100
apiProvisioning-v2/addUser.feature:102
apiProvisioning-v2/getUser.feature:37
apiProvisioning-v2/getUser.feature:114
apiProvisioning-v2/getUser.feature:125
apiProvisioning-v1/deleteUser.feature:32
apiProvisioning-v2/deleteUser.feature:32
#
# https://github.com/owncloud/ocis/issues/197
# Client token generation not implemented
@@ -494,6 +480,7 @@ apiShareOperationsToShares/getWebDAVSharePermissions.feature:143
#
apiShareOperationsToShares/gettingShares.feature:167
apiShareOperationsToShares/gettingShares.feature:168
#
apiSharePublicLink1/createPublicLinkShare.feature:793
apiSharePublicLink1/createPublicLinkShare.feature:804
#
@@ -1301,6 +1288,9 @@ apiWebdavProperties2/getFileProperties.feature:441
apiWebdavProperties2/getFileProperties.feature:442
apiWebdavProperties2/getFileProperties.feature:454
apiWebdavProperties2/getFileProperties.feature:455
#
# https://github.com/owncloud/product/issues/237 etags are not quoted in PROPFIND
#
apiWebdavUpload1/uploadFile.feature:144
apiWebdavUpload1/uploadFile.feature:145
apiWebdavUpload1/uploadFile.feature:157
@@ -1509,7 +1499,7 @@ apiWebdavEtagPropagation1/deleteFileFolder.feature:152
apiWebdavEtagPropagation1/deleteFileFolder.feature:182
apiWebdavEtagPropagation1/deleteFileFolder.feature:183
#
# https://github.com/owncloud/product/issues/239 moving a file from one folder to an other does not change the etag of the source folder
# https://github.com/owncloud/product/issues/243 etags don't change for a share receiver
#
apiWebdavEtagPropagation1/moveFileFolder.feature:235
apiWebdavEtagPropagation1/moveFileFolder.feature:236

View File

@@ -165,13 +165,11 @@ apiProvisioning-v2/enableUser.feature:31
apiProvisioning-v2/enableUser.feature:32
apiProvisioning-v2/getUser.feature:34
apiProvisioning-v2/getUser.feature:35
apiProvisioning-v1/addUser.feature:118
#
# https://github.com/owncloud/ocis-accounts/issues/80
# Creating an already existing user works
#
apiProvisioning-v1/addUser.feature:32
apiProvisioning-v2/addUser.feature:32
apiProvisioning-v1/addUser.feature:39
apiProvisioning-v2/addUser.feature:39
#
@@ -184,26 +182,7 @@ apiProvisioning-v2/addUser.feature:69
# https://github.com/owncloud/ocis-accounts/issues/128
# Username is case sensitive
#
apiProvisioning-v1/addUser.feature:96
apiProvisioning-v1/addUser.feature:97
apiProvisioning-v1/addUser.feature:98
apiProvisioning-v1/addUser.feature:99
apiProvisioning-v1/addUser.feature:100
apiProvisioning-v1/addUser.feature:102
apiProvisioning-v1/getUser.feature:37
apiProvisioning-v1/getUser.feature:113
apiProvisioning-v1/getUser.feature:124
apiProvisioning-v2/addUser.feature:96
apiProvisioning-v2/addUser.feature:97
apiProvisioning-v2/addUser.feature:98
apiProvisioning-v2/addUser.feature:99
apiProvisioning-v2/addUser.feature:100
apiProvisioning-v2/addUser.feature:102
apiProvisioning-v2/getUser.feature:37
apiProvisioning-v2/getUser.feature:114
apiProvisioning-v2/getUser.feature:125
apiProvisioning-v1/deleteUser.feature:32
apiProvisioning-v2/deleteUser.feature:32
#
# https://github.com/owncloud/ocis/issues/197
# Client token generation not implemented

View File

@@ -20,12 +20,12 @@ Feature: auth
| endpoint |
| /ocs/v1.php/cloud/users/%username% |
Then the HTTP status code of responses on all endpoints should be "200"
And the OCS status code of responses on all endpoints should be "103"
And the OCS status code of responses on all endpoints should be "998"
When the administrator requests these endpoints with "PUT" with body "doesnotmatter" using password "invalid" about user "Alice"
| endpoint |
| /ocs/v2.php/cloud/users/%username% |
Then the HTTP status code of responses on all endpoints should be "400"
And the OCS status code of responses on all endpoints should be "103"
Then the HTTP status code of responses on all endpoints should be "404"
And the OCS status code of responses on all endpoints should be "998"
@issue-ocis-reva-30
@issue-ocis-ocs-28

View File

@@ -12,8 +12,17 @@
"apps": [
"files",
"draw-io",
"pdf-viewer",
"markdown-editor",
"media-viewer"
],
"external_apps": [
{
"id": "settings",
"path": "https://ocis-server:9200/settings.js"
},
{
"id": "accounts",
"path": "https://ocis-server:9200/accounts.js"
}
]
}

View File

@@ -7,11 +7,10 @@ require (
contrib.go.opencensus.io/exporter/ocagent v0.7.0
contrib.go.opencensus.io/exporter/zipkin v0.1.1
github.com/UnnoTed/fileb0x v1.1.4
github.com/cs3org/reva v1.2.1-0.20200826162318-c0f54e1f37ea
github.com/cs3org/reva v1.3.1-0.20201021065855-dc400f81ecbc
github.com/go-chi/chi v4.1.2+incompatible
github.com/go-chi/render v1.0.1
github.com/golang/protobuf v1.4.2
github.com/google/uuid v1.1.2 // indirect
github.com/golang/protobuf v1.4.3
github.com/micro/cli/v2 v2.1.2
github.com/micro/go-micro/v2 v2.9.1
github.com/oklog/run v1.1.0
@@ -25,7 +24,7 @@ require (
github.com/restic/calens v0.2.0
github.com/spf13/viper v1.7.0
github.com/stretchr/testify v1.6.1
go.opencensus.io v0.22.4
go.opencensus.io v0.22.5
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect
google.golang.org/protobuf v1.25.0
)

View File

@@ -144,6 +144,8 @@ github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:l
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 h1:zV3ejI06GQ59hwDQAvmK1qxOQGB3WuVTRoY0okPTAv0=
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY=
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
github.com/ascarter/requestid v0.0.0-20170313220838-5b76ab3d4aee h1:3T/l+vMotQ7cDSLWNAn2Vg1SAQ3mdyLgBWWBitSS3uU=
github.com/ascarter/requestid v0.0.0-20170313220838-5b76ab3d4aee/go.mod h1:u7Wtt4WATGGgae9mURNGQQqxAudPKrxfsbSDSGOso+g=
github.com/asim/go-awsxray v0.0.0-20161209120537-0d8a60b6e205/go.mod h1:frVmN4PtXUuL1EbZn0uL4PHSTKNKFnbMpBIhngqMuNQ=
@@ -159,6 +161,8 @@ github.com/aws/aws-sdk-go v1.28.2/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN
github.com/aws/aws-sdk-go v1.29.26/go.mod h1:1KvfttTE3SPKMpo8g2c6jL3ZKfXtFvKscTgahTma5Xg=
github.com/aws/aws-sdk-go v1.33.19/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.34.2/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.34.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.35.9/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k=
github.com/aws/aws-xray-sdk-go v0.9.4/go.mod h1:XtMKdBQfpVut+tJEwI7+dJFRxxRdxHDyVNp2tHXRq04=
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
@@ -210,6 +214,7 @@ github.com/bwmarrin/discordgo v0.19.0/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVO
github.com/bwmarrin/discordgo v0.20.1/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
github.com/bwmarrin/discordgo v0.20.2/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
github.com/c-bata/go-prompt v0.2.3/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=
github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw=
github.com/caddyserver/certmagic v0.10.6/go.mod h1:Y8jcUBctgk/IhpAzlHKfimZNyXCkfGgRTC0orl8gROQ=
github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
@@ -293,6 +298,7 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
github.com/crewjam/httperr v0.0.0-20190612203328-a946449404da/go.mod h1:+rmNIXRvYMqLQeR4DHyTvs6y0MEMymTz4vyFpFkKTPs=
github.com/crewjam/saml v0.4.0/go.mod h1:geQUbAAwmTKNJFDzoXaTssZHY26O89PHIm3K3YWjWnI=
github.com/cs3org/cato v0.0.0-20200626150132-28a40e643719/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4=
github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4=
github.com/cs3org/go-cs3apis v0.0.0-20191128165347-19746c015c83/go.mod h1:IsVGyZrOLUQD48JIhlM/xb3Vz6He5o2+W0ZTfUGY+IU=
github.com/cs3org/go-cs3apis v0.0.0-20200306065539-29abc33f5be0 h1:jTKILSBtDm0GEw3FtXPxc5wxGpaw2pxzREg1GBV9LIQ=
github.com/cs3org/go-cs3apis v0.0.0-20200306065539-29abc33f5be0/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
@@ -301,6 +307,7 @@ github.com/cs3org/go-cs3apis v0.0.0-20200730121022-c4f3d4f7ddfd h1:uMaudkC7znaiI
github.com/cs3org/go-cs3apis v0.0.0-20200730121022-c4f3d4f7ddfd/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/go-cs3apis v0.0.0-20200810113633-b00aca449666 h1:E7VsSSN/2YZLSwrDMJJdAWU11lP7W1qkcXbrslb0PM0=
github.com/cs3org/go-cs3apis v0.0.0-20200810113633-b00aca449666/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/go-cs3apis v0.0.0-20200929101248-821df597ec8d/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/reva v0.0.2-0.20200115110931-4c7513415ec5/go.mod h1:Hk3eCcdhtv4eIhKvRK736fQuOyS1HuHnUcz0Dq6NK1A=
github.com/cs3org/reva v0.1.0 h1:PYzDejKm/+xG3OTS2WgzBxcksVogEGmPgjJVegwSR2c=
github.com/cs3org/reva v0.1.0/go.mod h1:8j6QyyAq9Kjj7RPfJb7M1aEmw5DmsuCJKUULXxYOyRo=
@@ -308,6 +315,10 @@ github.com/cs3org/reva v1.1.0 h1:Gih6ECHvMMGSx523SFluFlDmNMuhYelXYShdWvjvW38=
github.com/cs3org/reva v1.1.0/go.mod h1:fBzTrNuAKdQ62ybjpdu8nyhBin90/3/3s6DGQDCdBp4=
github.com/cs3org/reva v1.2.1-0.20200826162318-c0f54e1f37ea h1:xVyJvR+GoaBrRJV6GnDflgm9bzkmjchCBBg0nMiHu6M=
github.com/cs3org/reva v1.2.1-0.20200826162318-c0f54e1f37ea/go.mod h1:FvYB+UPpuPCw0hH42qHVR1R2atZyy69METZI/zEaST8=
github.com/cs3org/reva v1.2.2-0.20200924071957-e6676516e61e h1:khITGSnfDXtByQsLezoXgocUgGHJBBn0BPsUihGvk7w=
github.com/cs3org/reva v1.2.2-0.20200924071957-e6676516e61e/go.mod h1:DOV5SjpOBKN+aWfOHLdA4KiLQkpyC786PQaXEdRAZ0M=
github.com/cs3org/reva v1.3.1-0.20201021065855-dc400f81ecbc h1:8y6N/bscmzdXd4yAv6bIJiqggter8iEmb4cYMhuZkE8=
github.com/cs3org/reva v1.3.1-0.20201021065855-dc400f81ecbc/go.mod h1:rTJhfVoZggB5iSPH5oWqQSO+W1iTQIxNmaX/ueS9GAU=
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d h1:SwD98825d6bdB+pEuTxWOXiSjBrHdOl/UVp75eI7JT8=
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8=
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 h1:iwZdTE0PVqJCos1vaoKsclOGD3ADKpshg3SRtYBbwso=
@@ -323,8 +334,12 @@ github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14y
github.com/decker502/dnspod-go v0.2.0/go.mod h1:qsurYu1FgxcDwfSwXJdLt4kRsBLZeosEb9uq4Sy+08g=
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE=
github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY=
github.com/dgraph-io/ristretto v0.0.1/go.mod h1:T40EBc7CJke8TkpiYfGGKAeFjSaxuFXhuXRyumBd6RE=
github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
github.com/dnaeon/go-vcr v0.0.0-20180814043457-aafff18a5cc2/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
@@ -431,6 +446,7 @@ github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
github.com/go-ldap/ldap/v3 v3.1.7/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q=
github.com/go-ldap/ldap/v3 v3.2.3/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
github.com/go-ldap/ldap/v3 v3.2.4/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
github.com/go-log/log v0.1.0 h1:wudGTNsiGzrD5ZjgIkVZ517ugi2XRe9Q/xRCzwEO4/U=
github.com/go-log/log v0.1.0/go.mod h1:4mBwpdRMFLiuXZDCwU2lKQFsoSCo72j3HqBK9d81N2M=
github.com/go-log/log v0.2.0/go.mod h1:xzCnwajcues/6w7lne3yK2QU7DBPW7kqbgPGG5AF65U=
@@ -683,6 +699,7 @@ github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
@@ -759,6 +776,7 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xC
github.com/grpc-ecosystem/go-grpc-middleware v1.2.0 h1:0IKlLyQ3Hs9nDaiK5cSHAGmcQEIC8l2Ts1u6x5Dfrqg=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.0/go.mod h1:mJzapYve32yjrKlk9GbyCZHuPgZsrbyIbyKhSzOpg6s=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.1/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
@@ -827,6 +845,7 @@ github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/iancoleman/strcase v0.1.2/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4=
github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd/go.mod h1:3LVOLeyx9XVvwPgrt2be44XgSqndprz1G18rSk8KD84=
@@ -850,6 +869,8 @@ github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U=
github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ=
github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU=
@@ -899,6 +920,7 @@ github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f26
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -980,6 +1002,7 @@ github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
@@ -997,8 +1020,10 @@ github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsO
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
github.com/mattn/goveralls v0.0.5/go.mod h1:Xg2LHi51faXLyKXwsndxiW6uxEEQT9+3sjGzzwU4xy0=
github.com/mattn/goveralls v0.0.6/go.mod h1:h8b4ow6FxSPMQHF6o2ve3qsclnffZjYTNEKmLesRwqw=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103/go.mod h1:o9YPB5aGP8ob35Vy6+vyq3P3bWe7NQWzf+JLiXCiMaE=
@@ -1075,6 +1100,7 @@ github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
@@ -1187,13 +1213,17 @@ github.com/ory/fosite v0.29.0/go.mod h1:0atSZmXO7CAcs6NPMI/Qtot8tmZYj04Nddoold4S
github.com/ory/fosite v0.30.2/go.mod h1:Lq9qQ9Sl6mcea2Tt8J7PU+wUeFYPZ+vg7N3zPVKGbN8=
github.com/ory/fosite v0.30.4/go.mod h1:Lq9qQ9Sl6mcea2Tt8J7PU+wUeFYPZ+vg7N3zPVKGbN8=
github.com/ory/fosite v0.32.2/go.mod h1:UeBhRgW6nAjTcd8S7kAo0IFsY/rTPyOXPq/t8N20Q8I=
github.com/ory/fosite v0.33.0/go.mod h1:h+ize9gk0GvRyGjabriqSEmTkMhny+O95cijb8DVqPE=
github.com/ory/fosite v0.35.0/go.mod h1:h+ize9gk0GvRyGjabriqSEmTkMhny+O95cijb8DVqPE=
github.com/ory/go-acc v0.0.0-20181118080137-ddc355013f90/go.mod h1:sxnvPCxChFuSmTJGj8FdMupeq1BezCiEpDjTUXQ4hf4=
github.com/ory/go-acc v0.2.1/go.mod h1:0omgy2aa3nDBJ45VAKeLHH8ccPBudxLeic4xiDRtug0=
github.com/ory/go-acc v0.2.5/go.mod h1:4Kb/UnPcT8qRAk3IAxta+hvVapdxTLWtrr7bFLlEgpw=
github.com/ory/go-convenience v0.1.0/go.mod h1:uEY/a60PL5c12nYz4V5cHY03IBmwIAEm8TWB0yn9KNs=
github.com/ory/gojsonreference v0.0.0-20190720135523-6b606c2d8ee8/go.mod h1:wsH1C4nIeeQClDtD5AH7kF1uTS6zWyqfjVDTmB0Em7A=
github.com/ory/gojsonschema v1.1.1-0.20190919112458-f254ca73d5e9/go.mod h1:BNZpdJgB74KOLSsWFvzw6roXg1I6O51WO8roMmW+T7Y=
github.com/ory/herodot v0.6.2/go.mod h1:3BOneqcyBsVybCPAJoi92KN2BpJHcmDqAMcAAaJiJow=
github.com/ory/viper v1.5.6/go.mod h1:TYmpFpKLxjQwvT4f0QPpkOn4sDXU1kDgAwJpgLYiQ28=
github.com/ory/viper v1.7.5/go.mod h1:ypOuyJmEUb3oENywQZRgeAMwqgOyDqwboO1tj3DjTaM=
github.com/ory/x v0.0.85/go.mod h1:s44V8t3xyjWZREcU+mWlp4h302rTuM4aLXcW+y5FbQ8=
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ=
github.com/owncloud/flaex v0.0.0-20200411150708-dce59891a203/go.mod h1:jip86t4OVURJTf8CM/0e2qcji/Y4NG3l2lR8kex4JWw=
@@ -1252,6 +1282,7 @@ github.com/owncloud/ocis/ocis-pkg v0.0.0-20200918114005-1a0ddd2190ee h1:P/bd6+zV
github.com/owncloud/ocis/ocis-pkg v0.0.0-20200918114005-1a0ddd2190ee/go.mod h1:kukd3chd0ARpGNSLcIutgFywSvWIIdQcpyhPtVTyZbM=
github.com/owncloud/ocis/settings v0.0.0-20200918114005-1a0ddd2190ee h1:LaKP3hCTJ6WwB3W40m5UhddvokMRIbOXrjogxON4jAI=
github.com/owncloud/ocis/settings v0.0.0-20200918114005-1a0ddd2190ee/go.mod h1:5w91idmyOd8LgYK3eGuqsFBOfVJnSDeEp7S6dHheW14=
github.com/owncloud/ocis/storage v0.0.0-20201015120921-38358ba4d4df/go.mod h1:s9kJvxtBlHEi5qc1TuPAdz2bprk9yGFe+FSOeC76Pbs=
github.com/owncloud/ocis/store v0.0.0-20200918125107-fcca9faa81c8 h1:yFhYoWTmRHopVO2HfSoJtq8n9T91HFMMBTRx+KAvMuw=
github.com/owncloud/ocis/store v0.0.0-20200918125107-fcca9faa81c8/go.mod h1://2CHveV3rTfhJIAs/gK7o5/U5jB9Xx8IekM8NEE40s=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
@@ -1269,6 +1300,8 @@ github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfS
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4=
github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
github.com/pelletier/go-toml v1.8.0 h1:Keo9qb7iRJs2voHvunFtuuYFsbWeOBh8/P9v/kVMFtw=
github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs=
github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
@@ -1280,7 +1313,9 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pkg/term v0.0.0-20200520122047-c3ffed290a03/go.mod h1:Z9+Ul5bCbBKnbCvdOWbLqTHhJiYV414CURZJba6L8qA=
github.com/pkg/term v1.1.0/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw=
github.com/pkg/xattr v0.4.1/go.mod h1:W2cGD0TBEus7MkUgv0tNZ9JutLtVO3cXu+IBRuHqnFs=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -1359,6 +1394,8 @@ github.com/rs/zerolog v1.18.0 h1:CbAm3kP2Tptby1i9sYy2MGRg0uxIN9cyDb59Ys7W8z8=
github.com/rs/zerolog v1.18.0/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF5+I=
github.com/rs/zerolog v1.19.0 h1:hYz4ZVdUgjXTBUmrkrw55j1nHx68LfOKIQk5IYtyScg=
github.com/rs/zerolog v1.19.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo=
github.com/rs/zerolog v1.20.0 h1:38k9hgtUBdxFwE34yS8rTHmHBa4eN16E4DJlv177LNs=
github.com/rs/zerolog v1.20.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo=
github.com/rubenv/sql-migrate v0.0.0-20190212093014-1007f53448d7/go.mod h1:WS0rl9eEliYI8DPnr3TOwz4439pay+qNgzJoVya/DmY=
github.com/russellhaering/goxmldsig v0.0.0-20180430223755-7acd5e4a6ef7/go.mod h1:Oz4y6ImuOQZxynhbSXk7btjEfNBtGlj2dcaOvXl2FSM=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
@@ -1420,6 +1457,8 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B
github.com/spf13/afero v1.2.0/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/afero v1.3.2 h1:GDarE4TJQI52kYSbSAmLiId1Elfj+xgSDqrUZxFhxlU=
github.com/spf13/afero v1.3.2/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
@@ -1566,6 +1605,7 @@ go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
@@ -1619,6 +1659,7 @@ golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaE
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
@@ -1639,6 +1680,7 @@ golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
@@ -1819,18 +1861,21 @@ golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4 h1:Hynbrlo6LbYI3H1IqXpkVDOcX/3HiPdhVEuyj5a59RM=
golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1841,10 +1886,15 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666 h1:gVCS+QOncANNPlmlO1AhlU3oxs4V9z+gTtPwIk3p2N8=
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6 h1:DvY3Zkh7KabQE/kfzMvYvKirSiguP9Q/veMtkYyf0o8=
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1931,8 +1981,10 @@ golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4 h1:kDtqNkeBrZb8B+atrj50B5X
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200421042724-cfa8b22178d2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200427214658-4697a2867c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200526224456-8b020aee10d2 h1:21BqcH/onxtGHn1A2GDOJjZnbt4Nlez629S3eaR+eYs=
golang.org/x/tools v0.0.0-20200526224456-8b020aee10d2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200721223218-6123e77877b2/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200811215021-48a8ffc5b207 h1:8Kg+JssU1jBZs8GIrL5pl4nVyaqyyhdmHAR4D1zGErg=
golang.org/x/tools v0.0.0-20200811215021-48a8ffc5b207/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200817023811-d00afeaade8f h1:33yHANSyO/TeglgY9rBhUpX43wtonTXoFOsMRtNB6qE=
@@ -2057,6 +2109,8 @@ gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.51.1 h1:GyboHr4UqMiLUybYjd22ZjQIKEJEpgtLXtuGbR21Oho=
gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww=
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo=
gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q=
gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4=
@@ -2079,6 +2133,8 @@ gopkg.in/square/go-jose.v2 v2.4.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76
gopkg.in/square/go-jose.v2 v2.4.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.5.0 h1:OZ4sdq+Y+SHfYB7vfthi1Ei8b0vkP8ZPQgUfUwdUSqo=
gopkg.in/square/go-jose.v2 v2.5.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w=
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=

View File

File diff suppressed because it is too large Load Diff

View File

@@ -7,10 +7,8 @@ type Users struct {
// User holds the payload for a GetUser response
type User struct {
// TODO needs better naming, clarify if we need a userid, a username or both
Enabled string `json:"enabled" xml:"enabled"`
UserID string `json:"id" xml:"id"`
Username string `json:"username" xml:"username"`
UserID string `json:"id" xml:"id"`// UserID is mapped to the preferred_name attribute in accounts
DisplayName string `json:"display-name" xml:"display-name"`
LegacyDisplayName string `json:"displayname" xml:"displayname"`
Email string `json:"email" xml:"email"`

View File

@@ -3,6 +3,7 @@ package svc
import (
"fmt"
"net/http"
"regexp"
"github.com/go-chi/chi"
"github.com/go-chi/render"
@@ -16,18 +17,26 @@ import (
// ListUserGroups lists a users groups
func (o Ocs) ListUserGroups(w http.ResponseWriter, r *http.Request) {
userid := chi.URLParam(r, "userid")
var account *accounts.Account
var err error
account, err := o.getAccountService().GetAccount(r.Context(), &accounts.GetAccountRequest{Id: userid})
if err != nil {
merr := merrors.FromError(err)
if merr.Code == http.StatusNotFound {
render.Render(w, r, response.ErrRender(data.MetaNotFound.StatusCode, "The requested user could not be found"))
} else {
render.Render(w, r, response.ErrRender(data.MetaServerError.StatusCode, err.Error()))
if isValidUUID(userid) {
account, err = o.getAccountService().GetAccount(r.Context(), &accounts.GetAccountRequest{
Id: userid,
})
} else {
// despite the confusion, if we make it here we got ourselves a username
account, err = o.fetchAccountByUsername(r.Context(), userid)
if err != nil {
merr := merrors.FromError(err)
if merr.Code == http.StatusNotFound {
render.Render(w, r, response.ErrRender(data.MetaNotFound.StatusCode, "The requested user could not be found"))
} else {
render.Render(w, r, response.ErrRender(data.MetaServerError.StatusCode, err.Error()))
}
o.logger.Error().Err(err).Str("userid", userid).Msg("could not get list of user groups")
return
}
o.logger.Error().Err(err).Str("userid", userid).Msg("could not get list of user groups")
return
}
groups := []string{}
@@ -49,16 +58,26 @@ func (o Ocs) AddToGroup(w http.ResponseWriter, r *http.Request) {
render.Render(w, r, response.ErrRender(data.MetaBadRequest.StatusCode, "empty group assignment: unspecified group"))
return
}
account, err := o.fetchAccountByUsername(r.Context(), userid)
if err != nil {
merr := merrors.FromError(err)
if merr.Code == http.StatusNotFound {
render.Render(w, r, response.ErrRender(data.MetaNotFound.StatusCode, "The requested user could not be found"))
} else {
render.Render(w, r, response.ErrRender(data.MetaServerError.StatusCode, err.Error()))
}
return
}
_, err := o.getGroupsService().AddMember(r.Context(), &accounts.AddMemberRequest{
AccountId: userid,
_, err = o.getGroupsService().AddMember(r.Context(), &accounts.AddMemberRequest{
AccountId: account.Id,
GroupId: groupid,
})
if err != nil {
merr := merrors.FromError(err)
if merr.Code == http.StatusNotFound {
render.Render(w, r, response.ErrRender(data.MetaNotFound.StatusCode, "The requested user could not be found"))
render.Render(w, r, response.ErrRender(data.MetaNotFound.StatusCode, "The requested group could not be found"))
} else {
render.Render(w, r, response.ErrRender(data.MetaServerError.StatusCode, err.Error()))
}
@@ -75,15 +94,37 @@ func (o Ocs) RemoveFromGroup(w http.ResponseWriter, r *http.Request) {
userid := chi.URLParam(r, "userid")
groupid := r.URL.Query().Get("groupid")
_, err := o.getGroupsService().RemoveMember(r.Context(), &accounts.RemoveMemberRequest{
AccountId: userid,
var account *accounts.Account
var err error
if isValidUUID(userid) {
account, _ = o.getAccountService().GetAccount(r.Context(), &accounts.GetAccountRequest{
Id: userid,
})
} else {
// despite the confusion, if we make it here we got ourselves a username
account, err = o.fetchAccountByUsername(r.Context(), userid)
if err != nil {
merr := merrors.FromError(err)
if merr.Code == http.StatusNotFound {
render.Render(w, r, response.ErrRender(data.MetaServerError.StatusCode, "The requested user could not be found"))
} else {
render.Render(w, r, response.ErrRender(data.MetaServerError.StatusCode, err.Error()))
}
o.logger.Error().Err(err).Str("userid", userid).Msg("could not get list of user groups")
return
}
}
_, err = o.getGroupsService().RemoveMember(r.Context(), &accounts.RemoveMemberRequest{
AccountId: account.Id,
GroupId: groupid,
})
if err != nil {
merr := merrors.FromError(err)
if merr.Code == http.StatusNotFound {
render.Render(w, r, response.ErrRender(data.MetaNotFound.StatusCode, "The requested user could not be found"))
render.Render(w, r, response.ErrRender(data.MetaNotFound.StatusCode, "The requested group could not be found"))
} else {
render.Render(w, r, response.ErrRender(data.MetaServerError.StatusCode, err.Error()))
}
@@ -175,3 +216,8 @@ func (o Ocs) GetGroupMembers(w http.ResponseWriter, r *http.Request) {
o.logger.Error().Err(err).Int("count", len(members)).Str("groupid", groupid).Msg("listing group members")
render.Render(w, r, response.DataRender(&data.Users{Users: members}))
}
func isValidUUID(uuid string) bool {
r := regexp.MustCompile("^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$")
return r.MatchString(uuid)
}

View File

@@ -1,6 +1,7 @@
package svc
import (
"context"
"crypto/rand"
"encoding/hex"
"fmt"
@@ -25,6 +26,8 @@ import (
func (o Ocs) GetUser(w http.ResponseWriter, r *http.Request) {
// TODO this endpoint needs authentication using the roles and permissions
userid := chi.URLParam(r, "userid")
var account *accounts.Account
var err error
if userid == "" {
u, ok := user.ContextGetUser(r.Context())
@@ -32,13 +35,12 @@ func (o Ocs) GetUser(w http.ResponseWriter, r *http.Request) {
render.Render(w, r, response.ErrRender(data.MetaBadRequest.StatusCode, "missing user in context"))
return
}
userid = u.Id.OpaqueId
account, err = o.getAccountService().GetAccount(r.Context(), &accounts.GetAccountRequest{
Id: u.Id.OpaqueId,
})
} else {
account, err = o.fetchAccountByUsername(r.Context(), userid)
}
account, err := o.getAccountService().GetAccount(r.Context(), &accounts.GetAccountRequest{
Id: userid,
})
if err != nil {
merr := merrors.FromError(err)
if merr.Code == http.StatusNotFound {
@@ -64,9 +66,8 @@ func (o Ocs) GetUser(w http.ResponseWriter, r *http.Request) {
enabled = "false"
}
render.Render(w, r, response.DataRender(&data.User{
UserID: account.Id, // TODO userid vs username! implications for clients if we return the userid here? -> implement graph ASAP?
Username: account.PreferredName,
d := &data.User{
UserID: account.PreferredName,
DisplayName: account.DisplayName,
LegacyDisplayName: account.DisplayName,
Email: account.Mail,
@@ -82,7 +83,8 @@ func (o Ocs) GetUser(w http.ResponseWriter, r *http.Request) {
Relative: 0.18,
Definition: "default",
},
}))
}
render.Render(w, r, response.DataRender(d))
}
// AddUser creates a new user account
@@ -90,7 +92,6 @@ func (o Ocs) AddUser(w http.ResponseWriter, r *http.Request) {
// TODO this endpoint needs authentication using the roles and permissions
userid := r.PostFormValue("userid")
password := r.PostFormValue("password")
username := r.PostFormValue("username")
displayname := r.PostFormValue("displayname")
email := r.PostFormValue("email")
uid := r.PostFormValue("uidnumber")
@@ -118,24 +119,20 @@ func (o Ocs) AddUser(w http.ResponseWriter, r *http.Request) {
// fallbacks
/* TODO decide if we want to make these fallbacks. Keep in mind:
- ocis requires a username and email
- the username should really be different from the userid
if username == "" {
username = userid
}
if displayname == "" {
displayname = username
}
- ocis requires a preferred_name and email
*/
if displayname == "" {
displayname = userid
}
newAccount := &accounts.Account{
Id: userid,
DisplayName: displayname,
PreferredName: username,
OnPremisesSamAccountName: username,
PreferredName: userid,
OnPremisesSamAccountName: userid,
PasswordProfile: &accounts.PasswordProfile{
Password: password,
},
Id: userid,
Mail: email,
AccountEnabled: true,
}
@@ -178,12 +175,11 @@ func (o Ocs) AddUser(w http.ResponseWriter, r *http.Request) {
}
render.Render(w, r, response.DataRender(&data.User{
UserID: account.Id,
Username: account.PreferredName,
DisplayName: account.DisplayName,
LegacyDisplayName: account.DisplayName,
Email: account.Mail,
UIDNumber: account.UidNumber,
GIDNumber: account.UidNumber,
GIDNumber: account.GidNumber,
Enabled: enabled,
}))
}
@@ -191,9 +187,22 @@ func (o Ocs) AddUser(w http.ResponseWriter, r *http.Request) {
// EditUser creates a new user account
func (o Ocs) EditUser(w http.ResponseWriter, r *http.Request) {
// TODO this endpoint needs authentication
userid := chi.URLParam(r, "userid")
account, err := o.fetchAccountByUsername(r.Context(), userid)
if err != nil {
merr := merrors.FromError(err)
if merr.Code == http.StatusNotFound {
render.Render(w, r, response.ErrRender(data.MetaNotFound.StatusCode, "The requested user could not be found"))
} else {
render.Render(w, r, response.ErrRender(data.MetaServerError.StatusCode, err.Error()))
}
o.logger.Error().Err(err).Str("userid", userid).Msg("could not edit user")
return
}
req := accounts.UpdateAccountRequest{
Account: &accounts.Account{
Id: chi.URLParam(r, "userid"),
Id: account.Id,
},
}
key := r.PostFormValue("key")
@@ -221,12 +230,10 @@ func (o Ocs) EditUser(w http.ResponseWriter, r *http.Request) {
return
}
account, err := o.getAccountService().UpdateAccount(r.Context(), &req)
account, err = o.getAccountService().UpdateAccount(r.Context(), &req)
if err != nil {
merr := merrors.FromError(err)
switch merr.Code {
case http.StatusNotFound:
render.Render(w, r, response.ErrRender(data.MetaNotFound.StatusCode, "The requested user could not be found"))
case http.StatusBadRequest:
render.Render(w, r, response.ErrRender(data.MetaBadRequest.StatusCode, merr.Detail))
default:
@@ -247,11 +254,24 @@ func (o Ocs) EditUser(w http.ResponseWriter, r *http.Request) {
// DeleteUser deletes a user
func (o Ocs) DeleteUser(w http.ResponseWriter, r *http.Request) {
req := accounts.DeleteAccountRequest{
Id: chi.URLParam(r, "userid"),
userid := chi.URLParam(r, "userid")
account, err := o.fetchAccountByUsername(r.Context(), userid)
if err != nil {
merr := merrors.FromError(err)
if merr.Code == http.StatusNotFound {
render.Render(w, r, response.ErrRender(data.MetaNotFound.StatusCode, "The requested user could not be found"))
} else {
render.Render(w, r, response.ErrRender(data.MetaServerError.StatusCode, err.Error()))
}
o.logger.Error().Err(err).Str("userid", userid).Msg("could not delete user")
return
}
_, err := o.getAccountService().DeleteAccount(r.Context(), &req)
req := accounts.DeleteAccountRequest{
Id: account.Id,
}
_, err = o.getAccountService().DeleteAccount(r.Context(), &req)
if err != nil {
merr := merrors.FromError(err)
if merr.Code == http.StatusNotFound {
@@ -344,7 +364,7 @@ func (o Ocs) ListUsers(w http.ResponseWriter, r *http.Request) {
search := r.URL.Query().Get("search")
query := ""
if search != "" {
query = fmt.Sprintf("id eq '%s' or on_premises_sam_account_name eq '%s'", escapeValue(search), escapeValue(search))
query = fmt.Sprintf("on_premises_sam_account_name eq '%s'", escapeValue(search))
}
res, err := o.getAccountService().ListAccounts(r.Context(), &accounts.ListAccountsRequest{
@@ -368,3 +388,17 @@ func (o Ocs) ListUsers(w http.ResponseWriter, r *http.Request) {
func escapeValue(value string) string {
return strings.ReplaceAll(value, "'", "''")
}
func (o Ocs) fetchAccountByUsername(ctx context.Context, name string) (*accounts.Account, error) {
var res *accounts.ListAccountsResponse
res, err := o.getAccountService().ListAccounts(ctx, &accounts.ListAccountsRequest{
Query: fmt.Sprintf("on_premises_sam_account_name eq '%v'", escapeValue(name)),
})
if err != nil {
return nil, err
}
if res != nil && len(res.Accounts) == 1 {
return res.Accounts[0], nil
}
return nil, merrors.NotFound("", "The requested user could not be found")
}

View File

@@ -7,8 +7,8 @@ require (
contrib.go.opencensus.io/exporter/ocagent v0.7.0
contrib.go.opencensus.io/exporter/zipkin v0.1.1
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/cs3org/go-cs3apis v0.0.0-20200810113633-b00aca449666
github.com/cs3org/reva v1.2.1-0.20200826162318-c0f54e1f37ea
github.com/cs3org/go-cs3apis v0.0.0-20200929101248-821df597ec8d
github.com/cs3org/reva v1.3.1-0.20201021065855-dc400f81ecbc
github.com/justinas/alice v1.2.0
github.com/micro/cli/v2 v2.1.2
github.com/micro/go-micro/v2 v2.9.1
@@ -23,10 +23,10 @@ require (
github.com/prometheus/client_golang v1.7.1
github.com/restic/calens v0.2.0
github.com/spf13/viper v1.7.0
go.opencensus.io v0.22.4
go.opencensus.io v0.22.5
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
google.golang.org/grpc v1.31.1
google.golang.org/grpc v1.32.0
)
replace (

View File

@@ -131,6 +131,7 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
github.com/ascarter/requestid v0.0.0-20170313220838-5b76ab3d4aee h1:3T/l+vMotQ7cDSLWNAn2Vg1SAQ3mdyLgBWWBitSS3uU=
github.com/ascarter/requestid v0.0.0-20170313220838-5b76ab3d4aee/go.mod h1:u7Wtt4WATGGgae9mURNGQQqxAudPKrxfsbSDSGOso+g=
github.com/asim/go-awsxray v0.0.0-20161209120537-0d8a60b6e205/go.mod h1:frVmN4PtXUuL1EbZn0uL4PHSTKNKFnbMpBIhngqMuNQ=
@@ -146,6 +147,8 @@ github.com/aws/aws-sdk-go v1.28.2/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN
github.com/aws/aws-sdk-go v1.29.26/go.mod h1:1KvfttTE3SPKMpo8g2c6jL3ZKfXtFvKscTgahTma5Xg=
github.com/aws/aws-sdk-go v1.33.19/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.34.2/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.34.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.35.9/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k=
github.com/aws/aws-xray-sdk-go v0.9.4/go.mod h1:XtMKdBQfpVut+tJEwI7+dJFRxxRdxHDyVNp2tHXRq04=
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
@@ -184,6 +187,7 @@ github.com/bwmarrin/discordgo v0.19.0/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVO
github.com/bwmarrin/discordgo v0.20.1/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
github.com/bwmarrin/discordgo v0.20.2/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
github.com/c-bata/go-prompt v0.2.3/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=
github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw=
github.com/caddyserver/certmagic v0.10.6/go.mod h1:Y8jcUBctgk/IhpAzlHKfimZNyXCkfGgRTC0orl8gROQ=
github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
@@ -260,17 +264,22 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
github.com/crewjam/httperr v0.0.0-20190612203328-a946449404da/go.mod h1:+rmNIXRvYMqLQeR4DHyTvs6y0MEMymTz4vyFpFkKTPs=
github.com/crewjam/saml v0.4.0/go.mod h1:geQUbAAwmTKNJFDzoXaTssZHY26O89PHIm3K3YWjWnI=
github.com/cs3org/cato v0.0.0-20200626150132-28a40e643719/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4=
github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4=
github.com/cs3org/go-cs3apis v0.0.0-20191128165347-19746c015c83/go.mod h1:IsVGyZrOLUQD48JIhlM/xb3Vz6He5o2+W0ZTfUGY+IU=
github.com/cs3org/go-cs3apis v0.0.0-20200306065539-29abc33f5be0/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/go-cs3apis v0.0.0-20200408065125-6e23f3ecec0a/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/go-cs3apis v0.0.0-20200730121022-c4f3d4f7ddfd/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/go-cs3apis v0.0.0-20200810113633-b00aca449666 h1:E7VsSSN/2YZLSwrDMJJdAWU11lP7W1qkcXbrslb0PM0=
github.com/cs3org/go-cs3apis v0.0.0-20200810113633-b00aca449666/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/go-cs3apis v0.0.0-20200929101248-821df597ec8d/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/reva v0.0.2-0.20200115110931-4c7513415ec5/go.mod h1:Hk3eCcdhtv4eIhKvRK736fQuOyS1HuHnUcz0Dq6NK1A=
github.com/cs3org/reva v0.1.0/go.mod h1:8j6QyyAq9Kjj7RPfJb7M1aEmw5DmsuCJKUULXxYOyRo=
github.com/cs3org/reva v1.1.0/go.mod h1:fBzTrNuAKdQ62ybjpdu8nyhBin90/3/3s6DGQDCdBp4=
github.com/cs3org/reva v1.2.1-0.20200826162318-c0f54e1f37ea h1:xVyJvR+GoaBrRJV6GnDflgm9bzkmjchCBBg0nMiHu6M=
github.com/cs3org/reva v1.2.1-0.20200826162318-c0f54e1f37ea/go.mod h1:FvYB+UPpuPCw0hH42qHVR1R2atZyy69METZI/zEaST8=
github.com/cs3org/reva v1.2.2-0.20200924071957-e6676516e61e/go.mod h1:DOV5SjpOBKN+aWfOHLdA4KiLQkpyC786PQaXEdRAZ0M=
github.com/cs3org/reva v1.3.1-0.20201021065855-dc400f81ecbc h1:8y6N/bscmzdXd4yAv6bIJiqggter8iEmb4cYMhuZkE8=
github.com/cs3org/reva v1.3.1-0.20201021065855-dc400f81ecbc/go.mod h1:rTJhfVoZggB5iSPH5oWqQSO+W1iTQIxNmaX/ueS9GAU=
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8=
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
github.com/cznic/strutil v0.0.0-20181122101858-275e90344537/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc=
@@ -282,8 +291,12 @@ github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14y
github.com/decker502/dnspod-go v0.2.0/go.mod h1:qsurYu1FgxcDwfSwXJdLt4kRsBLZeosEb9uq4Sy+08g=
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE=
github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY=
github.com/dgraph-io/ristretto v0.0.1/go.mod h1:T40EBc7CJke8TkpiYfGGKAeFjSaxuFXhuXRyumBd6RE=
github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
github.com/dnaeon/go-vcr v0.0.0-20180814043457-aafff18a5cc2/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
@@ -379,6 +392,7 @@ github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
github.com/go-ldap/ldap/v3 v3.1.7/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q=
github.com/go-ldap/ldap/v3 v3.2.3/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
github.com/go-ldap/ldap/v3 v3.2.4/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
github.com/go-log/log v0.1.0/go.mod h1:4mBwpdRMFLiuXZDCwU2lKQFsoSCo72j3HqBK9d81N2M=
github.com/go-log/log v0.2.0/go.mod h1:xzCnwajcues/6w7lne3yK2QU7DBPW7kqbgPGG5AF65U=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
@@ -621,6 +635,7 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
@@ -687,6 +702,7 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.0/go.mod h1:mJzapYve32yjrKlk9GbyCZHuPgZsrbyIbyKhSzOpg6s=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.1/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
@@ -748,6 +764,7 @@ github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/iancoleman/strcase v0.1.2/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4=
github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd/go.mod h1:3LVOLeyx9XVvwPgrt2be44XgSqndprz1G18rSk8KD84=
@@ -770,6 +787,8 @@ github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ=
github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
@@ -810,6 +829,7 @@ github.com/kolo/xmlrpc v0.0.0-20190717152603-07c4ee3fd181/go.mod h1:o03bZfuBwAXH
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
@@ -874,6 +894,7 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
@@ -888,8 +909,10 @@ github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsO
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
github.com/mattn/goveralls v0.0.5/go.mod h1:Xg2LHi51faXLyKXwsndxiW6uxEEQT9+3sjGzzwU4xy0=
github.com/mattn/goveralls v0.0.6/go.mod h1:h8b4ow6FxSPMQHF6o2ve3qsclnffZjYTNEKmLesRwqw=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103/go.mod h1:o9YPB5aGP8ob35Vy6+vyq3P3bWe7NQWzf+JLiXCiMaE=
@@ -954,6 +977,7 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F
github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
@@ -1050,13 +1074,17 @@ github.com/ory/fosite v0.29.0/go.mod h1:0atSZmXO7CAcs6NPMI/Qtot8tmZYj04Nddoold4S
github.com/ory/fosite v0.30.2/go.mod h1:Lq9qQ9Sl6mcea2Tt8J7PU+wUeFYPZ+vg7N3zPVKGbN8=
github.com/ory/fosite v0.30.4/go.mod h1:Lq9qQ9Sl6mcea2Tt8J7PU+wUeFYPZ+vg7N3zPVKGbN8=
github.com/ory/fosite v0.32.2/go.mod h1:UeBhRgW6nAjTcd8S7kAo0IFsY/rTPyOXPq/t8N20Q8I=
github.com/ory/fosite v0.33.0/go.mod h1:h+ize9gk0GvRyGjabriqSEmTkMhny+O95cijb8DVqPE=
github.com/ory/fosite v0.35.0/go.mod h1:h+ize9gk0GvRyGjabriqSEmTkMhny+O95cijb8DVqPE=
github.com/ory/go-acc v0.0.0-20181118080137-ddc355013f90/go.mod h1:sxnvPCxChFuSmTJGj8FdMupeq1BezCiEpDjTUXQ4hf4=
github.com/ory/go-acc v0.2.1/go.mod h1:0omgy2aa3nDBJ45VAKeLHH8ccPBudxLeic4xiDRtug0=
github.com/ory/go-acc v0.2.5/go.mod h1:4Kb/UnPcT8qRAk3IAxta+hvVapdxTLWtrr7bFLlEgpw=
github.com/ory/go-convenience v0.1.0/go.mod h1:uEY/a60PL5c12nYz4V5cHY03IBmwIAEm8TWB0yn9KNs=
github.com/ory/gojsonreference v0.0.0-20190720135523-6b606c2d8ee8/go.mod h1:wsH1C4nIeeQClDtD5AH7kF1uTS6zWyqfjVDTmB0Em7A=
github.com/ory/gojsonschema v1.1.1-0.20190919112458-f254ca73d5e9/go.mod h1:BNZpdJgB74KOLSsWFvzw6roXg1I6O51WO8roMmW+T7Y=
github.com/ory/herodot v0.6.2/go.mod h1:3BOneqcyBsVybCPAJoi92KN2BpJHcmDqAMcAAaJiJow=
github.com/ory/viper v1.5.6/go.mod h1:TYmpFpKLxjQwvT4f0QPpkOn4sDXU1kDgAwJpgLYiQ28=
github.com/ory/viper v1.7.5/go.mod h1:ypOuyJmEUb3oENywQZRgeAMwqgOyDqwboO1tj3DjTaM=
github.com/ory/x v0.0.85/go.mod h1:s44V8t3xyjWZREcU+mWlp4h302rTuM4aLXcW+y5FbQ8=
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ=
github.com/owncloud/flaex v0.0.0-20200411150708-dce59891a203/go.mod h1:jip86t4OVURJTf8CM/0e2qcji/Y4NG3l2lR8kex4JWw=
@@ -1100,6 +1128,7 @@ github.com/owncloud/ocis-store v0.1.1/go.mod h1:Rav5iw0fZXYFqJl81IbyTVa/FidaBhgV
github.com/owncloud/ocis-thumbnails v0.2.0/go.mod h1:97QGLawjcpbhSIscbPXJAytE6vAQi5Y+Ov55h8/mq+0=
github.com/owncloud/ocis-thumbnails v0.3.0/go.mod h1:97QGLawjcpbhSIscbPXJAytE6vAQi5Y+Ov55h8/mq+0=
github.com/owncloud/ocis-webdav v0.1.1/go.mod h1:E9OlGfvlxf1NHFOvFgbHWBe7/pw4Gqy/JaSJFEHQSzg=
github.com/owncloud/ocis/storage v0.0.0-20201015120921-38358ba4d4df/go.mod h1:s9kJvxtBlHEi5qc1TuPAdz2bprk9yGFe+FSOeC76Pbs=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
github.com/parnurzeal/gorequest v0.2.15/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE=
@@ -1114,6 +1143,7 @@ github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfS
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4=
github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs=
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
@@ -1123,7 +1153,9 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pkg/term v0.0.0-20200520122047-c3ffed290a03/go.mod h1:Z9+Ul5bCbBKnbCvdOWbLqTHhJiYV414CURZJba6L8qA=
github.com/pkg/term v1.1.0/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw=
github.com/pkg/xattr v0.4.1/go.mod h1:W2cGD0TBEus7MkUgv0tNZ9JutLtVO3cXu+IBRuHqnFs=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -1194,6 +1226,7 @@ github.com/rs/zerolog v1.17.2/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF
github.com/rs/zerolog v1.18.0/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF5+I=
github.com/rs/zerolog v1.19.0 h1:hYz4ZVdUgjXTBUmrkrw55j1nHx68LfOKIQk5IYtyScg=
github.com/rs/zerolog v1.19.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo=
github.com/rs/zerolog v1.20.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo=
github.com/rubenv/sql-migrate v0.0.0-20190212093014-1007f53448d7/go.mod h1:WS0rl9eEliYI8DPnr3TOwz4439pay+qNgzJoVya/DmY=
github.com/russellhaering/goxmldsig v0.0.0-20180430223755-7acd5e4a6ef7/go.mod h1:Oz4y6ImuOQZxynhbSXk7btjEfNBtGlj2dcaOvXl2FSM=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
@@ -1250,6 +1283,7 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B
github.com/spf13/afero v1.2.0/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/afero v1.3.2/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
@@ -1374,6 +1408,7 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
@@ -1425,6 +1460,7 @@ golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaE
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
@@ -1442,6 +1478,7 @@ golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -1607,17 +1644,20 @@ golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1627,10 +1667,14 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6 h1:DvY3Zkh7KabQE/kfzMvYvKirSiguP9Q/veMtkYyf0o8=
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1712,7 +1756,9 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200421042724-cfa8b22178d2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200427214658-4697a2867c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200526224456-8b020aee10d2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200721223218-6123e77877b2/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200811215021-48a8ffc5b207/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200817023811-d00afeaade8f/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1823,6 +1869,7 @@ gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.51.1 h1:GyboHr4UqMiLUybYjd22ZjQIKEJEpgtLXtuGbR21Oho=
gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo=
gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q=
gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4=
@@ -1844,6 +1891,7 @@ gopkg.in/square/go-jose.v2 v2.4.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76
gopkg.in/square/go-jose.v2 v2.4.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.5.0 h1:OZ4sdq+Y+SHfYB7vfthi1Ei8b0vkP8ZPQgUfUwdUSqo=
gopkg.in/square/go-jose.v2 v2.5.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=

View File

@@ -12,7 +12,6 @@
"apps": [
"files",
"draw-io",
"pdf-viewer",
"markdown-editor",
"media-viewer"
],

View File

@@ -1,4 +1,5 @@
package external
//
//import (
// "context"