mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-30 17:01:17 -05:00
Merge pull request #709 from owncloud/autoincrement-index
Autoincrement index
This commit is contained in:
133
.drone.star
133
.drone.star
@@ -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',
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
164
accounts/go.sum
164
accounts/go.sum
@@ -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=
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
35
accounts/pkg/indexer/errors/errors.go
Normal file
35
accounts/pkg/indexer/errors/errors.go
Normal 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
|
||||
}
|
||||
387
accounts/pkg/indexer/index/cs3/autoincrement.go
Normal file
387
accounts/pkg/indexer/index/cs3/autoincrement.go
Normal 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
|
||||
}
|
||||
83
accounts/pkg/indexer/index/cs3/autoincrement_test.go
Normal file
83
accounts/pkg/indexer/index/cs3/autoincrement_test.go
Normal 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",
|
||||
// },
|
||||
// },
|
||||
// }
|
||||
//}
|
||||
45
accounts/pkg/indexer/index/cs3/data_provider_client.go
Normal file
45
accounts/pkg/indexer/index/cs3/data_provider_client.go
Normal 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
|
||||
}
|
||||
410
accounts/pkg/indexer/index/cs3/non_unique.go
Normal file
410
accounts/pkg/indexer/index/cs3/non_unique.go
Normal 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
|
||||
}
|
||||
68
accounts/pkg/indexer/index/cs3/non_unique_test.go
Normal file
68
accounts/pkg/indexer/index/cs3/non_unique_test.go
Normal 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)
|
||||
//
|
||||
//}
|
||||
372
accounts/pkg/indexer/index/cs3/unique.go
Normal file
372
accounts/pkg/indexer/index/cs3/unique.go
Normal 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)
|
||||
}
|
||||
107
accounts/pkg/indexer/index/cs3/unique_test.go
Normal file
107
accounts/pkg/indexer/index/cs3/unique_test.go
Normal 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)
|
||||
//}
|
||||
262
accounts/pkg/indexer/index/disk/autoincrement.go
Normal file
262
accounts/pkg/indexer/index/disk/autoincrement.go
Normal 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
|
||||
}
|
||||
299
accounts/pkg/indexer/index/disk/autoincrement_test.go
Normal file
299
accounts/pkg/indexer/index/disk/autoincrement_test.go
Normal 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
|
||||
}
|
||||
235
accounts/pkg/indexer/index/disk/non_unique.go
Normal file
235
accounts/pkg/indexer/index/disk/non_unique.go
Normal 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
|
||||
}
|
||||
113
accounts/pkg/indexer/index/disk/non_unique_test.go
Normal file
113
accounts/pkg/indexer/index/disk/non_unique_test.go
Normal 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
|
||||
}
|
||||
222
accounts/pkg/indexer/index/disk/unique.go
Normal file
222
accounts/pkg/indexer/index/disk/unique.go
Normal 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
|
||||
}
|
||||
133
accounts/pkg/indexer/index/disk/unique_test.go
Normal file
133
accounts/pkg/indexer/index/disk/unique_test.go
Normal 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
|
||||
}
|
||||
16
accounts/pkg/indexer/index/index.go
Normal file
16
accounts/pkg/indexer/index/index.go
Normal 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
|
||||
}
|
||||
222
accounts/pkg/indexer/indexer.go
Normal file
222
accounts/pkg/indexer/indexer.go
Normal 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
|
||||
}
|
||||
275
accounts/pkg/indexer/indexer_test.go
Normal file
275
accounts/pkg/indexer/indexer_test.go
Normal 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,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
27
accounts/pkg/indexer/map.go
Normal file
27
accounts/pkg/indexer/map.go
Normal 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},
|
||||
},
|
||||
}
|
||||
}
|
||||
132
accounts/pkg/indexer/option/option.go
Normal file
132
accounts/pkg/indexer/option/option.go
Normal 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
|
||||
}
|
||||
}
|
||||
41
accounts/pkg/indexer/reflect.go
Normal file
41
accounts/pkg/indexer/reflect.go
Normal 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()))
|
||||
}
|
||||
53
accounts/pkg/indexer/reflect_test.go
Normal file
53
accounts/pkg/indexer/reflect_test.go
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
15
accounts/pkg/indexer/registry/registry.go
Normal file
15
accounts/pkg/indexer/registry/registry.go
Normal 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": {},
|
||||
}
|
||||
92
accounts/pkg/indexer/test/data.go
Normal file
92
accounts/pkg/indexer/test/data.go
Normal 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
|
||||
}
|
||||
48
accounts/pkg/indexer/test/helpers.go
Normal file
48
accounts/pkg/indexer/test/helpers.go
Normal 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
|
||||
}
|
||||
23
accounts/pkg/indexer/test/test.go
Normal file
23
accounts/pkg/indexer/test/test.go
Normal 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()}))
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -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.")
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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:
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
15
changelog/unreleased/accounts-fs-based-index.md
Normal file
15
changelog/unreleased/accounts-fs-based-index.md
Normal 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
|
||||
9
changelog/unreleased/ocs-map-userid-to-username.md
Normal file
9
changelog/unreleased/ocs-map-userid-to-username.md
Normal 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
|
||||
7
changelog/unreleased/prevent-duplicate-accounts.md
Normal file
7
changelog/unreleased/prevent-duplicate-accounts.md
Normal 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
|
||||
@@ -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`
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -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{}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
56
ocs/go.sum
56
ocs/go.sum
@@ -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=
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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"`
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
|
||||
48
proxy/go.sum
48
proxy/go.sum
@@ -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=
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
"apps": [
|
||||
"files",
|
||||
"draw-io",
|
||||
"pdf-viewer",
|
||||
"markdown-editor",
|
||||
"media-viewer"
|
||||
],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
package external
|
||||
|
||||
//
|
||||
//import (
|
||||
// "context"
|
||||
|
||||
Reference in New Issue
Block a user