Merge branch 'master' into config-housekeeping-proxy

This commit is contained in:
A.Unger
2020-11-04 15:11:46 +01:00
441 changed files with 38259 additions and 14384 deletions

View File

@@ -7,8 +7,12 @@ exclude_paths:
- 'docs/**'
- '**/docs/**'
- '**/pkg/proto/**'
- 'konnectd/assets/identifier/**'
- 'konnectd/ui_config/**'
- 'konnectd/scripts/**'
- 'settings/rollup.config.js'
- 'accounts/rollup.config.js'
- 'ocis/docker/eos-ocis/Dockerfile'
- 'ocis/docker/eos-ocis-dev/Dockerfile'
- 'deployments/**'
...
...

View File

@@ -15,12 +15,12 @@ config = {
},
'apiTests': {
'coreBranch': 'master',
'coreCommit': '35c53c096f40dd15ae15940c589965379e921857',
'numberOfParts': 4
'coreCommit': '6e5e252dcd18448709006cb2de6fe86cb6d0ecec',
'numberOfParts': 6
},
'uiTests': {
'phoenixBranch': 'master',
'phoenixCommit': '42c2a372aceb31eb17e13ebae08e2e25e2447dfe',
'phoenixCommit': '492e6a663efad67f770ba4ac405c4d9983d00cd3',
'suites': {
'phoenixWebUI1': [
'webUICreateFilesFolders',
@@ -38,12 +38,12 @@ config = {
'webUIRenameFiles',
'webUIRenameFolders',
],
'phoenixWebUI4': [
'phoenixWebUI4': [
'webUITrashbin',
'webUIUpload',
# All tests in the following suites are skipped currently
# so they won't run now but when they are enabled they will run
'webUIRestrictSharing',
],
'phoenixWebUI5': [
'webUISharingAutocompletion',
'webUISharingInternalGroups',
'webUISharingInternalUsers',
@@ -51,17 +51,27 @@ config = {
'webUISharingFilePermissionsGroups',
'webUISharingFolderPermissionsGroups',
'webUISharingFolderAdvancedPermissionsGroups',
],
'phoenixWebUI6': [
'webUIResharing',
'webUISharingPublic',
'webUISharingPublicDifferentRoles',
'webUISharingAcceptShares',
'webUISharingFilePermissionMultipleUsers',
'webUISharingFolderPermissionMultipleUsers',
'webUISharingFolderAdvancedPermissionMultipleUsers',
'webUISharingNotifications',
],
'phoenixWebUI7': [
'webUISharingFilePermissionMultipleUsers',
],
'phoenixWebUI8': [
'webUISharingFolderPermissionMultipleUsers',
'webUISharingFolderAdvancedPermissionMultipleUsers',
],
}
}
},
'rocketchat': {
'channel': 'ocis-internal',
'from_secret': 'private_rocketchat',
},
}
def getTestSuiteNames():
keys = config['modules'].keys()
@@ -84,13 +94,11 @@ def getCoreApiTestPipelineNames():
return names
def getDependsOnAllTestPipelines(ctx):
dependencies = getTestSuiteNames() + [ 'upload-coverage' ]
if ctx.build.ref != "refs/heads/master":
dependencies = getTestSuiteNames() + [
'upload-coverage',
'localApiTests-owncloud-storage',
'localApiTests-ocis-storage',
] + getCoreApiTestPipelineNames() + getUITestSuiteNames()
dependencies = getTestSuiteNames() + [
'upload-coverage',
'localApiTests-owncloud-storage',
'localApiTests-ocis-storage',
] + getCoreApiTestPipelineNames() + getUITestSuiteNames() + ['accountsUITests']
return dependencies
@@ -102,6 +110,7 @@ def main(ctx):
docker(ctx, 'amd64'),
docker(ctx, 'arm64'),
docker(ctx, 'arm'),
dockerEos(ctx),
binary(ctx, 'linux'),
binary(ctx, 'darwin'),
binary(ctx, 'windows'),
@@ -114,12 +123,18 @@ def main(ctx):
readme(ctx),
badges(ctx),
docs(ctx),
updateDeployment(ctx)
updateDeployment(ctx),
notify(ctx),
]
if '[docs-only]' in ctx.build.title:
pipelines = docs(ctx)
pipelines['depends_on'] = []
if '[docs-only]' in (ctx.build.title + ctx.build.message):
doc_pipelines = docs(ctx)
doc_pipelines['depends_on'] = []
notify_pipelines = notify(ctx)
notify_pipelines['depends_on'] = ['docs']
pipelines = [ doc_pipelines, notify_pipelines ]
else:
pipelines = before + stages + after
@@ -142,13 +157,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']))
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),
@@ -163,7 +179,7 @@ def testing(ctx, module):
},
{
'name': 'staticcheck',
'image': 'webhippie/golang:1.13',
'image': 'webhippie/golang:1.14',
'pull': 'always',
'commands': [
'cd %s' % (module),
@@ -178,7 +194,7 @@ def testing(ctx, module):
},
{
'name': 'lint',
'image': 'webhippie/golang:1.13',
'image': 'webhippie/golang:1.14',
'pull': 'always',
'commands': [
'cd %s' % (module),
@@ -193,7 +209,7 @@ def testing(ctx, module):
},
{
'name': 'test',
'image': 'webhippie/golang:1.13',
'image': 'webhippie/golang:1.14',
'pull': 'always',
'commands': [
'cd %s' % (module),
@@ -292,9 +308,9 @@ def uploadCoverage(ctx):
'SONAR_TOKEN': {
'from_secret': 'sonar_token',
},
'SONAR_PULL_REQUEST_BASE': 'master' if ctx.build.event == 'pull_request' else None,
'SONAR_PULL_REQUEST_BRANCH': ctx.build.source if ctx.build.event == 'pull_request' else None,
'SONAR_PULL_REQUEST_KEY': ctx.build.ref.replace("refs/pull/", "").split("/")[0] if ctx.build.event == 'pull_request' else None,
'SONAR_PULL_REQUEST_BASE': '%s' % ('master' if ctx.build.event == 'pull_request' else None),
'SONAR_PULL_REQUEST_BRANCH': '%s' % (ctx.build.source if ctx.build.event == 'pull_request' else None),
'SONAR_PULL_REQUEST_KEY': '%s' % (ctx.build.ref.replace("refs/pull/", "").split("/")[0] if ctx.build.event == 'pull_request' else None),
},
},
{
@@ -336,13 +352,14 @@ def localApiTests(ctx, coreBranch = 'master', coreCommit = '', storage = 'ownclo
cloneCoreRepos(coreBranch, coreCommit) + [
{
'name': 'localApiTests-%s-storage' % (storage),
'image': 'owncloudci/php:7.2',
'image': 'owncloudci/php:7.4',
'pull': 'always',
'environment' : {
'TEST_SERVER_URL': 'https://ocis-server:9200',
'OCIS_REVA_DATA_ROOT': '%s' % ('/srv/app/tmp/ocis/owncloud/' if storage == 'owncloud' else ''),
'DELETE_USER_DATA_CMD': '%s' % ('rm -rf /srv/app/tmp/ocis/owncloud/data/*' if storage == 'owncloud' else 'rm -rf /srv/app/tmp/ocis/storage/users/nodes/root/*'),
'OCIS_REVA_DATA_ROOT': '%s' % ('/srv/app/tmp/ocis/owncloud/data/' if storage == 'owncloud' else ''),
'DELETE_USER_DATA_CMD': '%s' % ('' if storage == 'owncloud' else 'rm -rf /srv/app/tmp/ocis/storage/users/nodes/root/* /srv/app/tmp/ocis/storage/users/nodes/*-*-*-*'),
'SKELETON_DIR': '/srv/app/tmp/testing/data/apiSkeleton',
'OCIS_SKELETON_STRATEGY': '%s' % ('copy' if storage == 'owncloud' else 'upload'),
'TEST_OCIS':'true',
'BEHAT_FILTER_TAGS': '~@skipOnOcis-%s-Storage' % ('OC' if storage == 'owncloud' else 'OCIS'),
'PATH_TO_CORE': '/srv/app/testrunner'
@@ -367,6 +384,7 @@ def localApiTests(ctx, coreBranch = 'master', coreCommit = '', storage = 'ownclo
],
'trigger': {
'ref': [
'refs/heads/master',
'refs/tags/v*',
'refs/pull/**',
],
@@ -389,13 +407,14 @@ def coreApiTests(ctx, coreBranch = 'master', coreCommit = '', part_number = 1, n
cloneCoreRepos(coreBranch, coreCommit) + [
{
'name': 'oC10ApiTests-%s-storage-%s' % (storage, part_number),
'image': 'owncloudci/php:7.2',
'image': 'owncloudci/php:7.4',
'pull': 'always',
'environment' : {
'TEST_SERVER_URL': 'https://ocis-server:9200',
'OCIS_REVA_DATA_ROOT': '%s' % ('/srv/app/tmp/ocis/owncloud/' if storage == 'owncloud' else ''),
'DELETE_USER_DATA_CMD': '%s' % ('rm -rf /srv/app/tmp/ocis/owncloud/*' if storage == 'owncloud' else 'rm -rf /srv/app/tmp/ocis/storage/users/nodes/root/*'),
'OCIS_REVA_DATA_ROOT': '%s' % ('/srv/app/tmp/ocis/owncloud/data/' if storage == 'owncloud' else ''),
'DELETE_USER_DATA_CMD': '%s' % ('' if storage == 'owncloud' else 'rm -rf /srv/app/tmp/ocis/storage/users/nodes/root/* /srv/app/tmp/ocis/storage/users/nodes/*-*-*-*'),
'SKELETON_DIR': '/srv/app/tmp/testing/data/apiSkeleton',
'OCIS_SKELETON_STRATEGY': '%s' % ('copy' if storage == 'owncloud' else 'upload'),
'TEST_OCIS':'true',
'BEHAT_FILTER_TAGS': '~@notToImplementOnOCIS&&~@toImplementOnOCIS&&~comments-app-required&&~@federation-app-required&&~@notifications-app-required&&~systemtags-app-required&&~@local_storage&&~@skipOnOcis-%s-Storage' % ('OC' if storage == 'owncloud' else 'OCIS'),
'DIVIDE_INTO_NUM_PARTS': number_of_parts,
@@ -422,6 +441,7 @@ def coreApiTests(ctx, coreBranch = 'master', coreCommit = '', part_number = 1, n
],
'trigger': {
'ref': [
'refs/heads/master',
'refs/tags/v*',
'refs/pull/**',
],
@@ -458,7 +478,7 @@ def uiTestPipeline(suiteName, phoenixBranch = 'master', phoenixCommit = '', stor
'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/ocis/tests/config/drone/ocis-config.json',
'TEST_TAGS': 'not @skipOnOCIS and not @skip',
@@ -502,6 +522,100 @@ def uiTestPipeline(suiteName, phoenixBranch = 'master', phoenixCommit = '', stor
],
'trigger': {
'ref': [
'refs/heads/master',
'refs/tags/v*',
'refs/pull/**',
],
},
}
def accountsUITests(ctx, phoenixBranch, phoenixCommit, storage = 'owncloud'):
return {
'kind': 'pipeline',
'type': 'docker',
'name': 'accountsUITests',
'platform': {
'os': 'linux',
'arch': 'amd64',
},
'steps':
generate('ocis') +
build() +
ocisServer(storage) + [
{
'name': 'WebUIAcceptanceTests',
'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/data',
'OCIS_SKELETON_DIR': '/srv/app/testing/data/webUISkeleton',
'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',
},
'commands': [
'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'
}],
},
],
'services': [
{
'name': 'redis',
'image': 'webhippie/redis',
'pull': 'always',
'environment': {
'REDIS_DATABASES': 1
},
},
{
'name': 'selenium',
'image': 'selenium/standalone-chrome-debug:3.141.59-20200326',
'pull': 'always',
'volumes': [
{
'name': 'uploads',
'path': '/uploads'
}
],
},
],
'volumes': [
{
'name': 'gopath',
'temp': {},
},
{
'name': 'uploads',
'temp': {}
}
],
'trigger': {
'ref': [
'refs/heads/master',
'refs/tags/v*',
'refs/pull/**',
],
@@ -581,6 +695,78 @@ def docker(ctx, arch):
},
}
def dockerEos(ctx):
return {
'kind': 'pipeline',
'type': 'docker',
'name': 'docker-eos-ocis',
'platform': {
'os': 'linux',
'arch': 'amd64',
},
'steps':
generate('ocis') +
build() + [
{
'name': 'dryrun-eos-ocis',
'image': 'plugins/docker:18.09',
'pull': 'always',
'settings': {
'dry_run': True,
'context': 'ocis/docker/eos-ocis',
'tags': 'linux-eos-ocis',
'dockerfile': 'ocis/docker/eos-ocis/Dockerfile',
'repo': 'owncloud/eos-ocis',
},
'when': {
'ref': {
'include': [
'refs/pull/**',
],
},
},
},
{
'name': 'docker-eos-ocis',
'image': 'plugins/docker:18.09',
'pull': 'always',
'settings': {
'username': {
'from_secret': 'docker_username',
},
'password': {
'from_secret': 'docker_password',
},
'auto_tag': True,
'context': 'ocis/docker/eos-ocis',
'dockerfile': 'ocis/docker/eos-ocis/Dockerfile',
'repo': 'owncloud/eos-ocis',
},
'when': {
'ref': {
'exclude': [
'refs/pull/**',
],
},
},
},
],
'volumes': [
{
'name': 'gopath',
'temp': {},
},
],
'depends_on': getDependsOnAllTestPipelines(ctx),
'trigger': {
'ref': [
'refs/heads/master',
'refs/tags/v*',
'refs/pull/**',
],
},
}
def binary(ctx, name):
if ctx.build.event == "tag":
settings = {
@@ -633,7 +819,7 @@ def binary(ctx, name):
generate('ocis') + [
{
'name': 'build',
'image': 'webhippie/golang:1.13',
'image': 'webhippie/golang:1.14',
'pull': 'always',
'commands': [
'cd ocis',
@@ -648,7 +834,7 @@ def binary(ctx, name):
},
{
'name': 'finish',
'image': 'webhippie/golang:1.13',
'image': 'webhippie/golang:1.14',
'pull': 'always',
'commands': [
'cd ocis',
@@ -684,8 +870,7 @@ def binary(ctx, name):
'image': 'toolhippie/calens:latest',
'pull': 'always',
'commands': [
'cd ocis',
'calens --version %s -o dist/CHANGELOG.md' % ctx.build.ref.replace("refs/tags/v", "").split("-")[0],
'calens --version %s -o ocis/dist/CHANGELOG.md' % ctx.build.ref.replace("refs/tags/v", "").split("-")[0],
],
'when': {
'ref': [
@@ -814,6 +999,7 @@ def manifest(ctx):
'docker-amd64',
'docker-arm64',
'docker-arm',
'docker-eos-ocis',
'binaries-linux',
'binaries-darwin',
'binaries-windows',
@@ -838,7 +1024,7 @@ def changelog(ctx):
'steps': [
{
'name': 'generate',
'image': 'webhippie/golang:1.13',
'image': 'webhippie/golang:1.14',
'pull': 'always',
'commands': [
'cd ocis',
@@ -968,6 +1154,7 @@ def badges(ctx):
'docker-amd64',
'docker-arm64',
'docker-arm',
'docker-eos-ocis',
],
'trigger': {
'ref': [
@@ -1001,7 +1188,7 @@ def docs(ctx):
},
{
'name': 'generate-config-docs',
'image': 'webhippie/golang:1.13',
'image': 'webhippie/golang:1.14',
'commands': generateConfigDocs,
'volumes': [
{
@@ -1089,7 +1276,7 @@ def generate(module):
return [
{
'name': 'generate',
'image': 'webhippie/golang:1.13',
'image': 'webhippie/golang:1.14',
'pull': 'always',
'commands': [
'cd %s' % (module),
@@ -1144,6 +1331,42 @@ def updateDeployment(ctx):
}
}
def notify(ctx):
return {
'kind': 'pipeline',
'type': 'docker',
'name': 'chat-notifications',
'clone': {
'disable': True
},
'steps': [
{
'name': 'notify-rocketchat',
'image': 'plugins/slack:1',
'pull': 'always',
'settings': {
'webhook': {
'from_secret': config['rocketchat']['from_secret']
},
'channel': config['rocketchat']['channel']
},
'when': {
'status': [
'failure',
],
},
},
],
'depends_on': [],
'trigger': {
'ref': [
'refs/heads/master',
'refs/heads/release*',
'refs/tags/**',
],
}
}
def frontend(module):
return [
{
@@ -1164,32 +1387,29 @@ def ocisServer(storage):
return [
{
'name': 'ocis-server',
'image': 'webhippie/golang:1.13',
'image': 'webhippie/golang:1.14',
'pull': 'always',
'detach': True,
'environment' : {
#'OCIS_LOG_LEVEL': 'debug',
'STORAGE_STORAGE_HOME_DRIVER': '%s' % (storage),
'STORAGE_STORAGE_HOME_DATA_DRIVER': '%s' % (storage),
'STORAGE_STORAGE_OC_DRIVER': '%s' % (storage),
'STORAGE_STORAGE_OC_DATA_DRIVER': '%s' % (storage),
'STORAGE_STORAGE_HOME_DATA_TEMP_FOLDER': '/srv/app/tmp/',
'STORAGE_STORAGE_OCIS_ROOT': '/srv/app/tmp/ocis/storage/users',
'STORAGE_STORAGE_LOCAL_ROOT': '/srv/app/tmp/ocis/local/root',
'STORAGE_STORAGE_OWNCLOUD_DATADIR': '/srv/app/tmp/ocis/owncloud/data',
'STORAGE_STORAGE_OC_DATA_TEMP_FOLDER': '/srv/app/tmp/',
'STORAGE_STORAGE_OWNCLOUD_REDIS_ADDR': 'redis:6379',
'STORAGE_HOME_DRIVER': '%s' % (storage),
'STORAGE_USERS_DRIVER': '%s' % (storage),
'STORAGE_DRIVER_OCIS_ROOT': '/srv/app/tmp/ocis/storage/users',
'STORAGE_DRIVER_LOCAL_ROOT': '/srv/app/tmp/ocis/local/root',
'STORAGE_METADATA_ROOT': '/srv/app/tmp/ocis/metadata',
'STORAGE_DRIVER_OWNCLOUD_DATADIR': '/srv/app/tmp/ocis/owncloud/data',
'STORAGE_DRIVER_OWNCLOUD_REDIS_ADDR': 'redis:6379',
'STORAGE_LDAP_IDP': 'https://ocis-server:9200',
'STORAGE_OIDC_ISSUER': 'https://ocis-server:9200',
'PROXY_OIDC_ISSUER': 'https://ocis-server:9200',
'STORAGE_STORAGE_OC_DATA_SERVER_URL': 'http://ocis-server:9164/data',
'STORAGE_DATAGATEWAY_URL': 'https://ocis-server:9200/data',
'STORAGE_FRONTEND_URL': 'https://ocis-server:9200',
'STORAGE_HOME_DATA_SERVER_URL': 'http://ocis-server:9155/data',
'STORAGE_DATAGATEWAY_PUBLIC_URL': 'https://ocis-server:9200/data',
'STORAGE_USERS_DATA_SERVER_URL': 'http://ocis-server:9158/data',
'STORAGE_FRONTEND_PUBLIC_URL': 'https://ocis-server:9200',
'PHOENIX_WEB_CONFIG': '/drone/src/ocis/tests/config/drone/ocis-config.json',
'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
@@ -1210,7 +1430,7 @@ def cloneCoreRepos(coreBranch, coreCommit):
return [
{
'name': 'clone-core-repos',
'image': 'owncloudci/php:7.2',
'image': 'owncloudci/php:7.4',
'pull': 'always',
'commands': [
'git clone -b master --depth=1 https://github.com/owncloud/testing.git /srv/app/tmp/testing',
@@ -1255,7 +1475,7 @@ def build():
return [
{
'name': 'build',
'image': 'webhippie/golang:1.13',
'image': 'webhippie/golang:1.14',
'pull': 'always',
'commands': [
'cd ocis',

5
.gitignore vendored
View File

@@ -10,3 +10,8 @@ node_modules/
*/assets
.idea
*/yarn-error.log
# Konnectd
konnectd/assets/identifier

View File

@@ -4,10 +4,18 @@
* Bugfix - Add missing env vars to docker compose: [#392](https://github.com/owncloud/ocis/pull/392)
* Bugfix - Don't enforce empty external apps slice: [#473](https://github.com/owncloud/ocis/pull/473)
* Bugfix - Lower Bound was not working for the cs3 api index implementation: [#741](https://github.com/owncloud/ocis/pull/741)
* Bugfix - Fix button layout after phoenix update: [#625](https://github.com/owncloud/ocis/pull/625)
* Bugfix - Fix id or username query handling: [#745](https://github.com/owncloud/ocis/pull/745)
* Bugfix - Use micro default client: [#718](https://github.com/owncloud/ocis/pull/718)
* Bugfix - Allow consent-prompt with switch-account: [#788](https://github.com/owncloud/ocis/pull/788)
* Bugfix - Mint token with uid and gid: [#737](https://github.com/owncloud/ocis/pull/737)
* Bugfix - Don't create account if id/mail/username already taken: [#709](https://github.com/owncloud/ocis/pull/709)
* Bugfix - Fix director selection in proxy: [#521](https://github.com/owncloud/ocis/pull/521)
* Bugfix - Build docker images with alpine:latest instead of alpine:edge: [#416](https://github.com/owncloud/ocis/pull/416)
* Change - Accounts UI shows message when no permissions: [#656](https://github.com/owncloud/ocis/pull/656)
* Change - Filesystem based index: [#709](https://github.com/owncloud/ocis/pull/709)
* Change - Rebuild index command for accounts: [#748](https://github.com/owncloud/ocis/pull/748)
* Change - Add the thumbnails command: [#156](https://github.com/owncloud/ocis/issues/156)
* Change - Choose disk or cs3 storage for accounts and groups: [#623](https://github.com/owncloud/ocis/pull/623)
* Change - Integrate import command from ocis-migration: [#249](https://github.com/owncloud/ocis/pull/249)
@@ -15,12 +23,22 @@
* Change - Initial release of basic version: [#2](https://github.com/owncloud/ocis/issues/2)
* Change - Add cli-commands to manage accounts: [#115](https://github.com/owncloud/product/issues/115)
* Change - Start ocis-accounts with the ocis server command: [#25](https://github.com/owncloud/product/issues/25)
* Change - Properly style konnectd consent page: [#754](https://github.com/owncloud/ocis/pull/754)
* Change - Move the indexer package from ocis/accounts to ocis/ocis-pkg: [#794](https://github.com/owncloud/ocis/pull/794)
* Change - Switch over to a new custom-built runtime: [#287](https://github.com/owncloud/ocis/pull/287)
* Change - Remove username field in OCS: [#709](https://github.com/owncloud/ocis/pull/709)
* Change - Account management permissions for Admin role: [#124](https://github.com/owncloud/product/issues/124)
* Change - Update phoenix to v0.18.0: [#651](https://github.com/owncloud/ocis/pull/651)
* Change - Default apps in ownCloud Web: [#688](https://github.com/owncloud/ocis/pull/688)
* Change - Make ocis-settings available: [#287](https://github.com/owncloud/ocis/pull/287)
* Change - Start ocis-proxy with the ocis server command: [#119](https://github.com/owncloud/ocis/issues/119)
* Change - Bring oC theme: [#698](https://github.com/owncloud/ocis/pull/698)
* Change - Update phoenix to v0.20.0: [#674](https://github.com/owncloud/ocis/pull/674)
* Change - Update phoenix to v0.21.0: [#728](https://github.com/owncloud/ocis/pull/728)
* Change - Update phoenix to v0.22.0: [#757](https://github.com/owncloud/ocis/pull/757)
* Change - Update phoenix to v0.23.0: [#785](https://github.com/owncloud/ocis/pull/785)
* Change - Update reva config: [#336](https://github.com/owncloud/ocis/pull/336)
* Change - Clarify storage driver env vars: [#729](https://github.com/owncloud/ocis/pull/729)
* Change - Settings and accounts appear in the user menu: [#656](https://github.com/owncloud/ocis/pull/656)
* Enhancement - Add the accounts service: [#244](https://github.com/owncloud/product/issues/244)
* Enhancement - Document how to run OCIS on top of EOS: [#172](https://github.com/owncloud/ocis/pull/172)
@@ -39,6 +57,10 @@
* Enhancement - Add glauth fallback backend: [#649](https://github.com/owncloud/ocis/pull/649)
* Enhancement - Launch a storage to store ocis-metadata: [#602](https://github.com/owncloud/ocis/pull/602)
* Enhancement - Simplify tracing config: [#92](https://github.com/owncloud/product/issues/92)
* Enhancement - Update glauth to dev 4f029234b2308: [#786](https://github.com/owncloud/ocis/pull/786)
* Enhancement - Update konnectd to v0.33.8: [#744](https://github.com/owncloud/ocis/pull/744)
* Enhancement - Update reva to cdb3d6688da5: [#748](https://github.com/owncloud/ocis/pull/748)
* Enhancement - Update reva to dd3a8c0f38: [#725](https://github.com/owncloud/ocis/pull/725)
## Details
@@ -60,6 +82,14 @@
https://github.com/owncloud/ocis/pull/473
* Bugfix - Lower Bound was not working for the cs3 api index implementation: [#741](https://github.com/owncloud/ocis/pull/741)
Tags: accounts
Lower bound working on the cs3 index implementation
https://github.com/owncloud/ocis/pull/741
* Bugfix - Fix button layout after phoenix update: [#625](https://github.com/owncloud/ocis/pull/625)
Tags: accounts
@@ -70,6 +100,51 @@
https://github.com/owncloud/ocis/pull/625
* Bugfix - Fix id or username query handling: [#745](https://github.com/owncloud/ocis/pull/745)
Tags: accounts
The code was stopping execution when encountering an error while loading an account by id. But
for or queries we can continue execution.
https://github.com/owncloud/ocis/pull/745
* Bugfix - Use micro default client: [#718](https://github.com/owncloud/ocis/pull/718)
Tags: glauth
We found a file descriptor leak in the glauth connections to the accounts service. Fixed it by
using the micro default client.
https://github.com/owncloud/ocis/pull/718
* Bugfix - Allow consent-prompt with switch-account: [#788](https://github.com/owncloud/ocis/pull/788)
Multiple prompt values are allowed and this change fixes the check for select_account if it was
used together with other prompt values. Where select_account previously was ignored, it is
now processed as required, fixing the use case when a RP wants to trigger select_account first
while at the same time wants also to request interactive consent.
https://github.com/owncloud/ocis/pull/788
* Bugfix - Mint token with uid and gid: [#737](https://github.com/owncloud/ocis/pull/737)
Tags: accounts
The eos driver expects the uid and gid from the opaque map of a user. While the proxy does mint
tokens correctly, the accounts service wasn't.
https://github.com/owncloud/ocis/pull/737
* Bugfix - Don't create account if id/mail/username already taken: [#709](https://github.com/owncloud/ocis/pull/709)
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
* Bugfix - Fix director selection in proxy: [#521](https://github.com/owncloud/ocis/pull/521)
Tags: proxy
@@ -96,6 +171,35 @@
https://github.com/owncloud/ocis/pull/656
* Change - Filesystem based index: [#709](https://github.com/owncloud/ocis/pull/709)
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
* Change - Rebuild index command for accounts: [#748](https://github.com/owncloud/ocis/pull/748)
Tags: accounts
The index for the accounts service can now be rebuilt by running the cli command `./bin/ocis
accounts rebuild`. It deletes all configured indices and rebuilds them from the documents
found on storage. For this we also introduced a `LoadAccounts` and `LoadGroups` function on
storage for loading all existing documents.
https://github.com/owncloud/ocis/pull/748
* Change - Add the thumbnails command: [#156](https://github.com/owncloud/ocis/issues/156)
Tags: thumbnails
@@ -162,6 +266,22 @@
https://github.com/owncloud/product/issues/25
https://github.com/owncloud/ocis/pull/239/files
* Change - Properly style konnectd consent page: [#754](https://github.com/owncloud/ocis/pull/754)
Tags: konnectd
After bringing our theme into konnectd, we've had to adjust the styles of the consent page so the
text is visible and button reflects our theme.
https://github.com/owncloud/ocis/pull/754
* Change - Move the indexer package from ocis/accounts to ocis/ocis-pkg: [#794](https://github.com/owncloud/ocis/pull/794)
We are making that change for semantic reasons. So consumers of any index don't necessarily
need to know of the accounts service.
https://github.com/owncloud/ocis/pull/794
* Change - Switch over to a new custom-built runtime: [#287](https://github.com/owncloud/ocis/pull/287)
We moved away from using the go-micro runtime and are now using [our own
@@ -171,6 +291,17 @@
https://github.com/owncloud/ocis/pull/287
* Change - Remove username field in OCS: [#709](https://github.com/owncloud/ocis/pull/709)
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
* Change - Account management permissions for Admin role: [#124](https://github.com/owncloud/product/issues/124)
Tags: accounts, settings
@@ -209,6 +340,15 @@
https://github.com/owncloud/phoenix/releases/tag/v0.18.0
https://github.com/owncloud/owncloud-design-system/releases/tag/v1.12.1
* Change - Default apps in ownCloud Web: [#688](https://github.com/owncloud/ocis/pull/688)
Tags: web
We changed the default apps for ownCloud Web to be only files and media-viewer.
Markdown-editor and draw-io have been removed as defaults.
https://github.com/owncloud/ocis/pull/688
* Change - Make ocis-settings available: [#287](https://github.com/owncloud/ocis/pull/287)
Tags: settings
@@ -228,6 +368,54 @@
https://github.com/owncloud/ocis/issues/119
https://github.com/owncloud/ocis/issues/136
* Change - Bring oC theme: [#698](https://github.com/owncloud/ocis/pull/698)
Tags: konnectd
We've styled our konnectd login page to reflect ownCloud theme.
https://github.com/owncloud/ocis/pull/698
* Change - Update phoenix to v0.20.0: [#674](https://github.com/owncloud/ocis/pull/674)
Tags: web
We updated phoenix to v0.20.0. Please refer to the changelog (linked) for details on the
phoenix release.
https://github.com/owncloud/ocis/pull/674
https://github.com/owncloud/phoenix/releases/tag/v0.20.0
* Change - Update phoenix to v0.21.0: [#728](https://github.com/owncloud/ocis/pull/728)
Tags: web
We updated phoenix to v0.21.0. Please refer to the changelog (linked) for details on the
phoenix release.
https://github.com/owncloud/ocis/pull/728
https://github.com/owncloud/phoenix/releases/tag/v0.21.0
* Change - Update phoenix to v0.22.0: [#757](https://github.com/owncloud/ocis/pull/757)
Tags: web
We updated phoenix to v0.22.0. Please refer to the changelog (linked) for details on the
phoenix release.
https://github.com/owncloud/ocis/pull/757
https://github.com/owncloud/phoenix/releases/tag/v0.22.0
* Change - Update phoenix to v0.23.0: [#785](https://github.com/owncloud/ocis/pull/785)
Tags: web
We updated phoenix to v0.23.0. Please refer to the changelog (linked) for details on the
phoenix release.
https://github.com/owncloud/ocis/pull/785
https://github.com/owncloud/phoenix/releases/tag/v0.23.0
* Change - Update reva config: [#336](https://github.com/owncloud/ocis/pull/336)
* EOS homes are not configured with an enable-flag anymore, but with a dedicated storage driver.
@@ -238,6 +426,16 @@
https://github.com/owncloud/ocis/pull/338
https://github.com/owncloud/ocis-reva/pull/891
* Change - Clarify storage driver env vars: [#729](https://github.com/owncloud/ocis/pull/729)
After renaming ocsi-reva to storage and combining the storage and data providers some env vars
were confusingly named `STORAGE_STORAGE_...`. We are changing the prefix for driver related
env vars to `STORAGE_DRIVER_...`. This makes changing the storage driver using eg.:
`STORAGE_HOME_DRIVER=eos` and setting driver options using
`STORAGE_DRIVER_EOS_LAYOUT=...` less confusing.
https://github.com/owncloud/ocis/pull/729
* Change - Settings and accounts appear in the user menu: [#656](https://github.com/owncloud/ocis/pull/656)
We moved settings and accounts to the user menu.
@@ -1239,3 +1437,45 @@
https://github.com/owncloud/product/issues/92
https://github.com/owncloud/ocis/pull/329
https://github.com/owncloud/ocis/pull/409
* Enhancement - Update glauth to dev 4f029234b2308: [#786](https://github.com/owncloud/ocis/pull/786)
Includes a bugfix, don't mix graph and provisioning api.
https://github.com/owncloud/ocis/pull/786
* Enhancement - Update konnectd to v0.33.8: [#744](https://github.com/owncloud/ocis/pull/744)
This update adds options which allow the configuration of oidc-token expiration parameters:
KONNECTD_ACCESS_TOKEN_EXPIRATION, KONNECTD_ID_TOKEN_EXPIRATION and
KONNECTD_REFRESH_TOKEN_EXPIRATION.
Other changes from upstream:
- Generate random endsession state for external authority - Update dependencies in
Dockerfile - Set prompt=None to avoid loops with external authority - Update Jenkins
reporting plugin from checkstyle to recordIssues - Remove extra kty key from JWKS top level
document - Fix regression which encodes URL fragments twice - Avoid generating fragmet/query
URLs with wrong order - Return state for oidc endsession response redirects - Use server
provided username to avoid case mismatch - Use signed-out-uri if set as fallback for goodbye
redirect on saml slo - Add checks to ensure post_logout_redirect_uri is not empty - Fix SAML2
logout request parsing - Cure panic when no state is found in saml esr - Use SAML IdP Issuer value
from meta data entityID - Allow configuration of expiration of oidc access, id and refresh
tokens - Implement trampolin for external OIDC authority end session - Update
ca-certificates version
https://github.com/owncloud/ocis/pull/744
* Enhancement - Update reva to cdb3d6688da5: [#748](https://github.com/owncloud/ocis/pull/748)
* let the gateway filter invalid references
https://github.com/owncloud/ocis/pull/748
https://github.com/cs3org/reva/pull/1274
* Enhancement - Update reva to dd3a8c0f38: [#725](https://github.com/owncloud/ocis/pull/725)
* fixes etag propagation in the ocis driver
https://github.com/owncloud/ocis/pull/725
https://github.com/cs3org/reva/pull/1264

View File

@@ -156,8 +156,8 @@ $(GOPATH)/bin/protoc-gen-micro:
$(GOPATH)/bin/protoc-gen-microweb:
GO111MODULE=off go get -v github.com/owncloud/protoc-gen-microweb
$(GOPATH)/bin/protoc-gen-swagger:
GO111MODULE=off go get -v github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger
$(GOPATH)/bin/protoc-gen-openapiv2:
GO111MODULE=off go get -v github.com/grpc-ecosystem/grpc-gateway/protoc-gen-openapiv2
$(PROTO_SRC)/accounts.pb.go: $(PROTO_SRC)/accounts.proto
protoc \
@@ -186,5 +186,5 @@ $(PROTO_SRC)/accounts.swagger.json: $(PROTO_SRC)/accounts.proto
--swagger_out=$(PROTO_SRC) accounts.proto
.PHONY: protobuf
protobuf: $(GOPATH)/bin/protoc-gen-go $(GOPATH)/bin/protoc-gen-micro $(GOPATH)/bin/protoc-gen-microweb $(GOPATH)/bin/protoc-gen-swagger \
protobuf: $(GOPATH)/bin/protoc-gen-go $(GOPATH)/bin/protoc-gen-micro $(GOPATH)/bin/protoc-gen-microweb $(GOPATH)/bin/protoc-gen-openapiv2 \
$(PROTO_SRC)/accounts.pb.go $(PROTO_SRC)/accounts.pb.micro.go $(PROTO_SRC)/accounts.pb.web.go $(PROTO_SRC)/accounts.swagger.json

View File

@@ -3,43 +3,39 @@ 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/CiscoM31/godata v0.0.0-20201003040028-eadcd34e7f06 // indirect
github.com/cs3org/go-cs3apis v0.0.0-20201007120910-416ed6cf8b00
github.com/cs3org/reva v1.3.1-0.20201023144216-cdb3d6688da5
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/mennanov/fieldmask-utils v0.3.2
github.com/golang/protobuf v1.4.3
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 // indirect
github.com/iancoleman/strcase v0.1.2 // indirect
github.com/mennanov/fieldmask-utils v0.3.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
github.com/olekukonko/tablewriter v0.0.4
github.com/owncloud/ocis/ocis-pkg v0.0.0-20200918114005-1a0ddd2190ee
github.com/owncloud/ocis v1.0.0-rc3.0.20201103111659-46bf133a3c63 // indirect
github.com/owncloud/ocis/ocis-pkg v0.0.0-20201103111659-46bf133a3c63
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 // indirect
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.33.1
google.golang.org/protobuf v1.25.0
)
replace (
github.com/owncloud/ocis/ocis-pkg => ../ocis-pkg
github.com/owncloud/ocis/settings => ../settings
github.com/owncloud/ocis/storage => ../storage
google.golang.org/grpc => google.golang.org/grpc v1.26.0
)

View File

@@ -50,8 +50,8 @@ 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/CiscoM31/godata v0.0.0-20201003040028-eadcd34e7f06 h1:FKxVU/j9Dd8Je0YkVkm8Fxpz9zIeN21SEkcbzA6NWgY=
github.com/CiscoM31/godata v0.0.0-20201003040028-eadcd34e7f06/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 +68,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 +102,17 @@ 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-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/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
@@ -120,26 +124,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 +131,8 @@ 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/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw=
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 +148,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 +187,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 +196,30 @@ 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/go-cs3apis v0.0.0-20201007120910-416ed6cf8b00 h1:LVl25JaflluOchVvaHWtoCynm5OaM+VNai0IYkcCSe0=
github.com/cs3org/go-cs3apis v0.0.0-20201007120910-416ed6cf8b00/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/cs3org/reva v1.3.1-0.20201023144216-cdb3d6688da5 h1:nkmk9ywGKpJthWeMYGBiXh4DD6mTCOZLRfGDjp9rsKg=
github.com/cs3org/reva v1.3.1-0.20201023144216-cdb3d6688da5/go.mod h1:V50GXMiT524bvxACFkrkZqBzK4BoXLSprxcPshBlSOY=
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 +246,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 +255,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 +264,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=
@@ -306,6 +291,7 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
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/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
@@ -517,6 +503,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=
@@ -533,9 +520,10 @@ 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=
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 +549,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 +579,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 +624,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 +643,8 @@ 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/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/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 +677,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,26 +731,40 @@ 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-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
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.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=
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=
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
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 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=
github.com/mennanov/fieldmask-utils v0.3.2/go.mod h1:JpaanSp6Ql5A8dGktEFxTmA9uBXmz3F+2LAXDZwiimU=
github.com/mennanov/fieldmask-utils v0.3.3 h1:/cAjLk3ja74dQJ0BBxEsK4xyzvECcOYLLB1lo6HuLog=
github.com/mennanov/fieldmask-utils v0.3.3/go.mod h1:OcOWam4DG685inAjtNuFONKpkitiCCK1W5yKljvWwCY=
github.com/micro/cli/v2 v2.1.2 h1:43J1lChg/rZCC1rvdqZNFSQDrGT7qfMrtp6/ztpIkEM=
github.com/micro/cli/v2 v2.1.2/go.mod h1:EguNh6DAoWKm9nmk+k/Rg0H3lQnDxqzu5x5srOtGtYg=
github.com/micro/go-micro/v2 v2.9.1 h1:+S9koIrNWARjpP6k2TZ7kt0uC9zUJtNXzIdZTZRms7Q=
@@ -788,6 +800,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 +816,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 +844,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 +873,30 @@ 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/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=
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 v1.0.0-rc3 h1:ZFQxg7OhvO08l5Hvqa4gQS0HT6ul7s1j3w3qvHPh8gc=
github.com/owncloud/ocis v1.0.0-rc3.0.20201103111659-46bf133a3c63 h1:IkzoExiUk2zOWSTt5dlZmbmzs/wFz8zo/tHgz4QOFKY=
github.com/owncloud/ocis v1.0.0-rc3.0.20201103111659-46bf133a3c63/go.mod h1:kHoustfrV4pGvkKcNFXIr8GRT9MY25mzOKGij4uAC60=
github.com/owncloud/ocis/accounts v0.5.3-0.20201103104733-ff2c41028d9b/go.mod h1:IX7T4MJ1U8Y4z9dfDW1J2jq1nv/SHCM7n2zt1fmBHI8=
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 +909,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 +918,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 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 +964,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 +978,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 +1028,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 +1057,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 +1071,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 +1116,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 +1127,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=
@@ -1112,6 +1143,8 @@ 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=
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
@@ -1150,16 +1183,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 +1207,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 +1228,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 +1272,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 +1319,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,34 +1338,48 @@ 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-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-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-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/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200918174421-af09f7315aff h1:1CPUrky56AcgSpxz/KfgzQWzfG09u5YOL8MvPYBlrL8=
golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/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 +1447,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 +1499,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 +1542,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 +1553,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 +1568,9 @@ gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo=

View File

@@ -17,7 +17,7 @@
"watch": "rollup -c -w",
"test": "echo 'Not implemented'",
"generate-api": "node node_modules/swagger-vue-generator/bin/generate-api.js --package-version v0 --source pkg/proto/v0/accounts.swagger.json --moduleName accounts --destination ui/client/accounts/index.js",
"acceptance-tests": "cucumber-js --require-module @babel/register --require-module @babel/polyfill --require ${TEST_INFRA_DIRECTORY}/acceptance/setup.js --require ui/tests/acceptance/stepDefinitions --require ${TEST_INFRA_DIRECTORY}/acceptance/stepDefinitions --format node_modules/cucumber-pretty -t \"${TEST_TAGS:-not @skip and not @skipOnOC10}\""
"acceptance-tests": "cucumber-js --retry 1 --require-module @babel/register --require-module @babel/polyfill --require ${TEST_INFRA_DIRECTORY}/acceptance/setup.js --require ui/tests/acceptance/stepDefinitions --require ${TEST_INFRA_DIRECTORY}/acceptance/stepDefinitions --format node_modules/cucumber-pretty -t \"${TEST_TAGS:-not @skip and not @skipOnOC10}\""
},
"devDependencies": {
"@babel/core": "^7.7.7",
@@ -53,7 +53,7 @@
"ldap": "^0.7.1",
"nightwatch": "^1.3.6",
"nightwatch-api": "^3.0.1",
"node-fetch": "^2.6.0",
"node-fetch": "^2.6.1",
"qs": "^6.9.1",
"rimraf": "^3.0.0",
"rollup": "^1.28.0",

View File

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,34 @@
package command
import (
"context"
"fmt"
"github.com/micro/cli/v2"
"github.com/micro/go-micro/v2/client/grpc"
merrors "github.com/micro/go-micro/v2/errors"
"github.com/owncloud/ocis/accounts/pkg/config"
index "github.com/owncloud/ocis/accounts/pkg/proto/v0"
)
// RebuildIndex rebuilds the entire configured index.
func RebuildIndex(cdf *config.Config) *cli.Command {
return &cli.Command{
Name: "rebuildIndex",
Usage: "Rebuilds the service's index, i.e. deleting and then re-adding all existing documents",
Aliases: []string{"rebuild", "ri"},
Action: func(ctx *cli.Context) error {
idxSvcID := "com.owncloud.api.accounts"
idxSvc := index.NewIndexService(idxSvcID, grpc.NewClient())
_, err := idxSvc.RebuildIndex(context.Background(), &index.RebuildIndexRequest{})
if err != nil {
fmt.Println(merrors.FromError(err).Detail)
return err
}
fmt.Println("index rebuilt successfully")
return nil
},
}
}

View File

@@ -49,6 +49,7 @@ func Execute() error {
InspectAccount(cfg),
RemoveAccount(cfg),
PrintVersion(cfg),
RebuildIndex(cfg),
},
}

View File

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

View File

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

View File

File diff suppressed because it is too large Load Diff

View File

@@ -551,3 +551,77 @@ func (h *groupsServiceHandler) RemoveMember(ctx context.Context, in *RemoveMembe
func (h *groupsServiceHandler) ListMembers(ctx context.Context, in *ListMembersRequest, out *ListMembersResponse) error {
return h.GroupsServiceHandler.ListMembers(ctx, in, out)
}
// Api Endpoints for IndexService service
func NewIndexServiceEndpoints() []*api.Endpoint {
return []*api.Endpoint{
&api.Endpoint{
Name: "IndexService.RebuildIndex",
Path: []string{"/api/v0/index/rebuild"},
Method: []string{"POST"},
Body: "*",
Handler: "rpc",
},
}
}
// Client API for IndexService service
type IndexService interface {
RebuildIndex(ctx context.Context, in *RebuildIndexRequest, opts ...client.CallOption) (*RebuildIndexResponse, error)
}
type indexService struct {
c client.Client
name string
}
func NewIndexService(name string, c client.Client) IndexService {
return &indexService{
c: c,
name: name,
}
}
func (c *indexService) RebuildIndex(ctx context.Context, in *RebuildIndexRequest, opts ...client.CallOption) (*RebuildIndexResponse, error) {
req := c.c.NewRequest(c.name, "IndexService.RebuildIndex", in)
out := new(RebuildIndexResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for IndexService service
type IndexServiceHandler interface {
RebuildIndex(context.Context, *RebuildIndexRequest, *RebuildIndexResponse) error
}
func RegisterIndexServiceHandler(s server.Server, hdlr IndexServiceHandler, opts ...server.HandlerOption) error {
type indexService interface {
RebuildIndex(ctx context.Context, in *RebuildIndexRequest, out *RebuildIndexResponse) error
}
type IndexService struct {
indexService
}
h := &indexServiceHandler{hdlr}
opts = append(opts, api.WithEndpoint(&api.Endpoint{
Name: "IndexService.RebuildIndex",
Path: []string{"/api/v0/index/rebuild"},
Method: []string{"POST"},
Body: "*",
Handler: "rpc",
}))
return s.Handle(s.NewHandler(&IndexService{h}, opts...))
}
type indexServiceHandler struct {
IndexServiceHandler
}
func (h *indexServiceHandler) RebuildIndex(ctx context.Context, in *RebuildIndexRequest, out *RebuildIndexResponse) error {
return h.IndexServiceHandler.RebuildIndex(ctx, in, out)
}

View File

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

View File

@@ -372,6 +372,120 @@ func RegisterGroupsServiceWeb(r chi.Router, i GroupsServiceHandler, middlewares
r.MethodFunc("POST", "/api/v0/groups/{id=*}/members/$ref", handler.ListMembers)
}
type webIndexServiceHandler struct {
r chi.Router
h IndexServiceHandler
}
func (h *webIndexServiceHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.r.ServeHTTP(w, r)
}
func (h *webIndexServiceHandler) RebuildIndex(w http.ResponseWriter, r *http.Request) {
req := &RebuildIndexRequest{}
resp := &RebuildIndexResponse{}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusPreconditionFailed)
return
}
if err := h.h.RebuildIndex(
r.Context(),
req,
resp,
); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
render.Status(r, http.StatusCreated)
render.JSON(w, r, resp)
}
func RegisterIndexServiceWeb(r chi.Router, i IndexServiceHandler, middlewares ...func(http.Handler) http.Handler) {
handler := &webIndexServiceHandler{
r: r,
h: i,
}
r.MethodFunc("POST", "/api/v0/index/rebuild", handler.RebuildIndex)
}
// RebuildIndexRequestJSONMarshaler describes the default jsonpb.Marshaler used by all
// instances of RebuildIndexRequest. This struct is safe to replace or modify but
// should not be done so concurrently.
var RebuildIndexRequestJSONMarshaler = new(jsonpb.Marshaler)
// MarshalJSON satisfies the encoding/json Marshaler interface. This method
// uses the more correct jsonpb package to correctly marshal the message.
func (m *RebuildIndexRequest) MarshalJSON() ([]byte, error) {
if m == nil {
return json.Marshal(nil)
}
buf := &bytes.Buffer{}
if err := RebuildIndexRequestJSONMarshaler.Marshal(buf, m); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
var _ json.Marshaler = (*RebuildIndexRequest)(nil)
// RebuildIndexRequestJSONUnmarshaler describes the default jsonpb.Unmarshaler used by all
// instances of RebuildIndexRequest. This struct is safe to replace or modify but
// should not be done so concurrently.
var RebuildIndexRequestJSONUnmarshaler = new(jsonpb.Unmarshaler)
// UnmarshalJSON satisfies the encoding/json Unmarshaler interface. This method
// uses the more correct jsonpb package to correctly unmarshal the message.
func (m *RebuildIndexRequest) UnmarshalJSON(b []byte) error {
return RebuildIndexRequestJSONUnmarshaler.Unmarshal(bytes.NewReader(b), m)
}
var _ json.Unmarshaler = (*RebuildIndexRequest)(nil)
// RebuildIndexResponseJSONMarshaler describes the default jsonpb.Marshaler used by all
// instances of RebuildIndexResponse. This struct is safe to replace or modify but
// should not be done so concurrently.
var RebuildIndexResponseJSONMarshaler = new(jsonpb.Marshaler)
// MarshalJSON satisfies the encoding/json Marshaler interface. This method
// uses the more correct jsonpb package to correctly marshal the message.
func (m *RebuildIndexResponse) MarshalJSON() ([]byte, error) {
if m == nil {
return json.Marshal(nil)
}
buf := &bytes.Buffer{}
if err := RebuildIndexResponseJSONMarshaler.Marshal(buf, m); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
var _ json.Marshaler = (*RebuildIndexResponse)(nil)
// RebuildIndexResponseJSONUnmarshaler describes the default jsonpb.Unmarshaler used by all
// instances of RebuildIndexResponse. This struct is safe to replace or modify but
// should not be done so concurrently.
var RebuildIndexResponseJSONUnmarshaler = new(jsonpb.Unmarshaler)
// UnmarshalJSON satisfies the encoding/json Unmarshaler interface. This method
// uses the more correct jsonpb package to correctly unmarshal the message.
func (m *RebuildIndexResponse) UnmarshalJSON(b []byte) error {
return RebuildIndexResponseJSONUnmarshaler.Unmarshal(bytes.NewReader(b), m)
}
var _ json.Unmarshaler = (*RebuildIndexResponse)(nil)
// ListAccountsRequestJSONMarshaler describes the default jsonpb.Marshaler used by all
// instances of ListAccountsRequest. This struct is safe to replace or modify but
// should not be done so concurrently.

View File

@@ -136,6 +136,23 @@ service GroupsService {
}
service IndexService {
rpc RebuildIndex(RebuildIndexRequest) returns (RebuildIndexResponse) {
// All request parameters go into body.
option (google.api.http) = {
// URLs are broken
post: "/api/v0/index/rebuild"
body: "*"
};
}
}
message RebuildIndexRequest {
}
message RebuildIndexResponse {
}
message ListAccountsRequest {
// Optional. The maximum number of accounts to return in the response
int32 page_size = 1 [(google.api.field_behavior) = OPTIONAL];

View File

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

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

View File

@@ -26,6 +26,9 @@ func Server(opts ...Option) grpc.Service {
if err := proto.RegisterGroupsServiceHandler(service.Server(), handler); err != nil {
options.Logger.Fatal().Err(err).Msg("could not register groups handler")
}
if err := proto.RegisterIndexServiceHandler(service.Server(), handler); err != nil {
options.Logger.Fatal().Err(err).Msg("could not register index handler")
}
service.Init()
return service

View File

@@ -3,19 +3,20 @@ 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"
p "github.com/golang/protobuf/proto"
"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 +36,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 +59,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 +78,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 +111,76 @@ 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
}
if in.Query == "" {
err = s.repo.LoadAccounts(ctx, &out.Accounts)
if err != nil {
s.log.Err(err).Msg("failed to load all accounts from storage")
return merrors.InternalServerError(s.id, "failed to load all accounts")
}
for i := range out.Accounts {
a := out.Accounts[i]
// TODO add groups only if requested
// if in.FieldMask ...
s.expandMemberOf(a)
if a.PasswordProfile != nil {
a.PasswordProfile.Password = ""
}
}
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 +196,10 @@ func (s Service) ListAccounts(ctx context.Context, in *proto.ListAccountsRequest
return
}
func (s Service) findAccountsByQuery(ctx context.Context, query string) ([]string, error) {
return s.index.Query(&proto.Account{}, 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 +245,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 {
p.Merge(out, 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 +290,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 +345,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 +354,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 +388,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 +409,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 +465,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 +552,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 +561,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 +610,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 +685,56 @@ func (s Service) debugLogAccount(a *proto.Account) *zerolog.Event {
"DeletedDateTime": a.DeletedDateTime,
})
}
func (s Service) accountExists(ctx context.Context, username, mail, id string) (exists bool, err error) {
var ids []string
ids, err = s.index.FindBy(&proto.Account{}, "preferred_name", username)
if err != nil {
return false, err
}
if len(ids) > 0 {
return true, nil
}
ids, err = s.index.FindBy(&proto.Account{}, "on_premises_sam_account_name", username)
if err != nil {
return false, err
}
if len(ids) > 0 {
return true, nil
}
ids, err = s.index.FindBy(&proto.Account{}, "mail", mail)
if err != nil {
return false, err
}
if len(ids) > 0 {
return true, nil
}
a := &proto.Account{}
err = s.repo.LoadAccount(ctx, id, a)
if err == nil {
return true, nil
}
if !storage.IsNotFoundErr(err) {
return true, err
}
return false, nil
}
func getAuthQueryMatch(query string) (match []string, authRequest bool) {
match = authQuery.FindStringSubmatch(query)
return match, len(match) == 3
}
func isPasswordValid(logger log.Logger, hash string, pwd string) (ok bool) {
defer func() {
if r := recover(); r != nil {
logger.Error().Err(fmt.Errorf("%s", r)).Str("hash", hash).Msg("password lib panicked")
}
}()
c := crypt.NewFromHash(hash)
return c.Verify(hash, []byte(pwd)) == nil
}

View File

@@ -2,34 +2,18 @@ package service
import (
"context"
"github.com/owncloud/ocis/accounts/pkg/storage"
"path"
"path/filepath"
"strconv"
"github.com/CiscoM31/godata"
"github.com/blevesearch/bleve"
"github.com/gofrs/uuid"
p "github.com/golang/protobuf/proto"
"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"
"github.com/owncloud/ocis/accounts/pkg/storage"
)
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()
p.Merge(out, in.Group)
if out.Id == "" {
out.Id = uuid.Must(uuid.NewV4()).String()
}
if id, err = cleanupID(in.Group.Id); err != nil {
if _, err = cleanupID(out.Id); err != nil {
return merrors.InternalServerError(s.id, "could not clean up account id: %v", err.Error())
}
// extract member id
s.deflateMembers(in.Group)
s.deflateMembers(out)
if err = s.repo.WriteGroup(c, in.Group); err != nil {
s.log.Error().Err(err).Interface("group", in.Group).Msg("could not persist new group")
if err = s.repo.WriteGroup(c, out); err != nil {
s.log.Error().Err(err).Interface("group", out).Msg("could not persist new group")
return merrors.InternalServerError(s.id, "could not persist new group: %v", err.Error())
}
if err = s.indexGroup(id); err != nil {
indexResults, err := s.index.Add(out)
if err != nil {
s.rollbackCreateGroup(c, out)
return merrors.InternalServerError(s.id, "could not index new group: %v", err.Error())
}
for _, r := range indexResults {
if r.Field == "GidNumber" {
gid, err := strconv.Atoi(path.Base(r.Value))
if err != nil {
s.rollbackCreateGroup(c, out)
return err
}
out.GidNumber = int64(gid)
return s.repo.WriteGroup(context.Background(), out)
}
}
return
}
// rollbackCreateGroup tries to rollback changes made by `CreateGroup` if parts of it failed.
func (s Service) rollbackCreateGroup(ctx context.Context, group *proto.Group) {
err := s.index.Delete(group)
if err != nil {
s.log.Err(err).Msg("failed to rollback group from indices")
}
err = s.repo.DeleteGroup(ctx, group.Id)
if err != nil {
s.log.Err(err).Msg("failed to rollback group from repo")
}
}
// UpdateGroup implements the GroupsServiceHandler interface
func (s Service) UpdateGroup(c context.Context, in *proto.UpdateGroupRequest, out *proto.Group) (err error) {
return merrors.InternalServerError(s.id, "not implemented")
@@ -217,7 +203,7 @@ func (s Service) DeleteGroup(c context.Context, in *proto.DeleteGroupRequest, ou
return merrors.InternalServerError(s.id, "could not load group: %v", err.Error())
}
if err = s.index.Delete(id); err != nil {
if err = s.index.Delete(g); err != nil {
s.log.Error().Err(err).Str("id", id).Str("path", path).Msg("could not remove group from index")
return merrors.InternalServerError(s.id, "could not remove group from index: %v", err.Error())
}

View File

@@ -0,0 +1,108 @@
package service
import (
"context"
"fmt"
"github.com/owncloud/ocis/accounts/pkg/storage"
"github.com/owncloud/ocis/accounts/pkg/proto/v0"
"github.com/owncloud/ocis/ocis-pkg/indexer"
"github.com/owncloud/ocis/ocis-pkg/indexer/config"
"github.com/owncloud/ocis/ocis-pkg/indexer/option"
)
// RebuildIndex deletes all indices (in memory and on storage) and rebuilds them from scratch.
func (s Service) RebuildIndex(ctx context.Context, request *proto.RebuildIndexRequest, response *proto.RebuildIndexResponse) error {
if err := s.index.Reset(); err != nil {
return fmt.Errorf("failed to delete index containers: %w", err)
}
c, err := configFromSvc(s.Config)
if err != nil {
return err
}
if err := recreateContainers(s.index, c); err != nil {
return fmt.Errorf("failed to recreate index containers: %w", err)
}
if err := reindexDocuments(ctx, s.repo, s.index); err != nil {
return fmt.Errorf("failed to reindex documents: %w", err)
}
return nil
}
// recreateContainers adds all indices to the indexer that we have for this service.
func recreateContainers(idx *indexer.Indexer, cfg *config.Config) error {
// Accounts
if err := idx.AddIndex(&proto.Account{}, "Id", "Id", "accounts", "non_unique", nil, true); err != nil {
return err
}
if err := idx.AddIndex(&proto.Account{}, "DisplayName", "Id", "accounts", "non_unique", nil, true); err != nil {
return err
}
if err := idx.AddIndex(&proto.Account{}, "Mail", "Id", "accounts", "unique", nil, true); err != nil {
return err
}
if err := idx.AddIndex(&proto.Account{}, "OnPremisesSamAccountName", "Id", "accounts", "unique", nil, true); err != nil {
return err
}
if err := idx.AddIndex(&proto.Account{}, "PreferredName", "Id", "accounts", "unique", nil, true); err != nil {
return err
}
if err := idx.AddIndex(&proto.Account{}, "UidNumber", "Id", "accounts", "autoincrement", &option.Bound{
Lower: cfg.Index.UID.Lower,
Upper: cfg.Index.UID.Upper,
}, false); err != nil {
return err
}
// Groups
if err := idx.AddIndex(&proto.Group{}, "OnPremisesSamAccountName", "Id", "groups", "unique", nil, true); err != nil {
return err
}
if err := idx.AddIndex(&proto.Group{}, "DisplayName", "Id", "groups", "non_unique", nil, true); err != nil {
return err
}
if err := idx.AddIndex(&proto.Group{}, "GidNumber", "Id", "groups", "autoincrement", &option.Bound{
Lower: cfg.Index.GID.Lower,
Upper: cfg.Index.GID.Upper,
}, false); err != nil {
return err
}
return nil
}
// reindexDocuments loads all existing documents and adds them to the index.
func reindexDocuments(ctx context.Context, repo storage.Repo, index *indexer.Indexer) error {
accounts := make([]*proto.Account, 0)
if err := repo.LoadAccounts(ctx, &accounts); err != nil {
return err
}
for i := range accounts {
_, err := index.Add(accounts[i])
if err != nil {
return err
}
}
groups := make([]*proto.Group, 0)
if err := repo.LoadGroups(ctx, &groups); err != nil {
return err
}
for i := range groups {
_, err := index.Add(groups[i])
if err != nil {
return err
}
}
return nil
}

View File

@@ -3,19 +3,17 @@ 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/storage"
"github.com/owncloud/ocis/ocis-pkg/indexer"
idxcfg "github.com/owncloud/ocis/ocis-pkg/indexer/config"
idxerrs "github.com/owncloud/ocis/ocis-pkg/indexer/errors"
mclient "github.com/micro/go-micro/v2/client"
"github.com/owncloud/ocis/accounts/pkg/config"
"github.com/owncloud/ocis/accounts/pkg/proto/v0"
@@ -25,6 +23,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 +73,73 @@ 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) {
var indexcfg *idxcfg.Config
indexcfg, err := configFromSvc(s.Config)
if err != nil {
return nil, err
}
idx := indexer.CreateIndexer(indexcfg)
if err := recreateContainers(idx, indexcfg); err != nil {
return nil, err
}
return idx, nil
}
// configFromSvc creates an index config out of a service configuration. This intermediate step exists
// because the index config was mapped after the service config.
func configFromSvc(cfg *config.Config) (*idxcfg.Config, error) {
c := idxcfg.New()
defer func(cfg *config.Config) {
l := log.NewLogger(log.Color(cfg.Log.Color), log.Pretty(cfg.Log.Pretty), log.Level(cfg.Log.Level))
if r := recover(); r != nil {
l.Error().
Str("panic", "recovered from panic while parsing index config from service configuration").
Interface("svc_config", cfg).
Msg("recovered from panic")
}
}(cfg)
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 (config.Repo{}) != cfg.Repo {
if (config.Disk{}) != cfg.Repo.Disk {
c.Repo = idxcfg.Repo{
Disk: idxcfg.Disk{
Path: cfg.Repo.Disk.Path,
},
})
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 (config.CS3{}) != cfg.Repo.CS3 {
c.Repo = idxcfg.Repo{
CS3: idxcfg.CS3{
ProviderAddr: cfg.Repo.CS3.ProviderAddr,
DataURL: cfg.Repo.CS3.DataURL,
DataPrefix: cfg.Repo.CS3.DataPrefix,
JWTSecret: cfg.Repo.CS3.JWTSecret,
},
}
}
if index, err = bleve.New(indexDir, indexMapping); err != nil {
return nil, err
if (config.Index{}) != cfg.Index {
c.Index = idxcfg.Index{
UID: idxcfg.Bound{
Lower: cfg.Index.UID.Lower,
},
GID: idxcfg.Bound{
Lower: cfg.Index.GID.Lower,
},
}
}
if (config.ServiceUser{}) != cfg.ServiceUser {
c.ServiceUser = cfg.ServiceUser
}
}
return
return c, nil
}
func (s Service) createDefaultAccounts() (err error) {
@@ -275,8 +257,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 +346,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 +403,7 @@ type Service struct {
id string
log log.Logger
Config *config.Config
index bleve.Index
index *indexer.Indexer
RoleService settings.RoleService
RoleManager *roles.Manager
repo storage.Repo

View File

@@ -0,0 +1 @@
checks = ["all", "-ST1003", "-ST1000", "-SA1019"]

View File

@@ -8,16 +8,20 @@ import (
"io/ioutil"
"net/http"
"path"
"path/filepath"
"strconv"
"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"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/pkg/token"
"github.com/cs3org/reva/pkg/token/manager/jwt"
"github.com/owncloud/ocis/accounts/pkg/config"
"github.com/owncloud/ocis/accounts/pkg/proto/v0"
olog "github.com/owncloud/ocis/ocis-pkg/log"
"google.golang.org/grpc/metadata"
)
@@ -73,8 +77,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
@@ -84,12 +94,46 @@ func (r CS3Repo) LoadAccount(ctx context.Context, id string, a *proto.Account) (
return err
}
return r.loadAccount(id, t, a)
}
// LoadAccounts loads all the accounts from the cs3 api
func (r CS3Repo) LoadAccounts(ctx context.Context, a *[]*proto.Account) (err error) {
t, err := r.authenticate(ctx)
if err != nil {
return err
}
ctx = metadata.AppendToOutgoingContext(ctx, token.TokenHeader, t)
res, err := r.storageProvider.ListContainer(ctx, &provider.ListContainerRequest{
Ref: &provider.Reference{
Spec: &provider.Reference_Path{Path: path.Join("/meta", accountsFolder)},
},
})
if err != nil {
return err
}
log := olog.NewLogger(olog.Pretty(r.cfg.Log.Pretty), olog.Color(r.cfg.Log.Color), olog.Level(r.cfg.Log.Level))
for i := range res.Infos {
acc := &proto.Account{}
err := r.loadAccount(filepath.Base(res.Infos[i].Path), t, acc)
if err != nil {
log.Err(err).Msg("could not load account")
continue
}
*a = append(*a, acc)
}
return nil
}
func (r CS3Repo) loadAccount(id string, t string, a *proto.Account) error {
resp, err := r.dataProvider.get(r.accountURL(id), t)
if err != nil {
return err
}
if resp.StatusCode == http.StatusNotFound {
if resp.StatusCode != http.StatusOK {
return &notFoundErr{"account", id}
}
@@ -147,8 +191,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
@@ -158,6 +208,40 @@ func (r CS3Repo) LoadGroup(ctx context.Context, id string, g *proto.Group) (err
return err
}
return r.loadGroup(id, t, g)
}
// LoadGroups loads all the groups from the cs3 api
func (r CS3Repo) LoadGroups(ctx context.Context, g *[]*proto.Group) (err error) {
t, err := r.authenticate(ctx)
if err != nil {
return err
}
ctx = metadata.AppendToOutgoingContext(ctx, token.TokenHeader, t)
res, err := r.storageProvider.ListContainer(ctx, &provider.ListContainerRequest{
Ref: &provider.Reference{
Spec: &provider.Reference_Path{Path: path.Join("/meta", groupsFolder)},
},
})
if err != nil {
return err
}
log := olog.NewLogger(olog.Pretty(r.cfg.Log.Pretty), olog.Color(r.cfg.Log.Color), olog.Level(r.cfg.Log.Level))
for i := range res.Infos {
grp := &proto.Group{}
err := r.loadGroup(filepath.Base(res.Infos[i].Path), t, grp)
if err != nil {
log.Err(err).Msg("could not load account")
continue
}
*g = append(*g, grp)
}
return nil
}
func (r CS3Repo) loadGroup(id string, t string, g *proto.Group) error {
resp, err := r.dataProvider.get(r.groupURL(id), t)
if err != nil {
return err
@@ -205,14 +289,30 @@ func (r CS3Repo) DeleteGroup(ctx context.Context, id string) (err error) {
}
func (r CS3Repo) authenticate(ctx context.Context) (token string, err error) {
return AuthenticateCS3(ctx, r.cfg.ServiceUser, r.tm)
}
// AuthenticateCS3 mints an auth token for communicating with cs3 storage based on a service user from config
func AuthenticateCS3(ctx context.Context, su config.ServiceUser, tm token.Manager) (token string, err error) {
u := &user.User{
Id: &user.UserId{},
Id: &user.UserId{
OpaqueId: su.UUID,
},
Groups: []string{},
Opaque: &types.Opaque{
Map: map[string]*types.OpaqueEntry{
"uid": {
Decoder: "plain",
Value: []byte(strconv.FormatInt(su.UID, 10)),
},
"gid": {
Decoder: "plain",
Value: []byte(strconv.FormatInt(su.GID, 10)),
},
},
},
}
if r.cfg.ServiceUser.Username != "" {
u.Id.OpaqueId = r.cfg.ServiceUser.UUID
}
return r.tm.MintToken(ctx, u)
return tm.MintToken(ctx, u)
}
func (r CS3Repo) accountURL(id string) string {
@@ -224,11 +324,16 @@ func (r CS3Repo) groupURL(id string) string {
}
func (r CS3Repo) makeRootDirIfNotExist(ctx context.Context, folder string) error {
return MakeDirIfNotExist(ctx, r.storageProvider, folder)
}
// MakeDirIfNotExist will create a root node in the metadata storage. Requires an authenticated context.
func MakeDirIfNotExist(ctx context.Context, sp provider.ProviderAPIClient, folder string) error {
var rootPathRef = &provider.Reference{
Spec: &provider.Reference_Path{Path: path.Join("/meta", folder)},
}
resp, err := r.storageProvider.Stat(ctx, &provider.StatRequest{
resp, err := sp.Stat(ctx, &provider.StatRequest{
Ref: rootPathRef,
})
@@ -237,7 +342,7 @@ func (r CS3Repo) makeRootDirIfNotExist(ctx context.Context, folder string) error
}
if resp.Status.Code == v1beta11.Code_CODE_NOT_FOUND {
_, err := r.storageProvider.CreateContainer(ctx, &provider.CreateContainerRequest{
_, err := sp.CreateContainer(ctx, &provider.CreateContainerRequest{
Ref: rootPathRef,
})

View File

@@ -17,8 +17,8 @@ var groupLock sync.Mutex
// DiskRepo provides a local filesystem implementation of the Repo interface
type DiskRepo struct {
cfg *config.Config
log olog.Logger
cfg *config.Config
log olog.Logger
}
// NewDiskRepo creates a new disk repo
@@ -37,8 +37,8 @@ func NewDiskRepo(cfg *config.Config, log olog.Logger) DiskRepo {
}
}
return DiskRepo{
cfg: cfg,
log: log,
cfg: cfg,
log: log,
}
}
@@ -70,6 +70,20 @@ func (r DiskRepo) LoadAccount(ctx context.Context, id string, a *proto.Account)
return json.Unmarshal(data, a)
}
// LoadAccounts loads all the accounts from the local filesystem
func (r DiskRepo) LoadAccounts(ctx context.Context, a *[]*proto.Account) (err error) {
root := filepath.Join(r.cfg.Repo.Disk.Path, accountsFolder)
return filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
acc := &proto.Account{}
if e := r.LoadAccount(ctx, filepath.Base(path), acc); e != nil {
r.log.Err(e).Msg("could not load account")
return nil
}
*a = append(*a, acc)
return nil
})
}
// DeleteAccount from the local filesystem
func (r DiskRepo) DeleteAccount(ctx context.Context, id string) (err error) {
path := filepath.Join(r.cfg.Repo.Disk.Path, accountsFolder, id)
@@ -118,6 +132,20 @@ func (r DiskRepo) LoadGroup(ctx context.Context, id string, g *proto.Group) (err
return json.Unmarshal(data, g)
}
// LoadGroups loads all the groups from the local filesystem
func (r DiskRepo) LoadGroups(ctx context.Context, g *[]*proto.Group) (err error) {
root := filepath.Join(r.cfg.Repo.Disk.Path, groupsFolder)
return filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
grp := &proto.Group{}
if e := r.LoadGroup(ctx, filepath.Base(path), grp); e != nil {
r.log.Err(e).Msg("could not load group")
return nil
}
*g = append(*g, grp)
return nil
})
}
// DeleteGroup from the local filesystem
func (r DiskRepo) DeleteGroup(ctx context.Context, id string) (err error) {
path := filepath.Join(r.cfg.Repo.Disk.Path, groupsFolder, id)
@@ -127,10 +155,7 @@ func (r DiskRepo) DeleteGroup(ctx context.Context, id string) (err error) {
}
}
return nil
//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())
return
}
// deflateMemberOf replaces the groups of a user with an instance that only contains the id

View File

@@ -2,20 +2,23 @@ package storage
import (
"context"
"github.com/owncloud/ocis/accounts/pkg/proto/v0"
)
const (
accountsFolder = "accounts"
groupsFolder = "groups"
groupsFolder = "groups"
)
// Repo defines the storage operations
type Repo interface {
WriteAccount(ctx context.Context, a *proto.Account) (err error)
LoadAccount(ctx context.Context, id string, a *proto.Account) (err error)
LoadAccounts(ctx context.Context, a *[]*proto.Account) (err error)
DeleteAccount(ctx context.Context, id string) (err error)
WriteGroup(ctx context.Context, g *proto.Group) (err error)
LoadGroup(ctx context.Context, id string, g *proto.Group) (err error)
LoadGroups(ctx context.Context, g *[]*proto.Group) (err error)
DeleteGroup(ctx context.Context, id string) (err error)
}

View File

@@ -28,7 +28,7 @@ const navItems = [
name: 'accounts',
path: `/${appInfo.id}/`
},
menu: 'user'
menu: 'apps'
}
]

View File

@@ -17,12 +17,12 @@
</oc-grid>
</template>
<template v-else-if="hasFailed">
<oc-alert variation="warning" no-close class="oc-m">
<oc-alert variation="warning" no-close class="oc-m" id="accounts-list-loading-failed">
<oc-icon name="warning" variation="warning" class="uk-float-left oc-mr-s" />
<translate>You don't have permissions to manage accounts.</translate>
</oc-alert>
</template>
<oc-loader v-else />
<oc-loader id="accounts-list-loader" v-else />
</div>
</div>
</template>

View File

@@ -25,14 +25,20 @@ module.exports = {
},
selectRole: function (username, role) {
const roleTrigger =
util.format(this.elements.rowByUsername.selector, username) +
this.elements.rolesDropdownTrigger.selector
const roleSelector =
util.format(this.elements.rowByUsername.selector, username) +
util.format(this.elements.roleInRolesDropdown.selector, role)
return this
.click('@rolesDropdownTrigger')
.initAjaxCounters()
.waitForElementVisible(roleTrigger)
.click(roleTrigger)
.waitForElementVisible(roleSelector)
.click(roleSelector)
.waitForOutstandingAjaxCalls()
},
checkUsersRole: function (username, role) {
@@ -114,7 +120,7 @@ module.exports = {
locateStrategy: 'xpath'
},
roleInRolesDropdown: {
selector: '//label[contains(@class, "accounts-roles-dropdown-role") and normalize-space()="%s"]',
selector: '//label[contains(@class, "accounts-roles-dropdown-role")]/span[normalize-space()="%s"]',
locateStrategy: 'xpath'
},
rolesDropdownTrigger: {
@@ -122,11 +128,13 @@ module.exports = {
locateStrategy: 'xpath'
},
loadingAccountsList: {
selector: '//div[contains(@class, "oc-loader")]',
locateStrategy: 'xpath'
selector: '#accounts-list-loader'
},
loadingAccountsListFailed: {
selector: '#accounts-list-loading-failed'
},
rowCheckbox: {
selector: '//input[@class="oc-checkbox"]',
selector: '//input[contains(@class, "oc-checkbox")]',
locateStrategy: 'xpath'
},
batchActionDisable: {

View File

@@ -33,8 +33,7 @@ Then('the displayed role of user {string} should be {string} on the WebUI', func
Then('the user should not be able to see the accounts list on the WebUI', async function () {
return client.page.accountsPage()
.waitForAjaxCallsToStartAndFinish()
.waitForElementVisible('@loadingAccountsList')
.waitForElementNotPresent('@accountsListTable')
.waitForElementVisible('@loadingAccountsListFailed')
})
When('the user disables user/users {string} using the WebUI', function (usernames) {

View File

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

View File

@@ -1,28 +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",
"pdf-viewer",
"markdown-editor",
"media-viewer"
],
"external_apps": [
{
"id": "accounts",
"path": "https://ocis-server:9200/accounts.js",
"config": {
"url": "https://ocis-server:9200"
}
}
]
}

View File

@@ -1467,9 +1467,9 @@ binary-extensions@^2.0.0:
integrity sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==
bl@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/bl/-/bl-4.0.2.tgz#52b71e9088515d0606d9dd9cc7aa48dc1f98e73a"
integrity sha512-j4OH8f6Qg2bGuWfRiltT2HYGx0e1QcBTrK9KAHNMwMZdQnDZFk0ZSYIpADjYCB3U12nicC5tVJwSIhwOWjb4RQ==
version "4.0.3"
resolved "https://registry.yarnpkg.com/bl/-/bl-4.0.3.tgz#12d6287adc29080e22a705e5764b2a9522cdc489"
integrity sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==
dependencies:
buffer "^5.5.0"
inherits "^2.0.4"
@@ -4163,9 +4163,9 @@ lodash.union@^4.6.0:
integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=
lodash@^4.15.0, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4:
version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
version "4.17.20"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
log-symbols@2.2.0:
version "2.2.0"
@@ -4488,10 +4488,10 @@ node-environment-flags@1.0.5:
object.getownpropertydescriptors "^2.0.3"
semver "^5.7.0"
node-fetch@^2.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
node-fetch@^2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
node-modules-regexp@^1.0.0:
version "1.0.0"

View File

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

View File

@@ -0,0 +1,9 @@
Change: Rebuild index command for accounts
Tags: accounts
The index for the accounts service can now be rebuilt by running the cli command `./bin/ocis accounts rebuild`.
It deletes all configured indices and rebuilds them from the documents found on storage. For this we also introduced
a `LoadAccounts` and `LoadGroups` function on storage for loading all existing documents.
https://github.com/owncloud/ocis/pull/748

View File

@@ -0,0 +1,7 @@
Bugfix: Lower Bound was not working for the cs3 api index implementation
Tags: accounts
Lower bound working on the cs3 index implementation
https://github.com/owncloud/ocis/pull/741

View File

@@ -0,0 +1,7 @@
Bugfix: Fix id or username query handling
Tags: accounts
The code was stopping execution when encountering an error while loading an account by id. But for or queries we can continue execution.
https://github.com/owncloud/ocis/pull/745

View File

@@ -0,0 +1,7 @@
Bugfix: Use micro default client
Tags: glauth
We found a file descriptor leak in the glauth connections to the accounts service. Fixed it by using the micro default client.
https://github.com/owncloud/ocis/pull/718

View File

@@ -0,0 +1,7 @@
Change: Properly style konnectd consent page
Tags: konnectd
After bringing our theme into konnectd, we've had to adjust the styles of the consent page so the text is visible and button reflects our theme.
https://github.com/owncloud/ocis/pull/754

View File

@@ -0,0 +1,9 @@
Bugfix: Allow consent-prompt with switch-account
Multiple prompt values are allowed and this change fixes the check for
select_account if it was used together with other prompt values. Where
select_account previously was ignored, it is now processed as required,
fixing the use case when a RP wants to trigger select_account first
while at the same time wants also to request interactive consent.
https://github.com/owncloud/ocis/pull/788

View File

@@ -0,0 +1,8 @@
Bugfix: Mint token with uid and gid
Tags: accounts
The eos driver expects the uid and gid from the opaque map of a user. While the proxy does mint tokens correctly, the accounts service wasn't.
https://github.com/owncloud/ocis/pull/737

View File

@@ -0,0 +1,5 @@
Change: Move the indexer package from ocis/accounts to ocis/ocis-pkg
We are making that change for semantic reasons. So consumers of any index don't necessarily need to know of the accounts service.
https://github.com/owncloud/ocis/pull/794

View File

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

View File

@@ -0,0 +1,7 @@
Change: Default apps in ownCloud Web
Tags: web
We changed the default apps for ownCloud Web to be only files and media-viewer. Markdown-editor and draw-io have been removed as defaults.
https://github.com/owncloud/ocis/pull/688

View File

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

View File

@@ -0,0 +1,7 @@
Change: Bring oC theme
Tags: konnectd
We've styled our konnectd login page to reflect ownCloud theme.
https://github.com/owncloud/ocis/pull/698

View File

@@ -0,0 +1,5 @@
Enhancement: Update glauth to dev 4f029234b2308
Includes a bugfix, don't mix graph and provisioning api.
https://github.com/owncloud/ocis/pull/786

View File

@@ -0,0 +1,27 @@
Enhancement: Update konnectd to v0.33.8
This update adds options which allow the configuration of oidc-token expiration
parameters: KONNECTD_ACCESS_TOKEN_EXPIRATION, KONNECTD_ID_TOKEN_EXPIRATION and
KONNECTD_REFRESH_TOKEN_EXPIRATION.
Other changes from upstream:
- Generate random endsession state for external authority
- Update dependencies in Dockerfile
- Set prompt=None to avoid loops with external authority
- Update Jenkins reporting plugin from checkstyle to recordIssues
- Remove extra kty key from JWKS top level document
- Fix regression which encodes URL fragments twice
- Avoid generating fragmet/query URLs with wrong order
- Return state for oidc endsession response redirects
- Use server provided username to avoid case mismatch
- Use signed-out-uri if set as fallback for goodbye redirect on saml slo
- Add checks to ensure post_logout_redirect_uri is not empty
- Fix SAML2 logout request parsing
- Cure panic when no state is found in saml esr
- Use SAML IdP Issuer value from meta data entityID
- Allow configuration of expiration of oidc access, id and refresh tokens
- Implement trampolin for external OIDC authority end session
- Update ca-certificates version
https://github.com/owncloud/ocis/pull/744

View File

@@ -0,0 +1,8 @@
Change: Update phoenix to v0.20.0
Tags: web
We updated phoenix to v0.20.0. Please refer to the changelog (linked) for details on the phoenix release.
https://github.com/owncloud/ocis/pull/674
https://github.com/owncloud/phoenix/releases/tag/v0.20.0

View File

@@ -0,0 +1,8 @@
Change: Update phoenix to v0.21.0
Tags: web
We updated phoenix to v0.21.0. Please refer to the changelog (linked) for details on the phoenix release.
https://github.com/owncloud/ocis/pull/728
https://github.com/owncloud/phoenix/releases/tag/v0.21.0

View File

@@ -0,0 +1,8 @@
Change: Update phoenix to v0.22.0
Tags: web
We updated phoenix to v0.22.0. Please refer to the changelog (linked) for details on the phoenix release.
https://github.com/owncloud/ocis/pull/757
https://github.com/owncloud/phoenix/releases/tag/v0.22.0

View File

@@ -0,0 +1,8 @@
Change: Update phoenix to v0.23.0
Tags: web
We updated phoenix to v0.23.0. Please refer to the changelog (linked) for details on the phoenix release.
https://github.com/owncloud/ocis/pull/785
https://github.com/owncloud/phoenix/releases/tag/v0.23.0

View File

@@ -0,0 +1,6 @@
Enhancement: Update reva to cdb3d6688da5
* let the gateway filter invalid references
https://github.com/owncloud/ocis/pull/748
https://github.com/cs3org/reva/pull/1274

View File

@@ -0,0 +1,6 @@
Enhancement: Update reva to dd3a8c0f38
* fixes etag propagation in the ocis driver
https://github.com/owncloud/ocis/pull/725
https://github.com/cs3org/reva/pull/1264

View File

@@ -0,0 +1,5 @@
Change: Clarify storage driver env vars
After renaming ocsi-reva to storage and combining the storage and data providers some env vars were confusingly named `STORAGE_STORAGE_...`. We are changing the prefix for driver related env vars to `STORAGE_DRIVER_...`. This makes changing the storage driver using eg.: `STORAGE_HOME_DRIVER=eos` and setting driver options using `STORAGE_DRIVER_EOS_LAYOUT=...` less confusing.
https://github.com/owncloud/ocis/pull/729

View File

@@ -0,0 +1,53 @@
# Deployment scenario ocis with external konnectd service on separate node and traefik as reverse proxy
## Setup on ocis server
* Clone ocis repository
`git clone https://github.com/owncloud/ocis.git`
* Copy example sub folder for ocisnode to /opt
`cp deployment/examples/ocis_external_konnectd/ocisnode /opt/`
* Overwrite OCIS_DOMAIN and IDP_DOMAIN in .env with your-ocis.domain.com and your-idp.domain.com
`sed -i 's/ocis.domain.com/your-ocis.domain.com/g' /opt/ocisnode/.env`
`sed -i 's/idp.domain.com/your-idp.domain.com/g' /opt/ocisnode/.env`
* Change into deployment folder
`cd /opt/ocisnode`
* Start application stack
`docker-compose up -d`
## Setup on idp server
* Clone ocis repository
`git clone https://github.com/owncloud/ocis.git`
* Copy example sub folder for idpnode to /opt
`cp deployment/examples/ocis_external_konnectd/idpnode /opt/`
* Overwrite OCIS_DOMAIN and IDP_DOMAIN in .env with your-ocis.domain.com and your-idp.domain.com
`sed -i 's/ocis.domain.com/your-ocis.domain.com/g' /opt/idpnode/.env`
`sed -i 's/idp.domain.com/your-idp.domain.com/g' /opt/idpnode/.env`
* Overwrite redirect uri with your-ocis.domain.com in identifier-registration.yml
`sed -i 's/ocis.domain.com/your-ocis.domain.com/g' /opt/idpnode/config/identifier-registration.yml`
* Change into deployment folder
`cd /opt/idpnode`
* Start application stack
`docker-compose up -d`

View File

@@ -0,0 +1,2 @@
OCIS_DOMAIN=ocis.domain.com
IDP_DOMAIN=idp.domain.com

View File

@@ -0,0 +1,18 @@
---
# OpenID Connect client registry.
clients:
- id: phoenix
name: OCIS
application_type: web
insecure: yes
trusted: yes
redirect_uris:
- http://ocis.domain.com/
- https://ocis.domain.com/
- http://ocis.domain.com/oidc-callback.html
- https://ocis.domain.com/oidc-callback.html
- http://ocis.domain.com/oidc-silent-redirect.html
- https://ocis.domain.com/oidc-silent-redirect.html
origins:
- http://ocis.domain.com
- https://ocis.domain.com

View File

@@ -0,0 +1,67 @@
version: '3.7'
services:
traefik:
image: "traefik:v2.2"
container_name: "traefik"
networks:
- idpnet
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.idp.acme.tlschallenge=true"
- "--certificatesresolvers.idp.acme.caserver=https://acme-v02.api.letsencrypt.org/directory"
- "--certificatesresolvers.idp.acme.email=postmaster@${IDP_DOMAIN}"
- "--certificatesresolvers.idp.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- "letsencrypt:/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
konnectd:
container_name: konnectd
image: owncloud/ocis-konnectd:latest
networks:
- idpnet
ports:
- "9130:9130"
volumes:
- ./config:/etc/ocis
environment:
OCIS_LOG_LEVEL: debug
KONNECTD_ISS: https://${IDP_DOMAIN}
KONNECTD_IDENTIFIER_REGISTRATION_CONF: "/etc/ocis/identifier-registration.yml"
KONNECTD_LOG_LEVEL: debug
KONNECTD_TLS: '0'
LDAP_URI: ldap://${OCIS_DOMAIN}:9125
LDAP_BINDDN: cn=konnectd,ou=sysusers,dc=example,dc=org
LDAP_BINDPW: konnectd
LDAP_BASEDN: ou=users,dc=example,dc=org
LDAP_SCOPE: sub
LDAP_LOGIN_ATTRIBUTE: cn
LDAP_EMAIL_ATTRIBUTE: mail
LDAP_NAME_ATTRIBUTE=: n
LDAP_UUID_ATTRIBUTE: uid
LDAP_UUID_ATTRIBUTE_TYPE: text
LDAP_FILTER: (objectClass=posixaccount)
labels:
- "traefik.enable=true"
- "traefik.http.services.idp.loadbalancer.server.port=9200"
- "traefik.docker.network=idpnet"
- "traefik.port=9130"
- "traefik.protocol=https"
# ssl config
- "traefik.http.routers.idp.rule=Host(`${IDP_DOMAIN}`)"
- "traefik.http.routers.idp.entrypoints=websecure"
- "traefik.http.routers.idp.tls.certresolver=idp"
# http -> https forwarding
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
- "traefik.http.routers.idp-redirs.rule=Host(`${IDP_DOMAIN}`)"
- "traefik.http.routers.idp-redirs.entrypoints=web"
- "traefik.http.routers.idp-redirs.middlewares=redirect-to-https"

View File

@@ -0,0 +1,2 @@
OCIS_DOMAIN=ocis.domain.com
IDP_DOMAIN=idp.domain.com

View File

@@ -0,0 +1,68 @@
version: '3.7'
services:
traefik:
image: "traefik:v2.2"
container_name: "traefik"
networks:
- ocisnet
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.ocis.acme.tlschallenge=true"
- "--certificatesresolvers.ocis.acme.caserver=https://acme-v02.api.letsencrypt.org/directory"
- "--certificatesresolvers.ocis.acme.email=postmaster@${OCIS_DOMAIN}"
- "--certificatesresolvers.ocis.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- "letsencrypt:/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
ocis:
container_name: ocis
image: owncloud/ocis:latest
tty: true
privileged: true
stdin_open: true
ports:
- 9200:9200
- 9125:9125
hostname: ocis
networks:
- ocisnet
environment:
OCIS_DOMAIN: ${OCIS_DOMAIN}
PROXY_OIDC_ISSUER: https://${IDP_DOMAIN}
PROXY_OIDC_INSECURE: "true"
PROXY_TLS: "false"
GRAPH_OIDC_ENDPOINT: https://${IDP_DOMAIN}
REVA_OIDC_ISSUER: https://${IDP_DOMAIN}
REVA_LDAP_IDP: https://${IDP_DOMAIN}
PHOENIX_OIDC_AUTHORITY: https://${IDP_DOMAIN}
PHOENIX_OIDC_METADATA_URL: https://${IDP_DOMAIN}/.well-known/openid-configuration
PHOENIX_WEB_CONFIG_SERVER: https://${OCIS_DOMAIN}
OCIS_LOG_LEVEL: debug
REVA_TRANSFER_EXPIRES: 86400
REVA_FRONTEND_URL: https://${OCIS_DOMAIN}
REVA_DATAGATEWAY_URL: https://${OCIS_DOMAIN}/data
labels:
- "traefik.enable=true"
- "traefik.http.services.ocis.loadbalancer.server.port=9200"
- "traefik.docker.network=ocisnet"
- "traefik.protocol=https"
# ssl config
- "traefik.http.routers.idp.rule=Host(`${OCIS_DOMAIN}`)"
- "traefik.http.routers.ocis.entrypoints=websecure"
- "traefik.http.routers.ocis.tls.certresolver=idp"
# http -> https forwarding
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
- "traefik.http.routers.ocis-redirs.rule=Host(`${OCIS_DOMAIN}`)"
- "traefik.http.routers.ocis-redirs.entrypoints=web"
- "traefik.http.routers.ocis-redirs.middlewares=redirect-to-https"

View File

@@ -0,0 +1,3 @@
COMPOSE_PROJECT_NAME=bridge
OCIS_DOMAIN=ocis.domain.com
OC10_DOMAIN=oc10.domain.com

View File

@@ -0,0 +1,30 @@
# Deployment scenario ocis with oc10 backend and traefik as reverse proxy
## Setup on server
* Clone ocis repository
`git clone https://github.com/owncloud/ocis.git`
* Copy example folder to /opt
`cp deployment/examples/ocis_oc10_backend /opt/`
* Overwrite OCIS_DOMAIN and OC10_DOMAIN in .env with your-ocis.domain.com and your-oc10.domain.com
`sed -i 's/ocis.domain.com/your-ocis.domain.com/g' /opt/ocis_oc10_backend/.env`
`sed -i 's/oc10.domain.com/your-oc10.domain.com/g' /opt/ocis_oc10_backend/.env`
* Overwrite redirect uris with your-ocis.domain.com and your-oc10.domain.com in identifier-registration.yml
`sed -i 's/ocis.domain.com/your-ocis.domain.com/g' /opt/ocis_oc10_backend/ocis/identifier-registration.yml`
`sed -i 's/oc10.domain.com/your-oc10.domain.com/g' /opt/ocis_oc10_backend/ocis/identifier-registration.yml`
* Change into deployment folder
`cd /opt/ocis_oc10_backend`
* Start application stack
`docker-compose up -d`

View File

@@ -0,0 +1,171 @@
version: '3.7'
volumes:
files:
driver: local
mysql:
driver: local
backup:
driver: local
redis:
driver: local
tmp:
driver: local
letsencrypt:
driver: local
services:
traefik:
image: "traefik:v2.2"
container_name: "traefik"
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--serverstransport.insecureskipverify=true"
# Ocis certificate resolver
- "--certificatesresolvers.ocis.acme.tlschallenge=true"
- "--certificatesresolvers.ocis.acme.caserver=https://acme-v02.api.letsencrypt.org/directory"
- "--certificatesresolvers.ocis.acme.email=user@${OCIS_DOMAIN}"
- "--certificatesresolvers.ocis.acme.storage=/letsencrypt/acme-ocis.json"
# OC10 certificate resolver
- "--certificatesresolvers.oc10.acme.tlschallenge=true"
- "--certificatesresolvers.oc10.acme.caserver=https://acme-v02.api.letsencrypt.org/directory"
- "--certificatesresolvers.oc10.acme.email=user@${OCIS_DOMAIN}"
- "--certificatesresolvers.oc10.acme.storage=/letsencrypt/acme-oc10.json"
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- "letsencrypt:/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
owncloud:
build:
context: ./oc10
dockerfile: Dockerfile
expose:
- "8080"
depends_on:
- db
- redis
environment:
OWNCLOUD_DOMAIN: ${OC10_DOMAIN}
OWNCLOUD_DB_TYPE: mysql
OWNCLOUD_DB_NAME: owncloud
OWNCLOUD_DB_USERNAME: owncloud
OWNCLOUD_DB_PASSWORD: owncloud
OWNCLOUD_DB_HOST: db
OWNCLOUD_ADMIN_USERNAME: admin
OWNCLOUD_ADMIN_PASSWORD: admin
OWNCLOUD_MYSQL_UTF8MB4: "true"
OWNCLOUD_REDIS_ENABLED: "true"
OWNCLOUD_REDIS_HOST: redis
OWNCLOUD_DEBUG: "true"
OWNCLOUD_TRUSTED_PROXIES: ${OC10_DOMAIN}
OWNCLOUD_OVERWRITE_PROTOCOL: https
OWNCLOUD_OVERWRITE_HOST: ${OC10_DOMAIN}
OWNCLOUD_APPS_ENABLE: "openidconnect,oauth2,user_ldap,graphapi"
OWNCLOUD_LOG_LEVEL: 0
volumes:
- files:/mnt/data
- tmp:/tmp/shared
labels:
- "traefik.enable=true"
- "traefik.http.services.oc10.loadbalancer.server.port=8080"
- "traefik.docker.network=ocisnet"
- "traefik.protocol=https"
# ssl config
- "traefik.http.routers.oc10.rule=Host(`${OC10_DOMAIN}`)"
- "traefik.http.routers.oc10.entrypoints=websecure"
- "traefik.http.routers.oc10.tls.certresolver=oc10"
# http -> https forwarding
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
- "traefik.http.routers.oc10-redirs.rule=Host(`${OC10_DOMAIN}`)"
- "traefik.http.routers.oc10-redirs.entrypoints=web"
- "traefik.http.routers.oc10-redirs.middlewares=redirect-to-https"
ocis:
image: owncloud/ocis:latest
ports:
- 9200:9200
environment:
OCIS_DOMAIN: ${OCIS_DOMAIN}
PROXY_CONFIG_FILE: "/config/proxy-config.json"
PROXY_TLS: "false"
PROXY_OIDC_ISSUER: https://${OCIS_DOMAIN}
PROXY_OIDC_INSECURE: "true"
PROXY_AUTOPROVISION_ACCOUNTS: "true"
KONNECTD_ISS: https://${OCIS_DOMAIN}
KONNECTD_IDENTIFIER_REGISTRATION_CONF: "/config/identifier-registration.yml"
KONNECTD_TLS: 0
KONNECTD_SIGNING_KID: super
GRAPH_OIDC_ENDPOINT: https://${OC10_DOMAIN}/apps/graphapi/v1.0
PHOENIX_OIDC_AUTHORITY: https://${OCIS_DOMAIN}
PHOENIX_OIDC_METADATA_URL: https://${OCIS_DOMAIN}/.well-known/openid-configuration
PHOENIX_WEB_CONFIG_SERVER: https://${OCIS_DOMAIN}
PHOENIX_WEB_CONFIG: "/config/web/config.json"
STORAGE_OIDC_ISSUER: https://${OCIS_DOMAIN}
STORAGE_TRANSFER_EXPIRES: 86400
STORAGE_FRONTEND_URL: https://${OCIS_DOMAIN}
STORAGE_DATAGATEWAY_URL: https://${OCIS_DOMAIN}/data
STORAGE_LDAP_IDP: https://${OCIS_DOMAIN}
GLAUTH_BACKEND_DATASTORE: owncloud
GLAUTH_BACKEND_SERVERS: https://${OC10_DOMAIN}/apps/graphapi/v1.0
GLAUTH_BACKEND_BASEDN: dc=example,dc=org
LDAP_URI: ldap://localhost:9125
LDAP_BINDDN: "cn=admin,dc=example,dc=org"
LDAP_BINDPW: "admin"
LDAP_BASEDN: "dc=example,dc=org"
LDAP_SCOPE: sub
LDAP_LOGIN_ATTRIBUTE: uid
LDAP_EMAIL_ATTRIBUTE: mail
LDAP_NAME_ATTRIBUTE: givenName
LDAP_UUID_ATTRIBUTE: uid
LDAP_UUID_ATTRIBUTE_TYPE: text
LDAP_FILTER: "(objectClass=posixaccount)"
volumes:
- ./ocis:/config
- ./ocis/proxy-config.json:/etc/ocis/proxy.json
labels:
- "traefik.enable=true"
- "traefik.http.services.ocis.loadbalancer.server.port=9200"
- "traefik.docker.network=ocisnet"
- "traefik.protocol=https"
# ssl config
- "traefik.http.routers.ocis.rule=Host(`${OCIS_DOMAIN}`)"
- "traefik.http.routers.ocis.entrypoints=websecure"
- "traefik.http.routers.ocis.tls.certresolver=ocis"
# http -> https forwarding
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
- "traefik.http.routers.ocis-redirs.rule=Host(`${OCIS_DOMAIN}`)"
- "traefik.http.routers.ocis-redirs.entrypoints=web"
- "traefik.http.routers.ocis-redirs.middlewares=redirect-to-https"
db:
image: webhippie/mariadb:latest
restart: always
environment:
MARIADB_ROOT_PASSWORD: owncloud
MARIADB_USERNAME: owncloud
MARIADB_PASSWORD: owncloud
MARIADB_DATABASE: owncloud
MARIADB_MAX_ALLOWED_PACKET: 128M
MARIADB_INNODB_LOG_FILE_SIZE: 256M
healthcheck:
test: ["CMD", "/usr/bin/healthcheck"]
interval: 30s
timeout: 10s
retries: 5
volumes:
- mysql:/var/lib/mysql
- backup:/var/lib/backup
redis:
image: webhippie/redis:latest
environment:
- REDIS_DATABASES=1
volumes:
- redis:/var/lib/redis

View File

@@ -0,0 +1,3 @@
FROM owncloud/server:10.6.0-beta1
ADD apps/graphapi-0.1.0.tar.gz /var/www/owncloud/apps/
COPY overlay /

View File

Binary file not shown.

View File

@@ -0,0 +1,555 @@
<?php
function getConfigFromEnv() {
if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
$domain = trim(
explode(
",",
$_SERVER['HTTP_X_FORWARDED_HOST']
)[0]
);
} else if (isset($_SERVER['SERVER_NAME'])) {
$domain = $_SERVER['SERVER_NAME'];
} else {
$domain = 'localhost';
}
$config = [
'apps_paths' => [
0 => [
"path" => OC::$SERVERROOT . "/apps",
"url" => "/apps",
"writable" => false
],
1 => [
"path" => OC::$SERVERROOT . "/custom",
"url" => "/custom",
"writable" => true
]
],
'trusted_domains' => [
0 => $domain
],
'openid-connect' => [
'provider-url' => 'https://${OCIS_DOMAIN}',
'client-id' => 'oc10',
'client-secret' => 'super',
'loginButtonName' => 'OpenId Connect',
'search-attribute' => 'preferred_username',
'mode' => 'userid',
],
'datadirectory' => getenv('OWNCLOUD_VOLUME_FILES'),
'dbtype' => getenv('OWNCLOUD_DB_TYPE'),
'dbhost' => getenv('OWNCLOUD_DB_HOST'),
'dbname' => getenv('OWNCLOUD_DB_NAME'),
'dbuser' => getenv('OWNCLOUD_DB_USERNAME'),
'dbpassword' => getenv('OWNCLOUD_DB_PASSWORD'),
'dbtableprefix' => getenv('OWNCLOUD_DB_PREFIX'),
'phoenix.baseUrl' => 'https://${OCIS_DOMAIN}',
'cors.allowed-domains' => ['https://${OCIS_DOMAIN}'],
'log_type' => 'owncloud',
'supportedDatabases' => [
'sqlite',
'mysql',
'pgsql',
],
'upgrade.disable-web' => true,
];
if (getenv('OWNCLOUD_CORS_ALLOWED_DOMAINS') != '') {
$config['cors.allowed-domains'] = explode(',', getenv('OWNCLOUD_CORS_ALLOWED_DOMAINS'));
}
if (getenv('OWNCLOUD_VERSION_HIDE') != '') {
$config['version.hide'] = getenv('OWNCLOUD_VERSION_HIDE') == 'true';
}
if (getenv('OWNCLOUD_SHOW_SERVER_HOSTNAME') != '') {
$config['show_server_hostname'] = getenv('OWNCLOUD_SHOW_SERVER_HOSTNAME') == 'true';
}
if (getenv('OWNCLOUD_DEFAULT_LANGUAGE') != '') {
$config['default_language'] = getenv('OWNCLOUD_DEFAULT_LANGUAGE');
}
if (getenv('OWNCLOUD_DEFAULT_APP') != '') {
$config['defaultapp'] = getenv('OWNCLOUD_DEFAULT_APP');
}
if (getenv('OWNCLOUD_KNOWLEDGEBASE_ENABLED') != '') {
$config['knowledgebaseenabled'] = getenv('OWNCLOUD_KNOWLEDGEBASE_ENABLED') == 'true';
}
if (getenv('OWNCLOUD_ENABLE_AVATARS') != '') {
$config['enable_avatars'] = getenv('OWNCLOUD_ENABLE_AVATARS') == 'true';
}
if (getenv('OWNCLOUD_ALLOW_USER_TO_CHANGE_DISPLAY_NAME') != '') {
$config['allow_user_to_change_display_name'] = getenv('OWNCLOUD_ALLOW_USER_TO_CHANGE_DISPLAY_NAME') == 'true';
}
if (getenv('OWNCLOUD_REMEMBER_LOGIN_COOKIE_LIFETIME') != '') {
$config['remember_login_cookie_lifetime'] = (int) getenv('OWNCLOUD_REMEMBER_LOGIN_COOKIE_LIFETIME');
}
if (getenv('OWNCLOUD_SESSION_LIFETIME') != '') {
$config['session_lifetime'] = (int) getenv('OWNCLOUD_SESSION_LIFETIME');
}
if (getenv('OWNCLOUD_SESSION_KEEPALIVE') != '') {
$config['session_keepalive'] = getenv('OWNCLOUD_SESSION_KEEPALIVE') == 'true';
}
if (getenv('OWNCLOUD_TOKEN_AUTH_ENFORCED') != '') {
$config['token_auth_enforced'] = getenv('OWNCLOUD_TOKEN_AUTH_ENFORCED') == 'true';
}
if (getenv('OWNCLOUD_CSRF_DISABLED') != '') {
$config['csrf.disabled'] = getenv('OWNCLOUD_CSRF_DISABLED') == 'true';
}
if (getenv('OWNCLOUD_SKELETON_DIRECTORY') != '') {
$config['skeletondirectory'] = getenv('OWNCLOUD_SKELETON_DIRECTORY');
}
if (getenv('OWNCLOUD_LOST_PASSWORD_LINK') != '') {
$config['lost_password_link'] = getenv('OWNCLOUD_LOST_PASSWORD_LINK');
}
if (getenv('OWNCLOUD_ACCOUNTS_ENABLE_MEDIAL_SEARCH') != '') {
$config['accounts.enable_medial_search'] = getenv('OWNCLOUD_ACCOUNTS_ENABLE_MEDIAL_SEARCH') == 'true';
}
if (getenv('OWNCLOUD_USER_SEARCH_MIN_LENGTH') != '') {
$config['user.search_min_length'] = (int) getenv('OWNCLOUD_USER_SEARCH_MIN_LENGTH');
}
if (getenv('OWNCLOUD_MAIL_DOMAIN') != '') {
$config['mail_domain'] = getenv('OWNCLOUD_MAIL_DOMAIN');
}
if (getenv('OWNCLOUD_MAIL_FROM_ADDRESS') != '') {
$config['mail_from_address'] = getenv('OWNCLOUD_MAIL_FROM_ADDRESS');
}
if (getenv('OWNCLOUD_MAIL_SMTP_DEBUG') != '') {
$config['mail_smtpdebug'] = getenv('OWNCLOUD_MAIL_SMTP_DEBUG') == 'true';
}
if (getenv('OWNCLOUD_MAIL_SMTP_MODE') != '') {
$config['mail_smtpmode'] = getenv('OWNCLOUD_MAIL_SMTP_MODE');
}
if (getenv('OWNCLOUD_MAIL_SMTP_HOST') != '') {
$config['mail_smtphost'] = getenv('OWNCLOUD_MAIL_SMTP_HOST');
}
if (getenv('OWNCLOUD_MAIL_SMTP_PORT') != '') {
$config['mail_smtpport'] = (int) getenv('OWNCLOUD_MAIL_SMTP_PORT');
}
if (getenv('OWNCLOUD_MAIL_SMTP_TIMEOUT') != '') {
$config['mail_smtptimeout'] = (int) getenv('OWNCLOUD_MAIL_SMTP_TIMEOUT');
}
if (getenv('OWNCLOUD_MAIL_SMTP_SECURE') != '') {
$config['mail_smtpsecure'] = getenv('OWNCLOUD_MAIL_SMTP_SECURE');
}
if (getenv('OWNCLOUD_MAIL_SMTP_AUTH') != '') {
$config['mail_smtpauth'] = getenv('OWNCLOUD_MAIL_SMTP_AUTH') == 'true';
}
if (getenv('OWNCLOUD_MAIL_SMTP_AUTH_TYPE') != '') {
$config['mail_smtpauthtype'] = getenv('OWNCLOUD_MAIL_SMTP_AUTH_TYPE');
}
if (getenv('OWNCLOUD_MAIL_SMTP_NAME') != '') {
$config['mail_smtpname'] = getenv('OWNCLOUD_MAIL_SMTP_NAME');
}
if (getenv('OWNCLOUD_MAIL_SMTP_PASSWORD') != '') {
$config['mail_smtppassword'] = getenv('OWNCLOUD_MAIL_SMTP_PASSWORD');
}
if (getenv('OWNCLOUD_OVERWRITE_HOST') != '') {
$config['overwritehost'] = getenv('OWNCLOUD_OVERWRITE_HOST');
}
if (getenv('OWNCLOUD_OVERWRITE_PROTOCOL') != '') {
$config['overwriteprotocol'] = getenv('OWNCLOUD_OVERWRITE_PROTOCOL');
}
if (getenv('OWNCLOUD_OVERWRITE_WEBROOT') != '') {
$config['overwritewebroot'] = getenv('OWNCLOUD_OVERWRITE_WEBROOT');
}
if (getenv('OWNCLOUD_OVERWRITE_COND_ADDR') != '') {
$config['overwritecondaddr'] = getenv('OWNCLOUD_OVERWRITE_COND_ADDR');
}
if (getenv('OWNCLOUD_OVERWRITE_CLI_URL') != '') {
$config['overwrite.cli.url'] = getenv('OWNCLOUD_OVERWRITE_CLI_URL');
}
if (getenv('OWNCLOUD_HTACCESS_REWRITE_BASE') != '') {
$config['htaccess.RewriteBase'] = getenv('OWNCLOUD_HTACCESS_REWRITE_BASE');
}
if (getenv('OWNCLOUD_PROXY') != '') {
$config['proxy'] = getenv('OWNCLOUD_PROXY');
}
if (getenv('OWNCLOUD_PROXY_USERPWD') != '') {
$config['proxyuserpwd'] = getenv('OWNCLOUD_PROXY_USERPWD');
}
if (getenv('OWNCLOUD_TRASHBIN_RETENTION_OBLIGATION') != '') {
$config['trashbin_retention_obligation'] = getenv('OWNCLOUD_TRASHBIN_RETENTION_OBLIGATION');
}
if (getenv('OWNCLOUD_TRASHBIN_PURGE_LIMIT') != '') {
$config['trashbin_purge_limit'] = (int) getenv('OWNCLOUD_TRASHBIN_PURGE_LIMIT');
}
if (getenv('OWNCLOUD_VERSIONS_RETENTION_OBLIGATION') != '') {
$config['versions_retention_obligation'] = getenv('OWNCLOUD_VERSIONS_RETENTION_OBLIGATION');
}
if (getenv('OWNCLOUD_UPDATE_CHECKER') != '') {
$config['updatechecker'] = getenv('OWNCLOUD_UPDATE_CHECKER') == 'true';
}
if (getenv('OWNCLOUD_UPDATER_SERVER_URL') != '') {
$config['updater.server.url'] = getenv('OWNCLOUD_UPDATER_SERVER_URL');
}
if (getenv('OWNCLOUD_HAS_INTERNET_CONNECTION') != '') {
$config['has_internet_connection'] = getenv('OWNCLOUD_HAS_INTERNET_CONNECTION') == 'true';
}
if (getenv('OWNCLOUD_CHECK_FOR_WORKING_WELLKNOWN_SETUP') != '') {
$config['check_for_working_wellknown_setup'] = getenv('OWNCLOUD_CHECK_FOR_WORKING_WELLKNOWN_SETUP') == 'true';
}
if (getenv('OWNCLOUD_OPERATION_MODE') != '') {
$config['operation.mode'] = getenv('OWNCLOUD_OPERATION_MODE');
}
if (getenv('OWNCLOUD_LOG_FILE') != '') {
$config['logfile'] = getenv('OWNCLOUD_LOG_FILE');
}
if (getenv('OWNCLOUD_LOG_LEVEL') != '') {
$config['loglevel'] = (int) getenv('OWNCLOUD_LOG_LEVEL');
}
if (getenv('OWNCLOUD_LOG_DATE_FORMAT') != '') {
$config['logdateformat'] = getenv('OWNCLOUD_LOG_DATE_FORMAT');
}
if (getenv('OWNCLOUD_LOG_TIMEZONE') != '') {
$config['logtimezone'] = getenv('OWNCLOUD_LOG_TIMEZONE');
}
if (getenv('OWNCLOUD_CRON_LOG') != '') {
$config['cron_log'] = getenv('OWNCLOUD_CRON_LOG') == 'true';
}
if (getenv('OWNCLOUD_LOG_ROTATE_SIZE') != '') {
$config['log_rotate_size'] = (int) getenv('OWNCLOUD_LOG_ROTATE_SIZE');
}
if (getenv('OWNCLOUD_ENABLE_PREVIEWS') != '') {
$config['enable_previews'] = getenv('OWNCLOUD_ENABLE_PREVIEWS') == 'true';
}
if (getenv('OWNCLOUD_PREVIEW_MAX_X') != '') {
$config['preview_max_x'] = (int) getenv('OWNCLOUD_PREVIEW_MAX_X');
}
if (getenv('OWNCLOUD_PREVIEW_MAX_Y') != '') {
$config['preview_max_y'] = (int) getenv('OWNCLOUD_PREVIEW_MAX_Y');
}
if (getenv('OWNCLOUD_PREVIEW_MAX_SCALE_FACTOR') != '') {
$config['preview_max_scale_factor'] = (int) getenv('OWNCLOUD_PREVIEW_MAX_SCALE_FACTOR');
}
if (getenv('OWNCLOUD_PREVIEW_MAX_FILESIZE_IMAGE') != '') {
$config['preview_max_filesize_image'] = getenv('OWNCLOUD_PREVIEW_MAX_FILESIZE_IMAGE');
}
if (getenv('OWNCLOUD_PREVIEW_LIBREOFFICE_PATH') != '') {
$config['preview_libreoffice_path'] = getenv('OWNCLOUD_PREVIEW_LIBREOFFICE_PATH');
}
if (getenv('OWNCLOUD_PREVIEW_OFFICE_CL_PARAMETERS') != '') {
$config['preview_office_cl_parameters'] = getenv('OWNCLOUD_PREVIEW_OFFICE_CL_PARAMETERS');
}
if (getenv('OWNCLOUD_ENABLED_PREVIEW_PROVIDERS') != '') {
$config['enabledPreviewProviders'] = explode(',', getenv('OWNCLOUD_ENABLED_PREVIEW_PROVIDERS'));
}
if (getenv('OWNCLOUD_COMMENTS_MANAGER_FACTORY') != '') {
$config['comments.managerFactory'] = getenv('OWNCLOUD_COMMENTS_MANAGER_FACTORY');
}
if (getenv('OWNCLOUD_SYSTEMTAGS_MANAGER_FACTORY') != '') {
$config['systemtags.managerFactory'] = getenv('OWNCLOUD_SYSTEMTAGS_MANAGER_FACTORY');
}
if (getenv('OWNCLOUD_MAINTENANCE') != '') {
$config['maintenance'] = getenv('OWNCLOUD_MAINTENANCE') == 'true';
}
if (getenv('OWNCLOUD_SINGLEUSER') != '') {
$config['singleuser'] = getenv('OWNCLOUD_SINGLEUSER');
}
if (getenv('OWNCLOUD_ENABLE_CERTIFICATE_MANAGEMENT') != '') {
$config['enable_certificate_management'] = getenv('OWNCLOUD_ENABLE_CERTIFICATE_MANAGEMENT');
}
if (getenv('OWNCLOUD_MEMCACHE_LOCAL') != '') {
$config['memcache.local'] = getenv('OWNCLOUD_MEMCACHE_LOCAL');
}
if (getenv('OWNCLOUD_CACHE_PATH') != '') {
$config['cache_path'] = getenv('OWNCLOUD_CACHE_PATH');
}
if (getenv('OWNCLOUD_CACHE_CHUNK_GC_TTL') != '') {
$config['cache_chunk_gc_ttl'] = (int) getenv('OWNCLOUD_CACHE_CHUNK_GC_TTL');
}
if (getenv('OWNCLOUD_DAV_CHUNK_BASE_DIR') != '') {
$config['dav.chunk_base_dir'] = getenv('OWNCLOUD_DAV_CHUNK_BASE_DIR');
}
if (getenv('OWNCLOUD_SHARING_MANAGER_FACTORY') != '') {
$config['sharing.managerFactory'] = getenv('OWNCLOUD_SHARING_MANAGER_FACTORY');
}
if (getenv('OWNCLOUD_SHARING_FEDERATION_ALLOW_HTTP_FALLBACK') != '') {
$config['sharing.federation.allowHttpFallback'] = getenv('OWNCLOUD_SHARING_FEDERATION_ALLOW_HTTP_FALLBACK') == 'true';
}
if (getenv('OWNCLOUD_SQLITE_JOURNAL_MODE') != '') {
$config['sqlite.journal_mode'] = getenv('OWNCLOUD_SQLITE_JOURNAL_MODE');
}
if (getenv('OWNCLOUD_MYSQL_UTF8MB4') != '') {
$config['mysql.utf8mb4'] = getenv('OWNCLOUD_MYSQL_UTF8MB4') == 'true';
}
if (getenv('OWNCLOUD_TEMP_DIRECTORY') != '') {
$config['tempdirectory'] = getenv('OWNCLOUD_TEMP_DIRECTORY');
}
if (getenv('OWNCLOUD_HASHING_COST') != '') {
$config['hashingCost'] = (int) getenv('OWNCLOUD_HASHING_COST');
}
if (getenv('OWNCLOUD_BLACKLISTED_FILES') != '') {
$config['blacklisted_files'] = explode(',', getenv('OWNCLOUD_BLACKLISTED_FILES'));
}
if (getenv('OWNCLOUD_EXCLUDED_DIRECTORIES') != '') {
$config['excluded_directories'] = explode(',', getenv('OWNCLOUD_EXCLUDED_DIRECTORIES'));
}
if (getenv('OWNCLOUD_INTEGRITY_EXCLUDED_FILES') != '') {
$config['integrity.excluded.files'] = explode(',', getenv('OWNCLOUD_INTEGRITY_EXCLUDED_FILES'));
}
if (getenv('OWNCLOUD_INTEGRITY_IGNORE_MISSING_APP_SIGNATURE') != '') {
$config['integrity.ignore.missing.app.signature'] = explode(',', getenv('OWNCLOUD_INTEGRITY_IGNORE_MISSING_APP_SIGNATURE'));
}
if (getenv('OWNCLOUD_SHARE_FOLDER') != '') {
$config['share_folder'] = getenv('OWNCLOUD_SHARE_FOLDER');
}
if (getenv('OWNCLOUD_CIPHER') != '') {
$config['cipher'] = getenv('OWNCLOUD_CIPHER');
}
if (getenv('OWNCLOUD_MINIMUM_SUPPORTED_DESKTOP_VERSION') != '') {
$config['minimum.supported.desktop.version'] = getenv('OWNCLOUD_MINIMUM_SUPPORTED_DESKTOP_VERSION');
}
if (getenv('OWNCLOUD_QUOTA_INCLUDE_EXTERNAL_STORAGE') != '') {
$config['quota_include_external_storage'] = getenv('OWNCLOUD_QUOTA_INCLUDE_EXTERNAL_STORAGE') == 'true';
}
if (getenv('OWNCLOUD_FILESYSTEM_CHECK_CHANGES') != '') {
$config['filesystem_check_changes'] = (int) getenv('OWNCLOUD_FILESYSTEM_CHECK_CHANGES');
}
if (getenv('OWNCLOUD_PART_FILE_IN_STORAGE') != '') {
$config['part_file_in_storage'] = getenv('OWNCLOUD_PART_FILE_IN_STORAGE') == 'true';
}
if (getenv('OWNCLOUD_MOUNT_FILE') != '') {
$config['mount_file'] = getenv('OWNCLOUD_MOUNT_FILE');
}
if (getenv('OWNCLOUD_FILESYSTEM_CACHE_READONLY') != '') {
$config['filesystem_cache_readonly'] = getenv('OWNCLOUD_FILESYSTEM_CACHE_READONLY') == 'true';
}
if (getenv('OWNCLOUD_SECRET') != '') {
$config['secret'] = getenv('OWNCLOUD_SECRET');
}
if (getenv('OWNCLOUD_TRUSTED_PROXIES') != '') {
$config['trusted_proxies'] = explode(',', getenv('OWNCLOUD_TRUSTED_PROXIES'));
}
if (getenv('OWNCLOUD_FORWARDED_FOR_HEADERS') != '') {
$config['forwarded_for_headers'] = explode(',', getenv('OWNCLOUD_FORWARDED_FOR_HEADERS'));
}
if (getenv('OWNCLOUD_MAX_FILESIZE_ANIMATED_GIFS_PUBLIC_SHARING') != '') {
$config['max_filesize_animated_gifs_public_sharing'] = (int) getenv('OWNCLOUD_MAX_FILESIZE_ANIMATED_GIFS_PUBLIC_SHARING');
}
if (getenv('OWNCLOUD_FILELOCKING_ENABLED') != '') {
$config['filelocking.enabled'] = getenv('OWNCLOUD_FILELOCKING_ENABLED') == 'true';
}
if (getenv('OWNCLOUD_FILELOCKING_TTL') != '') {
$config['filelocking.ttl'] = getenv('OWNCLOUD_FILELOCKING_TTL');
}
if (getenv('OWNCLOUD_MEMCACHE_LOCKING') != '') {
$config['memcache.locking'] = getenv('OWNCLOUD_MEMCACHE_LOCKING');
}
if (getenv('OWNCLOUD_UPGRADE_AUTOMATIC_APP_UPDATES') != '') {
$config['upgrade.automatic-app-update'] = getenv('OWNCLOUD_UPGRADE_AUTOMATIC_APP_UPDATES') == 'true';
}
if (getenv('OWNCLOUD_DEBUG') != '') {
$config['debug'] = getenv('OWNCLOUD_DEBUG') == 'true';
}
if (getenv('OWNCLOUD_FILES_EXTERNAL_ALLOW_NEW_LOCAL') != '') {
$config['files_external_allow_create_new_local'] = getenv('OWNCLOUD_FILES_EXTERNAL_ALLOW_NEW_LOCAL') == 'true';
}
if (getenv('OWNCLOUD_SMB_LOGGING_ENABLE') != '') {
$config['smb.logging.enable'] = getenv('OWNCLOUD_SMB_LOGGING_ENABLE');
}
if (getenv('OWNCLOUD_DAV_ENABLE_ASYNC') != '') {
$config['dav.enable.async'] = getenv('OWNCLOUD_DAV_ENABLE_ASYNC');
}
if (getenv('OWNCLOUD_LICENSE_KEY') != '') {
$config['license-key'] = getenv('OWNCLOUD_LICENSE_KEY');
}
if (getenv('OWNCLOUD_MARKETPLACE_KEY') != '') {
$config['marketplace.key'] = getenv('OWNCLOUD_MARKETPLACE_KEY');
}
if (getenv('OWNCLOUD_MARKETPLACE_CA') != '') {
$config['marketplace.ca'] = getenv('OWNCLOUD_MARKETPLACE_CA');
}
if (getenv('OWNCLOUD_APPSTORE_URL') != '') {
$config['appstoreurl'] = getenv('OWNCLOUD_APPSTORE_URL');
}
if (getenv('OWNCLOUD_LOGIN_ALTERNATIVES') != '') {
$rows = explode(',', getenv('OWNCLOUD_LOGIN_ALTERNATIVES'));
foreach ($rows as $key => $value) {
parse_str($value, $opts);
$config['login.alternatives'][$key] = $opts;
}
}
switch (true) {
case getenv('OWNCLOUD_REDIS_ENABLED') && getenv('OWNCLOUD_REDIS_ENABLED') == 'true':
$config = array_merge_recursive($config, [
'memcache.distributed' => '\OC\Memcache\Redis',
'memcache.locking' => '\OC\Memcache\Redis',
]);
switch (true) {
case getenv('OWNCLOUD_REDIS_SEEDS') != '':
$config['redis.cluster']['seeds'] = explode(',', getenv('OWNCLOUD_REDIS_SEEDS'));
if (getenv('OWNCLOUD_REDIS_TIMEOUT') != '') {
$config['redis.cluster']['timeout'] = (float) getenv('OWNCLOUD_REDIS_TIMEOUT');
}
if (getenv('OWNCLOUD_REDIS_READ_TIMEOUT') != '') {
$config['redis.cluster']['read_timeout'] = (float) getenv('OWNCLOUD_REDIS_READ_TIMEOUT');
}
if (getenv('OWNCLOUD_REDIS_FAILOVER_MODE') != '') {
switch (getenv('OWNCLOUD_REDIS_FAILOVER_MODE')) {
case 'FAILOVER_NONE':
$config['redis.cluster']['failover_mode'] = \RedisCluster::FAILOVER_NONE;
case 'FAILOVER_ERROR':
$config['redis.cluster']['failover_mode'] = \RedisCluster::FAILOVER_ERROR;
case 'FAILOVER_DISTRIBUTE':
$config['redis.cluster']['failover_mode'] = \RedisCluster::FAILOVER_DISTRIBUTE;
}
}
case getenv('OWNCLOUD_REDIS_HOST') != '':
$config['redis']['host'] = getenv('OWNCLOUD_REDIS_HOST');
$config['redis']['port'] = getenv('OWNCLOUD_REDIS_PORT');
if (getenv('OWNCLOUD_REDIS_DB') != '') {
$config['redis']['dbindex'] = getenv('OWNCLOUD_REDIS_DB');
}
if (getenv('OWNCLOUD_REDIS_PASSWORD') != '') {
$config['redis']['password'] = getenv('OWNCLOUD_REDIS_PASSWORD');
}
if (getenv('OWNCLOUD_REDIS_TIMEOUT') != '') {
$config['redis']['timeout'] = (float) getenv('OWNCLOUD_REDIS_TIMEOUT');
}
}
break;
case getenv('OWNCLOUD_MEMCACHED_ENABLED') && getenv('OWNCLOUD_MEMCACHED_ENABLED') == 'true':
$config = array_merge_recursive($config, [
'memcache.distributed' => '\OC\Memcache\Memcached',
'memcache.locking' => '\OC\Memcache\Memcached',
'memcached_servers' => [
[
getenv('OWNCLOUD_MEMCACHED_HOST'),
getenv('OWNCLOUD_MEMCACHED_PORT'),
],
],
]);
if (getenv('OWNCLOUD_MEMCACHED_OPTIONS') != '') {
parse_str(getenv('OWNCLOUD_MEMCACHED_OPTIONS'), $opts);
foreach($opts as $key => $value) {
$config['memcached_options'][constant($key)] = $value;
}
}
break;
}
return $config;
}
$CONFIG = getConfigFromEnv();

View File

@@ -0,0 +1,127 @@
---
# OpenID Connect client registry.
clients:
- id: phoenix
name: OCIS
application_type: web
insecure: yes
trusted: yes
redirect_uris:
- http://ocis.domain.com/oidc-callback.html
- http://ocis.domain.com/
- https://ocis.domain.com/
- https://ocis.domain.com/oidc-callback.html
- http://ocis.domain.com/oidc-silent-redirect.html
- https://ocis.domain.com/oidc-silent-redirect.html
origins:
- http://ocis.domain.com
- https://ocis.domain.com
- id: oc10
name: OC10
application_type: web
secret: super
insecure: yes
trusted: yes
redirect_uris:
- https://oc10.domain.com/apps/openidconnect/redirect/
- https://oc10.domain.com/apps/openidconnect/redirect
origins:
- http://oc10.domain.com
- https://oc10.domain.com
- id: ocis-explorer.js
name: OCIS Graph Explorer
trusted: yes
application_type: web
insecure: yes
- id: xdXOt13JKxym1B1QcEncf2XDkLAexMBFwiT9j6EfhhHFJhs2KM9jbjTmf8JBXE69
secret: UBntmLjC2yYCeHwsyj73Uwo9TAaecAetRwMw0xYcvNL9yRdLSUi0hUAHfvCHFeFh
application_type: native
insecure: true
- id: e4rAsNUSIUs0lF4nbv9FmCeUkTlV9GdgTLDH1b5uie7syb90SzEVrbN7HIpmWJeD
secret: dInFYGV33xKzhbRmpqQltYNdfLdJIfJ9L5ISoKhNoT9qZftpdWSP71VrpGR9pmoD
application_type: native
redirect_uris:
- oc://android.owncloud.com
- id: mxd5OQDk6es5LzOzRvidJNfXLUZS2oN3oUFeXPP8LpPrhx3UroJFduGEYIBOxkY1
secret: KFeFWWEZO9TkisIQzR3fo7hfiMXlOpaqP8CFuTbSHzV1TUuGECglPxpiVKJfOXIx
application_type: native
redirect_uris:
- oc://ios.owncloud.com
- oc.ios://ios.owncloud.com
# - id: playground-trusted.js
# name: Trusted OIDC Playground
# trusted: yes
# application_type: web
# redirect_uris:
# - https://my-host:8509/
# origins:
# - https://my-host:8509
# - id: playground-trusted.js
# name: Trusted Insecure OIDC Playground
# trusted: yes
# application_type: web
# insecure: yes
# - id: client-with-keys
# secret: super
# application_type: native
# redirect_uris:
# - http://localhost
# trusted_scopes:
# - konnect/guestok
# - kopano/kwm
# jwks:
# keys:
# - kty: EC
# use: sig
# kid: client-with-keys-key-1
# crv: P-256
# x: RTZpWoRbjwX1YavmSHVBj6Cy3Yzdkkp6QLvTGB22D0c
# y: jeavjwcX0xlDSchFcBMzXSU7wGs2VPpNxWCwmxFvmF0
# request_object_signing_alg: ES256
# - id: first
# secret: lala
# application_type: native
# redirect_uris:
# - my://app
# - id: second
# secret: lulu
# application_type: native
# redirect_uris:
# - http://localhost
# External authority registry.
authorities:
# - id: my-univention
# name: Univention
# client_id: kopano-konnect
# authority_type: oidc
# jwks:
# keys:
# - kty: EC
# use: sig
# kid: example-key-1
# crv: P-256
# x: RTZpWoRbjwX1YavmSHVBj6Cy3Yzdkkp6QLvTGB22D0c
# y: jeavjwcX0xlDSchFcBMzXSU7wGs2VPpNxWCwmxFvmF0
# default: yes
# authorization_endpoint: https://my-univention/signin/v1/identifier/_/authorize
# response_type: id_token
# scopes:
# - openid
# - profile
# identity_claim_name: preferred_username
# identity_aliases:
# external-user-a: local-user-a
# external-user-b: local-user-b
# identity_alias_required: true

View File

@@ -0,0 +1,133 @@
{
"HTTP": {
"Namespace": "works.owncloud"
},
"policy_selector": {
"migration": {
"acc_found_policy" : "reva",
"acc_not_found_policy": "oc10",
"unauthenticated_policy": "oc10"
}
},
"policies": [
{
"name": "reva",
"routes": [
{
"endpoint": "/",
"backend": "http://localhost:9100"
},
{
"endpoint": "/.well-known/",
"backend": "http://localhost:9130"
},
{
"endpoint": "/konnect/",
"backend": "http://localhost:9130"
},
{
"endpoint": "/signin/",
"backend": "http://localhost:9130"
},
{
"endpoint": "/ocs/",
"backend": "http://localhost:9140"
},
{
"type": "regex",
"endpoint": "/ocs/v[12].php/cloud/user",
"backend": "http://localhost:9110"
},
{
"endpoint": "/remote.php/",
"backend": "http://localhost:9140"
},
{
"endpoint": "/dav/",
"backend": "http://localhost:9140"
},
{
"endpoint": "/webdav/",
"backend": "http://localhost:9140"
},
{
"endpoint": "/status.php",
"backend": "http://localhost:9140"
},
{
"endpoint": "/index.php/",
"backend": "http://localhost:9140"
},
{
"endpoint": "/data",
"backend": "http://localhost:9140"
},
{
"endpoint": "/api/v0/accounts",
"backend": "http://localhost:9181"
},
{
"endpoint": "/accounts.js",
"backend": "http://localhost:9181"
},
{
"endpoint": "/api/v0/settings",
"backend": "http://localhost:9190"
},
{
"endpoint": "/settings.js",
"backend": "http://localhost:9190"
}
]
},
{
"name": "oc10",
"routes": [
{
"endpoint": "/",
"backend": "http://localhost:9100"
},
{
"endpoint": "/.well-known/",
"backend": "http://localhost:9130"
},
{
"endpoint": "/konnect/",
"backend": "http://localhost:9130"
},
{
"endpoint": "/signin/",
"backend": "http://localhost:9130"
},
{
"endpoint": "/ocs/",
"backend": "http://owncloud:8080",
"apache-vhost": true
},
{
"endpoint": "/remote.php/",
"backend": "http://owncloud:8080",
"apache-vhost": true
},
{
"endpoint": "/dav/",
"backend": "http://owncloud:8080",
"apache-vhost": true
},
{
"endpoint": "/webdav/",
"backend": "http://owncloud:8080",
"apache-vhost": true
},
{
"endpoint": "/status.php",
"backend": "http://owncloud:8080"
},
{
"endpoint": "/index.php/",
"backend": "http://owncloud:8080"
}
]
}
]
}

View File

@@ -0,0 +1,49 @@
{
"server": "https://${OCIS_DOMAIN}",
"theme": "owncloud",
"version": "0.1.0",
"openIdConnect": {
"metadata_url": "https://${OCIS_DOMAIN}/.well-known/openid-configuration",
"authority": "https://${OCIS_DOMAIN}",
"client_id": "phoenix",
"response_type": "code",
"scope": "openid profile email"
},
"applications": [
{
"title": {
"en": "Classic Design",
"de": "Klassisches ownCloud"
},
"icon": "switch_ui",
"url": "https://${OC10_DOMAIN}",
"target": "_self"
},
{
"title": {"en": "Classic Settings"},
"icon": "application",
"url": "https://${OC10_DOMAIN}/index.php/settings/personal",
"target": "_self",
"menu": "user"
}
],
"apps": [
"files",
"draw-io",
"markdown-editor",
"media-viewer"
],
"options": {
"hideSearchBar": false
},
"external_apps": [
{
"id": "accounts",
"path": "/accounts.js"
},
{
"id": "settings",
"path": "/settings.js"
}
]
}

View File

@@ -0,0 +1 @@
OCIS_DOMAIN=ocis.domain.com

View File

@@ -0,0 +1,27 @@
# Deployment scenario ocis with traefik
## Setup on server
* Clone ocis repository
`git clone https://github.com/owncloud/ocis.git`
* Copy example folder to /opt
`cp deployment/examples/ocis_traefik /opt/`
* Overwrite OCIS_DOMAIN in .env with your.domain.com
`sed -i 's/ocis.domain.com/your.domain.com/g' /opt/ocis_traefik/.env`
* Overwrite redirect uri with your.domain.com in identifier-registration.yml
`sed -i 's/ocis.domain.com/your.domain.com/g' /opt/ocis_traefik/config/identifier-registration.yml`
* Change into deployment folder
`cd /opt/ocis_traefik`
* Start application stack
`docker-compose up -d`

View File

@@ -0,0 +1,18 @@
---
# OpenID Connect client registry.
clients:
- id: phoenix
name: OCIS
application_type: web
insecure: yes
trusted: yes
redirect_uris:
- http://ocis.domain.com/
- https://ocis.domain.com/
- http://ocis.domain.com/oidc-callback.html
- https://ocis.domain.com/oidc-callback.html
- http://ocis.domain.com/oidc-silent-redirect.html
- https://ocis.domain.com/oidc-silent-redirect.html
origins:
- http://ocis.domain.com
- https://ocis.domain.com

View File

@@ -0,0 +1,73 @@
version: "3.7"
services:
traefik:
image: "traefik:v2.2"
container_name: "traefik"
networks:
- ocisnet
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--serverstransport.insecureskipverify=true"
# Ocis certificate resolver
- "--certificatesresolvers.ocis.acme.tlschallenge=true"
- "--certificatesresolvers.ocis.acme.caserver=https://acme-v02.api.letsencrypt.org/directory"
- "--certificatesresolvers.ocis.acme.email=user@${OCIS_DOMAIN}"
- "--certificatesresolvers.ocis.acme.storage=/letsencrypt/acme-ocis.json"
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- "letsencrypt:/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
ocis:
container_name: ocis
image: owncloud/ocis:latest
ports:
- 9200:9200
hostname: ocis
networks:
- ocisnet
volumes:
- ./config:/etc/ocis
environment:
OCIS_DOMAIN: ${OCIS_DOMAIN}
PROXY_TLS: "false"
PROXY_HTTP_ADDR: 0.0.0.0:9200
PROXY_OIDC_ISSUER: https://${OCIS_DOMAIN}
PROXY_OIDC_INSECURE: "true"
KONNECTD_ISS: https://${OCIS_DOMAIN}
KONNECTD_IDENTIFIER_REGISTRATION_CONF: "/etc/ocis/identifier-registration.yml"
KONNECTD_TLS: 1
GRAPH_OIDC_ENDPOINT: https://${OCIS_DOMAIN}
PHOENIX_OIDC_AUTHORITY: https://${OCIS_DOMAIN}
PHOENIX_OIDC_METADATA_URL: https://${OCIS_DOMAIN}/.well-known/openid-configuration
PHOENIX_WEB_CONFIG_SERVER: https://${OCIS_DOMAIN}
STORAGE_OIDC_ISSUER: https://${OCIS_DOMAIN}
STORAGE_TRANSFER_EXPIRES: 86400
STORAGE_FRONTEND_URL: https://${OCIS_DOMAIN}
STORAGE_DATAGATEWAY_URL: https://${OCIS_DOMAIN}/data
STORAGE_LDAP_IDP: https://${OCIS_DOMAIN}
labels:
- "traefik.enable=true"
- "traefik.http.services.ocis.loadbalancer.server.port=9200"
- "traefik.docker.network=ocisnet"
- "traefik.protocol=https"
# ssl config
- "traefik.http.routers.ocis.rule=Host(`${OCIS_DOMAIN}`)"
- "traefik.http.routers.ocis.entrypoints=websecure"
- "traefik.http.routers.ocis.tls.certresolver=ocis"
# http -> https forwarding
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
- "traefik.http.routers.ocis-redirs.rule=Host(`${OCIS_DOMAIN}`)"
- "traefik.http.routers.ocis-redirs.entrypoints=web"
- "traefik.http.routers.ocis-redirs.middlewares=redirect-to-https"
networks:
ocisnet:

View File

@@ -57,5 +57,12 @@ The program provides a few sub-commands on execution. The available configuratio
The server command is used to start the grpc server. For further help please execute:
{{< highlight txt >}}
ocis-accounts server --help
accounts server --help
{{< / highlight >}}
### Version
The version command lists the versions of all running instances. For further help please execute:
{{< highlight txt >}}
accounts version --help
{{< /highlight >}}

View File

@@ -42,7 +42,7 @@ The program provides a few sub-commands on execution. The available configuratio
The server command is used to start the http and debug server on two addresses within a single process. The http server is serving the general webservice while the debug server is used for health check, readiness check and to server the metrics mentioned below. For further help please execute:
{{< highlight txt >}}
ocis-konnectd server --help
konnectd server --help
{{< / highlight >}}
### Health
@@ -50,9 +50,16 @@ ocis-konnectd server --help
The health command is used to execute a health check, if the exit code equals zero the service should be up and running, if the exist code is greater than zero the service is not in a healthy state. Generally this command is used within our Docker containers, it could also be used within Kubernetes.
{{< highlight txt >}}
ocis-konnectd health --help
konnectd health --help
{{< / highlight >}}
### Version
The version command lists the versions of all running instances. For further help please execute:
{{< highlight txt >}}
konnectd version --help
{{< /highlight >}}
## Metrics
This service provides some [Prometheus](https://prometheus.io/) metrics through the debug endpoint, you can optionally secure the metrics endpoint by some random token, which got to be configured through one of the flag `--debug-token` or the environment variable `KONNECTD_DEBUG_TOKEN` mentioned above. By default the metrics endpoint is bound to `http://0.0.0.0:9134/metrics`.

View File

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

View File

@@ -42,7 +42,7 @@ The program provides a few sub-commands on execution. The available configuratio
The server command is used to start the http and debug server on two addresses within a single process. The http server is serving the general webservice while the debug server is used for health check, readiness check and to server the metrics mentioned below. For further help please execute:
{{< highlight txt >}}
ocis-ocs server --help
ocs server --help
{{< / highlight >}}
### Health
@@ -50,9 +50,16 @@ ocis-ocs server --help
The health command is used to execute a health check, if the exit code equals zero the service should be up and running, if the exist code is greater than zero the service is not in a healthy state. Generally this command is used within our Docker containers, it could also be used within Kubernetes.
{{< highlight txt >}}
ocis-ocs health --help
ocs health --help
{{< / highlight >}}
### Version
The version command lists the versions of all running instances. For further help please execute:
{{< highlight txt >}}
ocs version --help
{{< /highlight >}}
## Metrics
This service provides some [Prometheus](https://prometheus.io/) metrics through the debug endpoint, you can optionally secure the metrics endpoint by some random token, which got to be configured through one of the flag `--debug-token` or the environment variable `OCS_DEBUG_TOKEN` mentioned above. By default the metrics endpoint is bound to `http://0.0.0.0:9114/metrics`.

View File

@@ -42,5 +42,12 @@ The program provides a few sub-commands on execution. The available configuratio
The server command is used to start the http server. For further help please execute:
{{< highlight txt >}}
ocis-proxy server --help
proxy server --help
{{< / highlight >}}
### Version
The version command lists the versions of all running instances. For further help please execute:
{{< highlight txt >}}
proxy version --help
{{< /highlight >}}

View File

@@ -160,7 +160,7 @@ The program provides a few sub-commands on execution. The available configuratio
The server command is used to start the http and debug server on two addresses within a single process. The http server is serving the general webservice while the debug server is used for health check, readiness check and to server the metrics mentioned below. For further help please execute:
{{< highlight txt >}}
ocis-settings server --help
settings server --help
{{< / highlight >}}
### Health
@@ -168,9 +168,16 @@ ocis-settings server --help
The health command is used to execute a health check, if the exit code equals zero the service should be up and running, if the exist code is greater than zero the service is not in a healthy state. Generally this command is used within our Docker containers, it could also be used within Kubernetes.
{{< highlight txt >}}
ocis-settings health --help
settings health --help
{{< / highlight >}}
### Version
The version command lists the versions of all running instances. For further help please execute:
{{< highlight txt >}}
settings version --help
{{< /highlight >}}
## Metrics
This service provides some [Prometheus](https://prometheus.io/) metrics through the debug endpoint, you can optionally secure the metrics endpoint by some random token, which got to be configured through one of the flag `--debug-token` or the environment variable `SETTINGS_DEBUG_TOKEN` mentioned above. By default the metrics endpoint is bound to `http://0.0.0.0:9194/metrics`.

View File

@@ -11,35 +11,35 @@ This service provides an ocis extension that wraps [reva](https://github.com/cs3
It uses the port range 9140-9179 to preconfigure several services.
| port | service |
+------+---------+
| 9109 | health? |
| 9140 | frontend |
| 9141 | frontend debug |
| 9142 | gateway |
| 9143 | gateway debug |
| 9144 | users |
| 9145 | users debug |
| 9146 | authbasic |
| 9147 | authbasic debug |
| 9148 | authbearer |
| 9149 | authbearer debug |
| 9150 | sharing |
| 9151 | sharing debug |
| 9152 | storage root |
| 9153 | storage root debug |
| 9154 | storage home |
| 9155 | storage home debug |
| 9156 | storage home data |
| 9157 | storage home data debug |
| 9158 | storage eos |
| 9159 | storage eos debug |
| 9160 | storage eos data |
| 9161 | storage eos data debug |
| 9162 | storage oc |
| 9163 | storage oc debug |
| 9164 | storage oc data |
| 9165 | storage oc data debug |
| port | service |
|-----------|-----------------------------------------------|
| 9109 | health? |
| 9140 | frontend |
| 9141 | frontend debug |
| 9142 | gateway |
| 9143 | gateway debug |
| 9144 | users |
| 9145 | users debug |
| 9146 | authbasic |
| 9147 | authbasic debug |
| 9148 | authbearer |
| 9149 | authbearer debug |
| 9150 | sharing |
| 9151 | sharing debug |
| 9152 | storage root |
| 9153 | storage root debug |
| 9154 | storage home |
| 9155 | storage home debug |
| 9156 | storage home data |
| 9157 | storage home data debug |
| 9158 | storage eos |
| 9159 | storage eos debug |
| 9160 | storage eos data |
| 9161 | storage eos data debug |
| 9162 | storage oc |
| 9163 | storage oc debug |
| 9164 | storage oc data |
| 9165 | storage oc data debug |
| 9166-9177 | reserved for s3, wnd, custom + data providers |
| 9178 | storage public link |
| 9179 | storage public link data |
| 9178 | storage public link |
| 9179 | storage public link data |

View File

@@ -158,11 +158,11 @@ For a simple docker-compose setup, you can create a volume which will be used by
The CERN eos storage has evolved with ownCloud and natively supports id based lookup, ETag propagation, subtree size accounting, sharing, trash and versions. To use it you need to change the default configuration of the `storage storage-home` command (or have a look at the Makefile ̀ eos-start` target):
```
export STORAGE_STORAGE_HOME_DRIVER=eos
export STORAGE_STORAGE_EOS_NAMESPACE=/eos
export STORAGE_STORAGE_EOS_MASTER_URL="root://eos-mgm1.eoscluster.cern.ch:1094"
export STORAGE_STORAGE_EOS_ENABLE_HOME=true
export STORAGE_STORAGE_EOS_LAYOUT="dockertest/{{.Username}}"
export STORAGE_HOME_DRIVER=eos
export STORAGE_DRIVER_EOS_NAMESPACE=/eos
export STORAGE_DRIVER_EOS_MASTER_URL="root://eos-mgm1.eoscluster.cern.ch:1094"
export STORAGE_DRIVER_EOS_ENABLE_HOME=true
export STORAGE_DRIVER_EOS_LAYOUT="dockertest/{{.Username}}"
```
Running it locally also requires the `eos` and `xrootd` binaries. Running it using `make eos-start` will use CentOS based containers that already have the necessary packages installed.

View File

@@ -1,148 +0,0 @@
---
title: "Testing"
date: 2018-05-02T00:00:00+00:00
weight: 37
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/storage
geekdocFilePath: testing.md
---
## API Acceptance tests
We are using the ownCloud 10 API acceptance testsuite against ocis. To set this up you need the owncloud 10 core repo, a ldap server that the acceptance tests can use to manage users, a redis server for file-versions and the ocis-reva code.
### Getting the tests
All you need to do to get the acceptance tests is check out the core repo:
```
git clone https://github.com/owncloud/core.git
```
### Run a ldap server in a docker container
The ownCloud 10 acceptance tests will need write permission. You can start a suitable ldap server in a docker container with:
```
docker run --hostname ldap.my-company.com \
-e LDAP_TLS_VERIFY_CLIENT=never \
-e LDAP_DOMAIN=owncloud.com \
-e LDAP_ORGANISATION=ownCloud \
-e LDAP_ADMIN_PASSWORD=admin \
--name docker-slapd \
-p 127.0.0.1:389:389 \
-p 636:636 -d osixia/openldap
```
### Run a redis server in a docker container
File versions need a redis server. Start one with docker by using:
`docker run -e REDIS_DATABASES=1 -p 6379:6379 -d webhippie/redis:latest`
### Run ocis-reva with that ldap server
`storage` provides multiple subcommands. To configure them all via env vars you can export these environment variables.
```
export STORAGE_USERS_DRIVER=ldap
export STORAGE_LDAP_HOSTNAME=localhost
export STORAGE_LDAP_PORT=636
export STORAGE_LDAP_BASE_DN='dc=owncloud,dc=com'
export STORAGE_LDAP_USERFILTER='(&(objectclass=posixAccount)(cn=%s))'
export STORAGE_LDAP_GROUPFILTER='(&(objectclass=posixGroup)(cn=%s))'
export STORAGE_LDAP_BIND_DN='cn=admin,dc=owncloud,dc=com'
export STORAGE_LDAP_BIND_PASSWORD=admin
export STORAGE_LDAP_SCHEMA_UID=uid
export STORAGE_LDAP_SCHEMA_MAIL=mail
export STORAGE_LDAP_SCHEMA_DISPLAYNAME=displayName
export STORAGE_LDAP_SCHEMA_CN=cn
export STORAGE_FRONTEND_URL=http://localhost:9140 # needed because the proxy is not started
export STORAGE_DATAGATEWAY_URL=http://localhost:9140/data # needed because the proxy is not started
```
Then you need to start the ocis-reva services
```
bin/storage frontend & \
bin/storage gateway & \
bin/storage auth-basic & \
bin/storage auth-bearer & \
bin/storage sharing & \
bin/storage storage-home & \
bin/storage storage-home-data & \
bin/storage storage-oc & \
bin/storage storage-oc-data & \
bin/storage users &
```
### Run the API acceptance tests
In the ownCloud 10 core repo run
```
make test-acceptance-api \
TEST_SERVER_URL=https://localhost:9200 \
TEST_EXTERNAL_USER_BACKENDS=true \
TEST_OCIS=true \
OCIS_REVA_DATA_ROOT=/var/tmp/ocis/owncloud/ \
BEHAT_FILTER_TAGS='~@notToImplementOnOCIS&&~@toImplementOnOCIS&&~@preview-extension-required' \
SKELETON_DIR=apps/testing/data/apiSkeleton
```
Make sure to adjust the settings `TEST_SERVER_URL`,`OCIS_REVA_DATA_ROOT` and `SKELETON_DIR` according to your environment.
This will run all tests that are relevant to OCIS.
To run a single test add `BEHAT_FEATURE=<feature file>` and specify the path to the feature file and an optional line number. For example: `BEHAT_FEATURE='tests/acceptance/features/apiWebdavUpload1/uploadFile.feature:12'`
### use existing tests for BDD
As a lot of scenarios are written for oC10, we can use those tests for Behaviour driven development in ocis.
Every scenario that does not work in OCIS with OC storage, is listed in `tests/acceptance/expected-failures-on-OC-storage.txt` with a link to the related issue.
Similarly, scenarios that do not work in OCIS with EOS storage are listed in `tests/acceptance/expected-failures-on-EOS-storage.txt`.
Scenarios from the oC10 API acceptance tests are run in the ordinary acceptance test pipeline in CI. The scenarios that fail are checked against the
expected failures. If there are any differences then the CI pipeline fails.
Additionally, some issues have scenarios that demonstrate the current buggy behaviour in ocis(reva).
Those scenarios are in this ocis-reva repository in `tests/acceptance/features/apiOcisSpecific`.
Have a look into the [documentation](https://doc.owncloud.com/server/developer_manual/testing/acceptance-tests.html#writing-scenarios-for-bugs) to understand why we are writing those tests.
Also, ocis behaves partly differently with EOS-Storage and OC-Storage. There are scenarios that do not work in OCIS when run on EOS-storage, but works when on OC-Storage, and vice-versa. For those kind of scenarios, ` @skipOnOcis-EOS-Storage` and `@skipOnOcis-OC-Storage` tags are used. For instance, for a scenario that fails on EOS-Storage but passes on OC-Storage, we use `@skipOnOcis-EOS-Storage` tag to let it run on OC-Storage, where it works as expected, instead of skipping the test completely.
If you want to work on a specific issue
1. adjust the core commit id to the latest commit in core so that CI will run the latest test code and scenarios from core.
For that change `coreCommit` in the `config` section:
config = {
'apiTests': {
'coreBranch': 'master',
'coreCommit': 'a06b1bd5ba8e5244bfaf7fa04f441961e6fb0daa',
'numberOfParts': 2
}
}
2. locally run each of the tests marked with that issue in the expected failures file:
E.g.:
```
make test-acceptance-api \
TEST_SERVER_URL=https://localhost:9200 \
TEST_EXTERNAL_USER_BACKENDS=true \
TEST_OCIS=true \
OCIS_REVA_DATA_ROOT=/var/tmp/ocis/owncloud/ \
BEHAT_FEATURE='tests/acceptance/features/apiComments/comments.feature:123'
```
3. the tests will fail, try to understand how and why they are failing
4. fix the code
5. go back to 2. and repeat till the tests are passing.
6. remove those tests from the expected failures file.
7. run each of the local tests that were demonstrating the **buggy** behavior. They should fail.
8. delete each of the local tests that were demonstrating the **buggy** behavior.
9. make a PR that has the fixed code, relevant lines removed from the expected failures file and bug demonstration tests deleted.
If the changes also affect the `ocis` repository make sure the changes get ported over there.
That will need the fixed code in `storage` to be applied to `ocis` along with the test-related changes.
### Notes
- in a normal case the test-code cleans up users after the test-run, but if a test-run is interrupted (e.g. by CTRL+C) users might have been left on the LDAP server. In that case rerunning the tests requires wiping the users in the ldap server, otherwise the tests will fail when trying to populate the users. This can be done by simply running `docker stop docker-slapd && docker rm docker-slapd` and [restarting the LDAP server container](#run-a-ldap-server-in-a-docker-container)
- the tests usually create users in the OU `TestUsers` with usernames specified in the feature file. If not defined in the feature file, most users have the password `123456`, defined by `regularUserPassword` in `behat.yml`, but other passwords are also used, see [`\FeatureContext::getPasswordForUser()`](https://github.com/owncloud/core/blob/master/tests/acceptance/features/bootstrap/FeatureContext.php#L386) for mapping and [`\FeatureContext::__construct`](https://github.com/owncloud/core/blob/master/tests/acceptance/features/bootstrap/FeatureContext.php#L1668) for the password definitions.

View File

@@ -160,7 +160,7 @@ The program provides a few sub-commands on execution. The available configuratio
The server command is used to start the http and debug server on two addresses within a single process. The http server is serving the general webservice while the debug server is used for health check, readiness check and to server the metrics mentioned below. For further help please execute:
{{< highlight txt >}}
ocis-store server --help
store server --help
{{< / highlight >}}
### Health
@@ -168,9 +168,16 @@ ocis-store server --help
The health command is used to execute a health check, if the exit code equals zero the service should be up and running, if the exist code is greater than zero the service is not in a healthy state. Generally this command is used within our Docker containers, it could also be used within Kubernetes.
{{< highlight txt >}}
ocis-store health --help
store health --help
{{< / highlight >}}
### Version
The version command lists the versions of all running instances. For further help please execute:
{{< highlight txt >}}
store version --help
{{< /highlight >}}
## Metrics
This service provides some [Prometheus](https://prometheus.io/) metrics through the debug endpoint, you can optionally secure the metrics endpoint by some random token, which got to be configured through one of the flag `--debug-token` or the environment variable `STORE_DEBUG_TOKEN` mentioned above. By default the metrics endpoint is bound to `http://0.0.0.0:9460/metrics`.

View File

@@ -189,6 +189,13 @@ The health command is used to execute a health check, if the exit code equals ze
{{ Name }} health --help
{{< / highlight >}}
### Version
The version command lists the versions of all running instances. For further help please execute:
{{< highlight txt >}}
{{ Name }} version --help
{{< /highlight >}}
## Metrics
This service provides some [Prometheus](https://prometheus.io/) metrics through the debug endpoint, you can optionally secure the metrics endpoint by some random token, which got to be configured through one of the flag `--debug-token` or the environment variable `THUMBNAILS_DEBUG_TOKEN` mentioned above. By default the metrics endpoint is bound to `http://0.0.0.0:9114/metrics`.

View File

@@ -157,7 +157,7 @@ The program provides a few sub-commands on execution. The available configuratio
The server command is used to start the http and debug server on two addresses within a single process. The http server is serving the general webservice while the debug server is used for health check, readiness check and to server the metrics mentioned below. For further help please execute:
{{< highlight txt >}}
ocis-webdav server --help
webdav server --help
{{< / highlight >}}
#### Health
@@ -165,9 +165,16 @@ ocis-webdav server --help
The health command is used to execute a health check, if the exit code equals zero the service should be up and running, if the exist code is greater than zero the service is not in a healthy state. Generally this command is used within our Docker containers, it could also be used within Kubernetes.
{{< highlight txt >}}
ocis-webdav health --help
webdav health --help
{{< / highlight >}}
### Version
The version command lists the versions of all running instances. For further help please execute:
{{< highlight txt >}}
webdav version --help
{{< /highlight >}}
### Metrics
This service provides some [Prometheus](https://prometheus.io/) metrics through the debug endpoint, you can optionally secure the metrics endpoint by some random token, which got to be configured through one of the flag `--debug-token` or the environment variable `WEBDAV_DEBUG_TOKEN` mentioned above. By default the metrics endpoint is bound to `http://0.0.0.0:9119/metrics`.

View File

@@ -1,232 +0,0 @@
---
title: "Configuration"
date: "2020-10-05T21:19:39+0200"
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/ocis
geekdocFilePath: configuration.md
---
{{< toc >}}
## Configuration
oCIS Single Binary is not responsible for configuring extensions. Instead, each extension could either be configured by environment variables, cli flags or config files.
Each extension has its dedicated documentation page (e.g. https://owncloud.github.io/extensions/ocis_proxy/configuration) which lists all possible configurations. Config files and environment variables are picked up if you use the `./bin/ocis server` command within the oCIS single binary. Command line flags must be set explicitly on the extensions subcommands.
### Configuration using config files
Out of the box extensions will attempt to read configuration details from:
```console
/etc/ocis
$HOME/.ocis
./config
```
For this configuration to be picked up, have a look at your extension `root` command and look for which default config name it has assigned. *i.e: ocis-proxy reads `proxy.json | yaml | toml ...`*.
So far we support the file formats `JSON` and `YAML`, if you want to get a full example configuration just take a look at [our repository](https://github.com/owncloud/ocis/tree/master/config), there you can always see the latest configuration format. These example configurations include all available options and the default values. The configuration file will be automatically loaded if it's placed at `/etc/ocis/ocis.yml`, `${HOME}/.ocis/ocis.yml` or `$(pwd)/config/ocis.yml`.
### Envrionment variables
If you prefer to configure the service with environment variables you can see the available variables below.
### Commandline flags
If you prefer to configure the service with commandline flags you can see the available variables below. Command line flags are only working when calling the subcommand directly.
## Root Command
ownCloud Infinite Scale Stack
Usage: `ocis [global options] command [command options] [arguments...]`
--config-file | $OCIS_CONFIG_FILE
: Path to config file.
--log-level | $OCIS_LOG_LEVEL
: Set logging level. Default: `info`.
--log-pretty | $OCIS_LOG_PRETTY
: Enable pretty logging. Default: `true`.
--log-color | $OCIS_LOG_COLOR
: Enable colored logging. Default: `true`.
## Sub Commands
### ocis kill
Kill an extension by name
Usage: `ocis kill [command options] [arguments...]`
### ocis server
Start fullstack server
Usage: `ocis server [command options] [arguments...]`
--tracing-enabled | $OCIS_TRACING_ENABLED
: Enable sending traces.
--tracing-type | $OCIS_TRACING_TYPE
: Tracing backend type. Default: `jaeger`.
--tracing-endpoint | $OCIS_TRACING_ENDPOINT
: Endpoint for the agent. Default: `localhost:6831`.
--tracing-collector | $OCIS_TRACING_COLLECTOR
: Endpoint for the collector. Default: `http://localhost:14268/api/traces`.
--tracing-service | $OCIS_TRACING_SERVICE
: Service name for tracing. Default: `ocis`.
--debug-addr | $OCIS_DEBUG_ADDR
: Address to bind debug server. Default: `0.0.0.0:9010`.
--debug-token | $OCIS_DEBUG_TOKEN
: Token to grant metrics access.
--debug-pprof | $OCIS_DEBUG_PPROF
: Enable pprof debugging.
--debug-zpages | $OCIS_DEBUG_ZPAGES
: Enable zpages debugging.
--http-addr | $OCIS_HTTP_ADDR
: Address to bind http server. Default: `0.0.0.0:9000`.
--http-root | $OCIS_HTTP_ROOT
: Root path of http server. Default: `/`.
--grpc-addr | $OCIS_GRPC_ADDR
: Address to bind grpc server. Default: `0.0.0.0:9001`.
### ocis run
Runs an extension
Usage: `ocis run [command options] [arguments...]`
### ocis health
Check health status
Usage: `ocis health [command options] [arguments...]`
--debug-addr | $OCIS_DEBUG_ADDR
: Address to debug endpoint. Default: `0.0.0.0:9010`.
### ocis list
Lists running ocis extensions
Usage: `ocis list [command options] [arguments...]`
### List of available Extension subcommands
There are more subcommands to start the individual extensions. Please check the documentation about their usage and options in the dedicated section of the documentation.
#### ocis konnectd
Start konnectd server
#### ocis storage-frontend
Start storage frontend
#### ocis accounts
Start accounts server
#### ocis storage-storage-root
Start storage root storage
#### ocis storage-gateway
Start storage gateway
#### ocis storage-storage-home
Start storage storage service for home mount
#### ocis storage-storage-public-link
Start storage public link storage
#### ocis store
Start a go-micro store
#### ocis glauth
Start glauth server
#### ocis storage-auth-bearer
Start storage auth-bearer service
#### ocis storage-sharing
Start storage sharing service
#### ocis webdav
Start webdav server
#### ocis storage-storage-oc-data
Start storage storage data provider for oc mount
#### ocis thumbnails
Start thumbnails server
#### ocis proxy
Start proxy server
#### ocis settings
Start settings server
#### ocis storage-auth-basic
Start storage auth-basic service
#### ocis storage-storage-metadata
Start storage storage service for metadata mount
#### ocis ocs
Start ocs server
#### ocis storage-storage-eos
Start storage storage service for eos mount
#### ocis storage-storage-eos-data
Start storage storage data provider for eos mount
#### ocis storage-storage-home-data
Start storage storage data provider for home mount
#### ocis storage-storage-oc
Start storage storage service for oc mount
#### ocis storage-users
Start storage users service
#### ocis phoenix
Start phoenix server

View File

@@ -3,14 +3,14 @@ title: "Deployment"
date: 2020-10-01T20:35:00+01:00
weight: -10
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/deployment
geekdocEditPath: edit/master/docs/ocis/deployment
geekdocFilePath: _index.md
---
{{< toc >}}
## Deployments Scenarios and Examples
This section handles deployments and operations for admins. If you are looking for a development setup, start with
This section handles deployments and operations for admins. If you are looking for a development setup, start with
### Setup oCIS
oCIS deployments are super simple, yet there are many configrations possible for advanced setups.

View File

@@ -3,7 +3,7 @@ title: "Basic Remote Setup"
date: 2020-02-27T20:35:00+01:00
weight: 16
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs
geekdocEditPath: edit/master/docs/ocis/deployment
geekdocFilePath: basic-remote-setup.md
---

View File

@@ -3,7 +3,7 @@ title: "Bridge"
date: 2020-02-27T20:35:00+01:00
weight: 30
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs
geekdocEditPath: edit/master/docs/ocis/deployment
geekdocFilePath: bridge.md
---
@@ -64,7 +64,7 @@ Enter host password for user 'admin':
### Start ocis-glauth
We are going to use the above ownCloud 10 and graphapi app to turn it into the datastore for an LDAP proxy.
We are going to use the above ownCloud 10 and graphapi app to turn it into the datastore for an LDAP proxy.
#### Grab it!
@@ -250,5 +250,5 @@ In the above configuration replace
## Next steps
Aside from the above todos these are the next stepo
- tie it all together behind `ocis-proxy`
- tie it all together behind `ocis-proxy`
- create an `ocis bridge` command that runs all the ocis services in one step with a properly preconfigured `ocis-konnectd` `identifier-registration.yaml` file for `phoenix` and the owncloud 10 `openidconnect` app, as well as a randomized `--signing-kid`.

View File

@@ -0,0 +1,194 @@
---
title: "ocis with konnectd on external node deployment scenario"
date: 2020-10-12T14:39:00+01:00
weight: 26
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/ocis/deployment
geekdocFilePath: ocis_external_konnectd.md
---
{{< toc >}}
This scenario shows how to setup ocis with konnectd as idp running on a separate node. Both node are having separate domains pointing on the servers.
## Overview
* ocis and konnectd running on linux nodes behind traefik as reverse proxy
* Cloudflare DNS is resolving the domains
* Letsencrypt provides ssl certificates for the domains
* Traefik docker container terminates ssl and forwards http requests to the services
## Nodes
### Requirements
* Server running Ubuntu 20.04 is public availible with a static ip address
* Two A-records for both domains are pointing on the servers ip address
* Create user
`$ sudo adduser username`
* Add user to sudo group
`$ sudo usermod -aG sudo username`
* Add users pub key to `~/.ssh/authorized_keys`
* Setup ssh to permit authorisation only by ssh key
* Install docker
`$ sudo apt install docker.io`
* Add user to docker group
`$ sudo usermod -aG docker username`
* Install docker-compose via
`$ sudo curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose`
(docker compose version 1.27.4 as of today)
* Make docker-compose executable
`$ sudo chmod +x /usr/local/bin/docker-compose`
* Environment variables for OCIS Stack are provided by .env file
### Setup on ocis server
* Clone ocis repository
`git clone https://github.com/owncloud/ocis.git`
* Copy example sub folder for ocisnode to /opt
`cp deployment/examples/ocis_external_konnectd/ocisnode /opt/`
* Overwrite OCIS_DOMAIN and IDP_DOMAIN in .env with your-ocis.domain.com and your-idp.domain.com
`sed -i 's/ocis.domain.com/your-ocis.domain.com/g' /opt/ocisnode/.env`
`sed -i 's/idp.domain.com/your-idp.domain.com/g' /opt/ocisnode/.env`
* Change into deployment folder
`cd /opt/ocisnode`
* Start application stack
`docker-compose up -d`
### Setup on idp server
* Clone ocis repository
`git clone https://github.com/owncloud/ocis.git`
* Copy example sub folder for idpnode to /opt
`cp deployment/examples/ocis_external_konnectd/idpnode /opt/`
* Overwrite OCIS_DOMAIN and IDP_DOMAIN in .env with your-ocis.domain.com and your-idp.domain.com
`sed -i 's/ocis.domain.com/your-ocis.domain.com/g' /opt/idpnode/.env`
`sed -i 's/idp.domain.com/your-idp.domain.com/g' /opt/idpnode/.env`
* Overwrite redirect uri with your-ocis.domain.com in identifier-registration.yml
`sed -i 's/ocis.domain.com/your-ocis.domain.com/g' /opt/idpnode/config/identifier-registration.yml`
* Change into deployment folder
`cd /opt/idpnode`
* Start application stack
`docker-compose up -d`
### Stack
On both nodes, a traefik dokcer container is terminating ssl and forwards the http requests to the services. The nodes are named according to their services.
### Config
#### Repository structure
```bash
ocis_external_konnectd # rootfolder
└───ocisnode
│ │ docker-compose.yml
│ │ .env
└───idpnode
│ docker-compose.yml
│ .env
└───config
│ identifier-registration.yml
```
Both subfolders contain the dockr-compose files including additionaly conf files if required. The content of both folders has to be deployed on each node.
#### Traefik
Traefik is set up similar to the traefik example on both nodes.
The certificate resolvers are named similar to their services and behave exactly like in the other examples.
#### Konnectd
Konnectd as Openid provider needs the redirect url's to point to ocis.
```yaml
---
# OpenID Connect client registry.
clients:
- id: phoenix
name: OCIS
application_type: web
insecure: yes
trusted: yes
redirect_uris:
- http://ocis.domain.com/
- https://ocis.domain.com/
- http://ocis.domain.com/oidc-callback.html
- https://ocis.domain.com/oidc-callback.html
- http://ocis.domain.com/oidc-silent-redirect.html
- https://ocis.domain.com/oidc-silent-redirect.html
origins:
- http://ocis.domain.com
- https://ocis.domain.com
```
Behind traefik, http is used to communicate between the services. Setting KONNECTD_TLS enforces it.
```yaml
KONNECTD_TLS: '0'
```
In order to resolve users from glauth service on ocis node, Konnectd needs ldap settings to work properly.
```yaml
LDAP_URI: ldap://${OCIS_DOMAIN}:9125
LDAP_BINDDN: cn=konnectd,ou=sysusers,dc=example,dc=org
LDAP_BINDPW: konnectd
LDAP_BASEDN: ou=users,dc=example,dc=org
LDAP_SCOPE: sub
LDAP_LOGIN_ATTRIBUTE: cn
LDAP_EMAIL_ATTRIBUTE: mail
LDAP_NAME_ATTRIBUTE=: n
LDAP_UUID_ATTRIBUTE: uid
LDAP_UUID_ATTRIBUTE_TYPE: text
LDAP_FILTER: (objectClass=posixaccount)
```
#### ocis
On the ocis node, the setting is following a standard scenario, except, that port 9125 needs to be exposed for the idp node to resolve ldap querries from Konnectd.
```yaml
ocis:
...
ports:
- 9200:9200
- 9125:9125
...
```

View File

@@ -0,0 +1,289 @@
---
title: "ocis frontend with oc10 backend deployment scenario"
date: 2020-10-12T14:04:00+01:00
weight: 25
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/ocis/deployment
geekdocFilePath: ocis_frontend_oc10_backend.md
---
{{< toc >}}
This deployment scenario shows how to use ocis as frontend for a existing owncloud 10 installation.
ocis will allow owncloud 10 users to log in and work with their files.
## Overview
### Node Setup
* ocis and oc10 running as docker containers behind traefik as reverse proxy
* Cloudflare DNS is resolving one domain for ocis and one for oc10
* Letsencrypt is providing valid ssl certificate for both domains
## Node Deployment
### Requirements
* Server running Ubuntu 20.04 is public availible with a static ip address
* Two A-records for both domains are pointing on the servers ip address
* Create user
`$ sudo adduser username`
* Add user to sudo group
`$ sudo usermod -aG sudo username`
* Add users pub key to `~/.ssh/authorized_keys`
* Setup ssh to permit authorisation only by ssh key
* Install docker
`$ sudo apt install docker.io`
* Add user to docker group
`$ sudo usermod -aG docker username`
* Install docker-compose via
`$ sudo curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose`
(docker compose version 1.27.4 as of today)
* Make docker-compose executable
`$ sudo chmod +x /usr/local/bin/docker-compose`
* Environment variables for OCIS Stack are provided by .env file
### Setup on server
* Clone ocis repository
`git clone https://github.com/owncloud/ocis.git`
* Copy example folder to /opt
`cp deployment/examples/ocis_oc10_backend /opt/`
* Overwrite OCIS_DOMAIN and OC10_DOMAIN in .env with your-ocis.domain.com and your-oc10.domain.com
`sed -i 's/ocis.domain.com/your-ocis.domain.com/g' /opt/ocis_oc10_backend/.env`
`sed -i 's/oc10.domain.com/your-oc10.domain.com/g' /opt/ocis_oc10_backend/.env`
* Overwrite redirect uris with your-ocis.domain.com and your-oc10.domain.com in identifier-registration.yml
`sed -i 's/ocis.domain.com/your-ocis.domain.com/g' /opt/ocis_oc10_backend/ocis/identifier-registration.yml`
`sed -i 's/oc10.domain.com/your-oc10.domain.com/g' /opt/ocis_oc10_backend/ocis/identifier-registration.yml`
* Change into deployment folder
`cd /opt/ocis_oc10_backend`
* Start application stack
`docker-compose up -d`
### Stack
The application stack is separated in docker containers. One is a traefik proxy which is terminating ssl and forwards the https requests to the internal docker network. Additional, traefik is creating two certificates that are stored in the file `letsencrypt/acme.json` of the users home directory. In a local setup, this traefik is not included.
The next container is the ocis server which is exposing the webservice on port 9200 to traefic and provides the oidc provider konnectd to owncloud.
oc10 is running as a three container setup out of owncloud-server, a db container and a redis container as memcache storage.
### Config
#### Repository structure
```bash
ocis_oc10_backend # rootfolder
│ .env
│ docker-compose.yml
└───ocis #ocis related config files
│ │ identifier-registration.yml
│ │ proxy-config.json
└───oc10 #owncloud 10 related files
│ Dockerfile
└───apps
│ graphapi-0.1.0.tar.gz
```
#### Traefik
In this deployment scenario, traefik requests letsencrypt to issue 2 ssl certificates, so two certificate resolver are needed. These are named according to the services, ocis for the ocis container and oc10 for the oc10 container.
```yaml
...
traefik:
image: "traefik:v2.2"
container_name: "traefik"
command:
...
# Ocis certificate resolver
- "--certificatesresolvers.ocis.acme.tlschallenge=true"
- "--certificatesresolvers.ocis.acme.caserver=https://acme-v02.api.letsencrypt.org/directory"
- "--certificatesresolvers.ocis.acme.email=user@${OCIS_DOMAIN}"
- "--certificatesresolvers.ocis.acme.storage=/letsencrypt/acme-ocis.json"
# OC10 certificate resolver
- "--certificatesresolvers.oc10.acme.tlschallenge=true"
- "--certificatesresolvers.oc10.acme.caserver=https://acme-v02.api.letsencrypt.org/directory"
- "--certificatesresolvers.oc10.acme.email=user@${OCIS_DOMAIN}"
- "--certificatesresolvers.oc10.acme.storage=/letsencrypt/acme-oc10.json"
...
```
Both container's traefik labels have to match with the correct resolvers and domains
```yaml
ocis:
...
labels:
...
- "traefik.http.routers.ocis.rule=Host(`${OCIS_DOMAIN}`)"
...
```
```yaml
oc10:
...
labels:
...
- "traefik.http.routers.oc10.rule=Host(`${OC10_DOMAIN}`)"
...
```
A folder for letsencypt to store the certificate needs to be created
`$ mkdir ~/letsencrypt`
This folder is bind to the docker container and the certificate is persistently stored into it.
#### ocis
Since ssl shall be terminated from traefik and inside of the docker network the services shall comunicate via http, `PROXY_TLS: "false"` as environment parameter for ocis has to be set.
For ocis 2 config files are provided.
```bash
└───ocis #ocis related config files
│ │ identifier-registration.yml
│ │ proxy-config.json
```
Changes need to be done in identifier-registration.yml to match the domains
Phoenix client needs the redirects uri's set to the ocis domain while oc10 client needs them to point on the owncloud domain
```yaml
---
# OpenID Connect client registry.
clients:
- id: phoenix
name: OCIS
application_type: web
insecure: yes
trusted: yes
redirect_uris:
- http://ocis.domain.com/
- https://ocis.domain.com/
- http://ocis.domain.com/oidc-callback.html
- https://ocis.domain.com/oidc-callback.html
- http://ocis.domain.com/oidc-silent-redirect.html
- https://ocis.domain.com/oidc-silent-redirect.html
origins:
- http://ocis.domain.com
- https://ocis.domain.com
- id: oc10
name: OC10
application_type: web
secret: super
insecure: yes
trusted: yes
redirect_uris:
- https://oc10.domain.com/apps/openidconnect/redirect/
- https://oc10.domain.com/apps/openidconnect/redirect
origins:
- http://oc10.domain.com
- https://oc10.domain.com
```
The second file is proxy-config.json which configures the ocis internal service proxy routes. The policy_selector selector needs to be changed to forward to the related backend. ocis proxy makes the decision in this scenario to which backend the request needs to be forwarded based on the user storage.
```yaml
{
"HTTP": {
"Namespace": "works.owncloud"
},
"policy_selector": {
"migration": {
"acc_found_policy" : "reva",
"acc_not_found_policy": "oc10",
"unauthenticated_policy": "oc10"
}
"policies": [
{
"name": "reva",
"routes": [
{
"endpoint": "/",
"backend": "http://localhost:9100"
},
{
....
```
Glauth needs to be configured to utilize oc10 as primary user backend.
```yaml
GLAUTH_BACKEND_DATASTORE: owncloud
GLAUTH_BACKEND_SERVERS: https://${OC10_DOMAIN}/apps/graphapi/v1.0
GLAUTH_BACKEND_BASEDN: dc=example,dc=org
STORAGE_STORAGE_METADATA_PROVIDER_DRIVER: owncloud
STORAGE_STORAGE_METADATA_DATA_PROVIDER_DRIVER: owncloud
ACCOUNTS_STORAGE_DISK_PATH: /var/tmp/ocis-accounts # Accounts fails to start when cs3 backend is used atm
```
To allow konnectd to glauth, ldap needs to be configured have to be set.
```yaml
# Konnectd ldap setup
LDAP_URI: ldap://localhost:9125
LDAP_BINDDN: "cn=admin,dc=example,dc=org"
LDAP_BINDPW: "admin"
LDAP_BASEDN: "dc=example,dc=org"
LDAP_SCOPE: sub
LDAP_LOGIN_ATTRIBUTE: uid
LDAP_EMAIL_ATTRIBUTE: mail
LDAP_NAME_ATTRIBUTE: givenName
LDAP_UUID_ATTRIBUTE: uid
LDAP_UUID_ATTRIBUTE_TYPE: text
LDAP_FILTER: "(objectClass=posixaccount)"
```
#### oc10
Owncloud 10 needs the graph api extensions to work in this setup. This extension is needed for Glauth to get oc10 users. It's necessary to add a image build step which extends owncloud/server:latest docker image with the app. The app is provided as tarball in the folder oc10/apps
```bash
└───oc10
│ │ Dockerfile
│ │
│ └───apps
│ │ │ graphapi-0.1.0.tar.gz
```
The docker files is pretty simple
```Dockerfile
# Take the latest owncloud/server image as base
FROM owncloud/server:latest
# Add the provided tarballs into oc10's apps folder
ADD apps/graphapi-0.1.0.tar.gz /var/www/owncloud/apps/
```
The build is triggered by the terminal command `docker-compose build` from the root folder.
Constraints: In this setup it's mandatory that the user has an email adress set in oc10.

View File

@@ -0,0 +1,148 @@
---
title: "ocis with traefik deployment scenario"
date: 2020-10-12T14:04:00+01:00
weight: 24
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/ocis/deployment
geekdocFilePath: ocis_traefik.md
---
{{< toc >}}
## Overview
* ocis running on a hcloud node behind traefik as reverse proxy
* Cloudflare DNS is resolving the domain
* Letsencrypt provides a ssl certificate for the domain
* Traefik docker container terminates ssl and forwards http requests to ocis
## Node
### Requirements
* Server running Ubuntu 20.04 is public availible with a static ip address
* Two A-records for both domains are pointing on the servers ip address
* Create user
`$ sudo adduser username`
* Add user to sudo group
`$ sudo usermod -aG sudo username`
* Add users pub key to `~/.ssh/authorized_keys`
* Setup ssh to permit authorisation only by ssh key
* Install docker
`$ sudo apt install docker.io`
* Add user to docker group
`$ sudo usermod -aG docker username`
* Install docker-compose via
`$ sudo curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose`
(docker compose version 1.27.4 as of today)
* Make docker-compose executable
`$ sudo chmod +x /usr/local/bin/docker-compose`
* Environment variables for OCIS Stack are provided by .env file
### Setup on server
* Clone ocis repository
`git clone https://github.com/owncloud/ocis.git`
* Copy example folder to /opt
`cp deployment/examples/ocis_traefik /opt/`
* Overwrite OCIS_DOMAIN in .env with your.domain.com
`sed -i 's/ocis.domain.com/your.domain.com/g' /opt/ocis_traefik/.env`
* Overwrite redirect uri with your.domain.com in identifier-registration.yml
`sed -i 's/ocis.domain.com/your.domain.com/g' /opt/ocis_traefik/config/identifier-registration.yml`
* Change into deployment folder
`cd /opt/ocis_traefik`
* Start application stack
`docker-compose up -d`
### Stack
The application stack contains two containers. The first one is a traefik proxy which is terminating ssl and forwards the requests to the internal docker network. Additional, traefik is creating a certificate that is stored in `acme.json` in the folder `letsencrypt` inside the users home directory.
The second one is th ocis server which is exposing the webservice on port 9200 to traefic.
### Config
Edit docker-compose.yml file to fit your domain setup
```yaml
...
traefik:
image: "traefik:v2.2"
...
labels:
...
# Email address is neccesary for certificate creation
- "--certificatesresolvers.ocisresolver.acme.email=username@${OCIS_DOMAIN}"
...
```
```yaml
ocis:
container_name: ocis
...
labels:
...
# This is the domain for which traefik is creating the certificate from letsencrypt
- "traefik.http.routers.ocis.rule=Host(`${OCIS_DOMAIN}`)"
...
```
In this example, ssl is terminated from traefik while inside of the docker network the services are comunicating via http. For this `PROXY_TLS: "false"` as environment parameter for ocis has to be set.
For ocis to work properly it's neccesary to provide one config file.
Change identifier-registration.yml to match your domain.
```yaml
---
# OpenID Connect client registry.
clients:
- id: phoenix
name: OCIS
application_type: web
insecure: yes
trusted: yes
redirect_uris:
- http://ocis.domain.com/
- https://ocis.domain.com/
- http://ocis.domain.com/oidc-callback.html
- https://ocis.domain.com/oidc-callback.html
- http://ocis.domain.com/oidc-silent-redirect.html
- https://ocis.domain.com/oidc-silent-redirect.html
origins:
- http://ocis.domain.com
- https://ocis.domain.com
```
To make it availible for ocis inside of the container, `config` hast to be mounted as volume.
```yaml
...
volumes:
- ./config:/etc/ocis
environment:
...
KONNECTD_IDENTIFIER_REGISTRATION_CONF: "/etc/ocis/identifier-registration.yml"
...
```

View File

@@ -3,7 +3,7 @@ title: "Development"
date: 2020-10-01T20:35:00+01:00
weight: -12
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/development
geekdocEditPath: edit/master/docs/ocis/development
geekdocFilePath: _index.md
---

View File

@@ -3,7 +3,7 @@ title: "Build the documentation"
date: 2020-07-27T08:39:38+00:00
weight: 99
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/development
geekdocEditPath: edit/master/docs/ocis/development
geekdocFilePath: building-docs.md
---
@@ -26,11 +26,11 @@ hugo -D server
Then open "http://localhost:1313/"
When making changes to the docs, run
When making changes to the docs, run
```bash
rsync -ax --delete ../docs/ content/
```
```
in the hugo folder and the server will pick up the changes and reload the page automatically.

Some files were not shown because too many files have changed in this diff Show More