Compare commits

...

18 Commits

Author SHA1 Message Date
dusanb d7075502cc Merge branch 'pagination' into 'main'
NOISSUE - Fix Users Pagination

See merge request DAVEEmbeddedSystems/innovation-lab/tlm/tlml/abstract-machines/magistrala!13
2024-03-27 11:21:20 +00:00
Rodney Osodo d9195d0f6e NOISSUE - Fix Users Pagination 2024-03-27 11:21:19 +00:00
dusanb e00b630e79 Merge branch 'update' into 'main'
NOISSUE - Sync With Magistrala

See merge request DAVEEmbeddedSystems/innovation-lab/tlm/tlml/abstract-machines/magistrala!12
2024-03-26 11:19:40 +00:00
Rodney Osodo fc279d7d78 NOISSUE - Sync With Magistrala 2024-03-26 11:19:39 +00:00
dusanb b4c60b21cc Merge branch 'retry-kratos-req' into 'main'
NOISSUE - Retry Kratos Failed Requests

See merge request DAVEEmbeddedSystems/innovation-lab/tlm/tlml/abstract-machines/magistrala!11
2024-03-21 14:02:52 +00:00
Rodney Osodo f5c0e2c906 NOISSUE - Retry Kratos Failed Requests 2024-03-21 14:02:52 +00:00
dusanb e2b021ab60 Merge branch 'update' into 'main'
NOISSUE - Sync with Magistrala

See merge request DAVEEmbeddedSystems/innovation-lab/tlm/tlml/abstract-machines/magistrala!10
2024-03-15 14:14:03 +00:00
Rodney Osodo 959dbd7c50 NOISSUE - Sync with Magistrala 2024-03-15 14:14:03 +00:00
dusanb 7a61872648 Merge branch 'update' into 'main'
NOISSUE - Sync with Magistrala

See merge request DAVEEmbeddedSystems/innovation-lab/tlm/tlml/abstract-machines/magistrala!9
2024-03-04 15:32:33 +00:00
Rodney Osodo 8e45a8c5d7 NOISSUE - Sync with Magistrala 2024-03-04 15:32:32 +00:00
dusanb 8ffc710b6a Merge branch 'ci' into 'main'
MG-1 - Update Docker Image names and setup Continous Delivery

Closes #1

See merge request DAVEEmbeddedSystems/innovation-lab/tlm/tlml/abstract-machines/magistrala!4
2024-03-01 13:45:04 +00:00
Rodney Osodo f762b91669 MG-1 - Update Docker Image names and setup Continous Delivery 2024-03-01 13:45:04 +00:00
dusanb 6e8ca15f56 Merge branch 'kratos-oauth2' into 'main'
NOISSUE - Add Kratos as an OAuth2.0 Provider

See merge request DAVEEmbeddedSystems/innovation-lab/tlm/tlml/abstract-machines/magistrala!6
2024-03-01 13:33:10 +00:00
Rodney Osodo d3fe7d1063 NOISSUE - Add Kratos as an OAuth2.0 Provider 2024-03-01 13:33:09 +00:00
dusanb ad6619f0ac Merge branch 'update-main' into 'main'
NOISSUE - Add Kratos as Users Repository

See merge request DAVEEmbeddedSystems/innovation-lab/tlm/tlml/abstract-machines/magistrala!7
2024-03-01 12:29:48 +00:00
Rodney Osodo 4bee424289 NOISSUE - Add Kratos as Users Repository 2024-03-01 12:29:47 +00:00
dusanb f55d7640eb Merge branch 'migrate-to-gitlab' into 'main'
NOISSUE - Migrate to GitLab

See merge request DAVEEmbeddedSystems/innovation-lab/tlm/tlml/abstract-machines/magistrala!8
2024-03-01 12:15:10 +00:00
Rodney Osodo 221c1212bb NOISSUE - Migrate to GitLab 2024-03-01 12:15:10 +00:00
112 changed files with 2408 additions and 3429 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
# SPDX-License-Identifier: Apache-2.0
.git
.github
.gitlab
build
docker
metrics
-52
View File
@@ -1,52 +0,0 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
name: Bug Report
description: File a bug/issue report. Make sure to search to see if an issue already exists for the bug you encountered.
title: "Bug: <title>"
labels: ["bug", "needs-review", "help wanted"]
body:
- type: textarea
attributes:
label: What were you trying to achieve?
description: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
attributes:
label: What are the expected results?
description: A concise description of what you expected to happen.
validations:
required: true
- type: textarea
attributes:
label: What are the received results?
description: A concise description of what you received.
validations:
required: true
- type: textarea
attributes:
label: Steps To Reproduce
description: What are the steps to reproduce the issue?
placeholder: |
1. In this environment...
2. With this config...
3. Run '...'
4. See error...
validations:
required: false
- type: textarea
attributes:
label: In what environment did you encounter the issue?
description: A concise description of the environment you encountered the issue in.
validations:
required: true
- type: textarea
attributes:
label: Additional information you deem important
description: |
Links? References? Anything that will give us more context about the issue you are encountering!
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations:
required: false
-11
View File
@@ -1,11 +0,0 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
blank_issues_enabled: false
contact_links:
- name: Google group
url: https://groups.google.com/forum/#!forum/mainflux
about: Join the Mainflux community on Google group.
- name: Gitter
url: https://gitter.im/mainflux/mainflux
about: Join the Mainflux community on Gitter.
@@ -1,39 +0,0 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
name: Feature Request
description: File a feature request. Make sure to search to see if a request already exists for the feature you are requesting.
title: "Feature: <title>"
labels: ["enchancement", "needs-review"]
body:
- type: textarea
attributes:
label: Is your feature request related to a problem? Please describe.
description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
validations:
required: true
- type: textarea
attributes:
label: Describe the feature you are requesting, as well as the possible use case(s) for it.
description: A clear and concise description of what you want to happen.
validations:
required: true
- type: dropdown
attributes:
label: Indicate the importance of this feature to you.
description: This will help us prioritize the feature request.
options:
- Must-have
- Should-have
- Nice-to-have
validations:
required: true
- type: textarea
attributes:
label: Anything else?
description: |
Links? References? Anything that will give us more context about the feature that you are requesting.
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations:
required: false
-58
View File
@@ -1,58 +0,0 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
name: Continuous Delivery
on:
push:
branches:
- main
jobs:
build-and-push:
name: Build and Push
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v4
with:
go-version: 1.21.x
cache-dependency-path: "go.sum"
- name: Run tests
run: |
make test
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV }}
directory: ./coverage/
name: codecov-umbrella
verbose: true
- name: Set up Docker Build
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v3
with:
registry: docker.io
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
- name: Compile check for rabbitmq
run: |
MG_MESSAGE_BROKER_TYPE=rabbitmq make mqtt
- name: Compile check for redis
run: |
MG_ES_TYPE=redis make mqtt
- name: Build and push Dockers
run: |
make latest -j $(nproc)
-155
View File
@@ -1,155 +0,0 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
name: Check the consistency of generated files
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
check-generated-files:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v4
with:
go-version: 1.21.x
cache-dependency-path: "go.sum"
- name: Check for changes in go.mod
run: |
go mod tidy
git diff --exit-code
- name: Check for changes in specific paths
uses: dorny/paths-filter@v2
id: changes
with:
base: main
filters: |
proto:
- ".github/workflows/check-generated-files.yml"
- "auth.proto"
- "auth/*.pb.go"
- "pkg/messaging/message.proto"
- "pkg/messaging/*.pb.go"
mocks:
- ".github/workflows/check-generated-files.yml"
- "pkg/sdk/go/sdk.go"
- "users/postgres/clients.go"
- "users/clients.go"
- "pkg/clients/clients.go"
- "pkg/messaging/pubsub.go"
- "things/postgres/clients.go"
- "things/things.go"
- "auth/domains.go"
- "auth/keys.go"
- "auth/policies.go"
- "auth/service.go"
- "pkg/events/events.go"
- "provision/service.go"
- "pkg/groups/groups.go"
- name: Set up protoc
if: steps.changes.outputs.proto == 'true'
run: |
PROTOC_VERSION=25.3
PROTOC_GEN_VERSION=v1.32.0
PROTOC_GRPC_VERSION=v1.3.0
# Download and install protoc
PROTOC_ZIP=protoc-$PROTOC_VERSION-linux-x86_64.zip
curl -0L -o $PROTOC_ZIP https://github.com/protocolbuffers/protobuf/releases/download/v$PROTOC_VERSION/$PROTOC_ZIP
unzip -o $PROTOC_ZIP -d protoc3
sudo mv protoc3/bin/* /usr/local/bin/
sudo mv protoc3/include/* /usr/local/include/
rm -rf $PROTOC_ZIP protoc3
# Install protoc-gen-go and protoc-gen-go-grpc
go install google.golang.org/protobuf/cmd/protoc-gen-go@$PROTOC_GEN_VERSION
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@$PROTOC_GRPC_VERSION
# Add protoc to the PATH
export PATH=$PATH:/usr/local/bin/protoc
- name: Check Protobuf is up to Date
if: steps.changes.outputs.proto == 'true'
run: |
for p in $(find . -name "*.pb.go"); do
mv $p $p.tmp
done
make proto
for p in $(find . -name "*.pb.go"); do
if ! cmp -s $p $p.tmp; then
echo "Error: Proto file and generated Go file $p are out of sync!"
echo "Please run 'make proto' with protoc version $PROTOC_VERSION, protoc-gen-go version $PROTOC_GEN_VERSION and protoc-gen-go-grpc version $PROTOC_GRPC_VERSION and commit the changes."
exit 1
fi
done
- name: Check Mocks are up to Date
if: steps.changes.outputs.mocks == 'true'
run: |
MOCKERY_VERSION=v2.38.0
go install github.com/vektra/mockery/v2@$MOCKERY_VERSION
mv ./pkg/sdk/mocks/sdk.go ./pkg/sdk/mocks/sdk.go.tmp
mv ./users/mocks/repository.go ./users/mocks/repository.go.tmp
mv ./users/mocks/service.go ./users/mocks/service.go.tmp
mv ./pkg/messaging/mocks/pubsub.go ./pkg/messaging/mocks/pubsub.go.tmp
mv ./things/mocks/repository.go ./things/mocks/repository.go.tmp
mv ./things/mocks/service.go ./things/mocks/service.go.tmp
mv ./things/mocks/cache.go ./things/mocks/cache.go.tmp
mv ./auth/mocks/agent.go ./auth/mocks/agent.go.tmp
mv ./auth/mocks/authz.go ./auth/mocks/authz.go.tmp
mv ./auth/mocks/domains.go ./auth/mocks/domains.go.tmp
mv ./auth/mocks/keys.go ./auth/mocks/keys.go.tmp
mv ./auth/mocks/service.go ./auth/mocks/service.go.tmp
mv ./pkg/events/mocks/publisher.go ./pkg/events/mocks/publisher.go.tmp
mv ./pkg/events/mocks/subscriber.go ./pkg/events/mocks/subscriber.go.tmp
mv ./provision/mocks/service.go ./provision/mocks/service.go.tmp
mv ./pkg/groups/mocks/repository.go ./pkg/groups/mocks/repository.go.tmp
mv ./pkg/groups/mocks/service.go ./pkg/groups/mocks/service.go.tmp
make mocks
check_mock_changes() {
local file_path=$1
local tmp_file_path=$1.tmp
local entity_name=$2
if ! cmp -s "$file_path" "$tmp_file_path"; then
echo "Error: Generated mocks for $entity_name are out of sync!"
echo "Please run 'make mocks' with mockery version $MOCKERY_VERSION and commit the changes."
exit 1
fi
}
check_mock_changes ./pkg/sdk/mocks/sdk.go "SDK ./pkg/sdk/mocks/sdk.go"
check_mock_changes ./users/mocks/repository.go "Users Repository ./users/mocks/repository.go"
check_mock_changes ./users/mocks/service.go "Users Service ./users/mocks/service.go"
check_mock_changes ./pkg/messaging/mocks/pubsub.go "PubSub ./pkg/messaging/mocks/pubsub.go"
check_mock_changes ./things/mocks/repository.go "Things Repository ./things/mocks/repository.go"
check_mock_changes ./things/mocks/service.go "Things Service ./things/mocks/service.go"
check_mock_changes ./things/mocks/cache.go "Things Cache ./things/mocks/cache.go"
check_mock_changes ./auth/mocks/agent.go "Auth Agent ./auth/mocks/agent.go"
check_mock_changes ./auth/mocks/authz.go "Auth Authz ./auth/mocks/authz.go"
check_mock_changes ./auth/mocks/domains.go "Auth Domains ./auth/mocks/domains.go"
check_mock_changes ./auth/mocks/keys.go "Auth Keys ./auth/mocks/keys.go"
check_mock_changes ./auth/mocks/service.go "Auth Service ./auth/mocks/service.go"
check_mock_changes ./pkg/events/mocks/publisher.go "ES Publisher ./pkg/events/mocks/publisher.go"
check_mock_changes ./pkg/events/mocks/subscriber.go "EE Subscriber ./pkg/events/mocks/subscriber.go"
check_mock_changes ./provision/mocks/service.go "Provision Service ./provision/mocks/service.go"
check_mock_changes ./pkg/groups/mocks/repository.go "Groups Repository ./pkg/groups/mocks/repository.go"
check_mock_changes ./pkg/groups/mocks/service.go "Groups Service ./pkg/groups/mocks/service.go"
-31
View File
@@ -1,31 +0,0 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
name: Check License Header
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
check-license:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Check License Header
run: |
CHECK=$(grep -rcL --exclude-dir={.git,build,**vernemq**} \
--exclude=\*.{crt,key,pem,zed,hcl,md,json,csv,mod,sum,tmpl,args} \
--exclude={CODEOWNERS,LICENSE,MAINTAINERS} \
--regexp "Copyright (c) Abstract Machines" .)
if [ "$CHECK" ]; then
echo "License header check failed. Fix the following files:"
echo "$CHECK"
exit 1
fi
-31
View File
@@ -1,31 +0,0 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
name: Deploy GitHub Pages
on:
push:
branches:
- main
jobs:
swagger-ui:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Swagger UI action
id: swagger-ui-action
uses: blokovi/swagger-ui-action@main
with:
dir: "./api/openapi"
pattern: "*.yml"
debug: "true"
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: swagger-ui
cname: api.mainflux.io
-407
View File
@@ -1,407 +0,0 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
name: CI Pipeline
on:
pull_request:
branches:
- main
jobs:
lint-and-build: # Linting and building are combined to save time for setting up Go
name: Lint and Build
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v4
with:
go-version: 1.21.x
cache-dependency-path: "go.sum"
- name: golangci-lint
uses: golangci/golangci-lint-action@v4
with:
version: v1.56.1
- name: Build all Binaries
run: |
make all -j $(nproc)
- name: Compile check for rabbitmq
run: |
MG_MESSAGE_BROKER_TYPE=rabbitmq make mqtt
- name: Compile check for redis
run: |
MG_ES_TYPE=redis make mqtt
run-tests:
name: Run tests
runs-on: ubuntu-latest
needs: lint-and-build
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v4
with:
go-version: 1.21.x
cache-dependency-path: "go.sum"
- name: Check for changes in specific paths
uses: dorny/paths-filter@v2
id: changes
with:
base: main
filters: |
workflow:
- ".github/workflows/tests.yml"
auth:
- "auth/**"
- "cmd/auth/**"
- "auth.proto"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "pkg/ulid/**"
- "pkg/uuid/**"
bootstrap:
- "bootstrap/**"
- "cmd/bootstrap/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "auth/**"
- "pkg/sdk/**"
- "pkg/events/**"
certs:
- "certs/**"
- "cmd/certs/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "auth/**"
- "pkg/sdk/**"
coap:
- "coap/**"
- "cmd/coap/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "things/**"
- "pkg/messaging/**"
consumers:
- "consumers/**"
- "cmd/cassandra-writer/**"
- "cmd/influxdb-writer/**"
- "cmd/mongodb-writer/**"
- "cmd/postgres-writer/**"
- "cmd/timescale-writer/**"
- "cmd/smpp-notifier/**"
- "cmd/smtp-notifier/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "auth/**"
- "pkg/ulid/**"
- "pkg/uuid/**"
- "pkg/messaging/**"
http:
- "http/**"
- "cmd/http/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "things/**"
- "pkg/messaging/**"
- "logger/**"
internal:
- "internal/**"
invitations:
- "invitations/**"
- "cmd/invitations/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "auth/**"
- "pkg/sdk/**"
lora:
- "lora/**"
- "cmd/lora/**"
- "pkg/messaging/**"
logger:
- "logger/**"
mqtt:
- "mqtt/**"
- "cmd/mqtt/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "things/**"
- "pkg/messaging/**"
- "logger/**"
- "pkg/events/**"
opcua:
- "opcua/**"
- "cmd/opcua/**"
- "logger/**"
pkg-auth:
- "pkg/auth/**"
pkg-clients:
- "pkg/clients/**"
pkg-errors:
- "pkg/errors/**"
pkg-events:
- "pkg/events/**"
- "pkg/messaging/**"
pkg-messaging:
- "pkg/messaging/**"
pkg-sdk:
- "pkg/sdk/**"
- "pkg/clients/**"
- "pkg/errors/**"
- "auth/**"
- "bootstrap/**"
- "certs/**"
- "consumers/**"
- "http/**"
- "invitations/**"
- "provision/**"
- "readers/**"
- "things/**"
- "twins/**"
- "users/**"
pkg-transformers:
- "pkg/transformers/**"
pkg-ulid:
- "pkg/ulid/**"
pkg-uuid:
- "pkg/uuid/**"
provision:
- "provision/**"
- "cmd/provision/**"
- "logger/**"
- "pkg/sdk/**"
readers:
- "readers/**"
- "cmd/cassandra-reader/**"
- "cmd/influxdb-reader/**"
- "cmd/mongodb-reader/**"
- "cmd/postgres-reader/**"
- "cmd/timescale-reader/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "things/**"
- "auth/**"
things:
- "things/**"
- "cmd/things/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "auth/**"
- "pkg/clients/**"
- "pkg/ulid/**"
- "pkg/uuid/**"
- "pkg/events/**"
twins:
- "twins/**"
- "cmd/twins/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "auth/**"
- "pkg/messaging/**"
- "pkg/ulid/**"
- "pkg/uuid/**"
- "logger/**"
users:
- "users/**"
- "cmd/users/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "auth/**"
- "pkg/clients/**"
- "pkg/ulid/**"
- "pkg/uuid/**"
- "pkg/events/**"
ws:
- "ws/**"
- "cmd/ws/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "things/**"
- "pkg/messaging/**"
- name: Create coverage directory
run: |
mkdir coverage
- name: Run auth tests
if: steps.changes.outputs.auth == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/auth.out ./auth/...
- name: Run bootstrap tests
if: steps.changes.outputs.bootstrap == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/bootstrap.out ./bootstrap/...
- name: Run certs tests
if: steps.changes.outputs.certs == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/certs.out ./certs/...
- name: Run CoAP tests
if: steps.changes.outputs.coap == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/coap.out ./coap/...
- name: Run consumers tests
if: steps.changes.outputs.consumers == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/consumers.out ./consumers/...
- name: Run HTTP tests
if: steps.changes.outputs.http == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/http.out ./http/...
- name: Run internal tests
if: steps.changes.outputs.internal == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/internal.out ./internal/...
- name: Run invitations tests
if: steps.changes.outputs.invitations == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/invitations.out ./invitations/...
- name: Run logger tests
if: steps.changes.outputs.logger == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/logger.out ./logger/...
- name: Run LoRa tests
if: steps.changes.outputs.lora == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/lora.out ./lora/...
- name: Run MQTT tests
if: steps.changes.outputs.mqtt == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/mqtt.out ./mqtt/...
- name: Run OPC-UA tests
if: steps.changes.outputs.opcua == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/opcua.out ./opcua/...
- name: Run pkg auth tests
if: steps.changes.outputs.pkg-auth == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/pkg-auth.out ./pkg/auth/...
- name: Run pkg clients tests
if: steps.changes.outputs.pkg-clients == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/pkg-clients.out ./pkg/clients/...
- name: Run pkg errors tests
if: steps.changes.outputs.pkg-errors == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/pkg-errors.out ./pkg/errors/...
- name: Run pkg events tests
if: steps.changes.outputs.pkg-events == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/pkg-events.out ./pkg/events/...
- name: Run pkg messaging tests
if: steps.changes.outputs.pkg-messaging == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/pkg-messaging.out ./pkg/messaging/...
- name: Run pkg sdk tests
if: steps.changes.outputs.pkg-sdk == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/pkg-sdk.out ./pkg/sdk/...
- name: Run pkg transformers tests
if: steps.changes.outputs.pkg-transformers == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/pkg-transformers.out ./pkg/transformers/...
- name: Run pkg ulid tests
if: steps.changes.outputs.pkg-ulid == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/pkg-ulid.out ./pkg/ulid/...
- name: Run pkg uuid tests
if: steps.changes.outputs.pkg-uuid == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/pkg-uuid.out ./pkg/uuid/...
- name: Run provision tests
if: steps.changes.outputs.provision == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/provision.out ./provision/...
- name: Run readers tests
if: steps.changes.outputs.readers == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/readers.out ./readers/...
- name: Run things tests
if: steps.changes.outputs.things == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/things.out ./things/...
- name: Run twins tests
if: steps.changes.outputs.twins == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/twins.out ./twins/...
- name: Run users tests
if: steps.changes.outputs.users == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/users.out ./users/...
- name: Run WebSocket tests
if: steps.changes.outputs.ws == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/ws.out ./ws/...
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV }}
directory: ./coverage/
name: codecov-umbrella
verbose: true
+78
View File
@@ -0,0 +1,78 @@
variables:
DOCKER_HOST: tcp://docker:2375/
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: ""
GOLANGCI_LINT_VERSION: "v1.55.2"
PROTOC_VERSION: "25.3"
PROTOC_GEN_VERSION: "v1.32.0"
PROTOC_GRPC_VERSION: "v1.3.0"
stages:
- test
- build
- publish
lint:
image: golang:1.21.6-bookworm
stage: test
before_script:
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin $GOLANGCI_LINT_VERSION
- export PATH=$PATH:$HOME/go/bin
script:
- golangci-lint run -v
test:
image: golang:1.21.6-bookworm
stage: test
before_script:
- go mod download
- make mocks
- mkdir -p coverage
- touch coverage/coverage.out
script:
- go test -v --race -count 1 -tags test -coverprofile=coverage/coverage.out $(go list ./... | grep -v 'consumers\|readers\|events\|cache\|messaging\|postgres\|mongodb\|internal\|opcua\|cmd')
check-generated-files:
image: golang:1.21.6-bookworm
stage: test
before_script:
- apt-get update && apt-get install -y unzip curl
- PROTOC_ZIP=protoc-$PROTOC_VERSION-linux-x86_64.zip
- curl -0L -o $PROTOC_ZIP https://github.com/protocolbuffers/protobuf/releases/download/v$PROTOC_VERSION/$PROTOC_ZIP
- unzip -o $PROTOC_ZIP -d protoc3
- mv protoc3/bin/* /usr/local/bin/
- mv protoc3/include/* /usr/local/include/
- rm -rf $PROTOC_ZIP protoc3
- go install google.golang.org/protobuf/cmd/protoc-gen-go@$PROTOC_GEN_VERSION
- go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@$PROTOC_GRPC_VERSION
- export PATH=$PATH:/usr/local/bin/protoc
- go mod download
script:
- make check-generated-files
build:
image: golang:1.21.6-bookworm
stage: build
before_script:
- go mod download
script:
- MG_MESSAGE_BROKER_TYPE=rabbitmq make mqtt
- MG_ES_TYPE=redis make mqtt
- make all -j $(nproc)
publish:
image: docker:latest
stage: publish
services:
- name: docker:dind
entrypoint: ["env", "-u", "DOCKER_HOST"]
command: ["dockerd-entrypoint.sh"]
before_script:
- apk add --no-cache make go git
- echo $CI_REGISTRY_PASSWORD | docker login $CI_REGISTRY --username $CI_REGISTRY_USER --password-stdin
- go mod download
script:
- make all -j $(nproc)
- MG_DOCKER_IMAGE_NAME_PREFIX=registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala make latest -j $(nproc)
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
@@ -3,11 +3,6 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/"
schedule:
+36
View File
@@ -0,0 +1,36 @@
<!---
Please read this!
Before opening a new issue, make sure to search for existing issues and verify the issue you're about to submit isn't a duplicate.
--->
## What were you trying to achieve?
<!-- A clear and concise description of what the bug is. -->
## What are the expected results?
<!-- A concise description of what you expected to happen. -->
## What are the received results?
<!-- A concise description of what actually happened. -->
## Steps to reproduce
<!-- Describe how one can reproduce the issue - this is very important. Please use an ordered list. -->
## In what environment did you encounter the issue?
<!-- Describe the environment you encountered the issue in. -->
## Additional information you deem important
<!-- List any additional information that you think might help us debug the issue.
Links? References? Anything that will give us more context about the issue you are encountering!
You can attach images or log files by clicking this area to highlight it and then dragging files in.
-->
/label ~"type::bug"
+25
View File
@@ -0,0 +1,25 @@
<!---
Please read this!
Before opening a new issue, make sure to search for existing issues and verify the issue you're about to submit isn't a duplicate.
--->
## Is your feature request related to a problem? Please describe?
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
## Describe the feature you'd like
<!-- A clear and concise description of what you want to happen. Add any considered drawbacks. -->
## Describe alternatives you've considered
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
## Indicate the importance of this feature to you.
<!-- How important is this feature to you? How much would you appreciate it? -->
## Additional context
<!-- Is there anything else you can add about the proposal? E.g. links to other issues, PRs, etc. -->
@@ -1,12 +1,9 @@
<!-- Copyright (c) Abstract Machines
SPDX-License-Identifier: Apache-2.0 -->
<!--
Pull request title should be `MG-XXX - description` or `NOISSUE - description` where XXX is ID of the issue that this PR relate to.
Please review the [CONTRIBUTING.md](https://github.com/absmach/magistrala/blob/master/CONTRIBUTING.md) file for detailed contributing guidelines.
Please review the [CONTRIBUTING.md](https://gitlab.com/DAVEEmbeddedSystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/-/blob/main/CONTRIBUTING.md?ref_type=heads) file for detailed contributing guidelines.
For Work In Progress Pull Requests, please use the Draft PR feature, see https://github.blog/2019-02-14-introducing-draft-pull-requests/ for further details.
For Work In Progress Pull Requests, please use the Draft PR feature.
For a timely review/response, please avoid force-pushing additional commits if your PR already received reviews or comments.
@@ -17,17 +14,17 @@ For a timely review/response, please avoid force-pushing additional commits if y
- Update any related documentation.
-->
# What type of PR is this?
## What type of PR is this?
<!--This represents the type of PR you are submitting.
For example:
This is a bug fix because it fixes the following issue: #1234
This is a feature because it adds the following functionality: ...
This is a refactor because it changes the following functionality: ...
This is a documentation update because it updates the following documentation: ...
This is a dependency update because it updates the following dependencies: ...
This is an optimization because it improves the following functionality: ...
This PR is a bug fix because it fixes the following issue: #1234
This PR is a feature because it adds the following functionality: ...
This PR is a refactor because it changes the following functionality: ...
This PR is a documentation update because it updates the following documentation: ...
This PR is a dependency update because it updates the following dependencies: ...
This PR is an optimization because it improves the following functionality: ...
-->
## What does this do?
@@ -45,8 +42,10 @@ For pull requests that relate or close an issue, please include them below. We
For example having the text: "Resolves #1234" would connect the current pull request to issue 1234. And when we merge the pull request, Github will automatically close the issue.
-->
<!--
- Related Issue #
- Resolves #
-->
## Have you included tests for your changes?
-5
View File
@@ -54,10 +54,6 @@ linters-settings:
- "mosquitto"
stylecheck:
checks: ["-ST1000", "-ST1003", "-ST1020", "-ST1021", "-ST1022"]
goheader:
template: |-
Copyright (c) Abstract Machines
SPDX-License-Identifier: Apache-2.0
linters:
disable-all: true
@@ -78,7 +74,6 @@ linters:
- gofmt
- goimports
- loggercheck
- goheader
- asasalint
- asciicheck
- bidichk
-36
View File
@@ -1,36 +0,0 @@
# Adopters
As Magistrala Community grows, we'd like to keep track of Magistrala adopters to grow the community, contact other users, share experiences and best practices.
To accomplish this, we created a public ledger. The list of organizations and users who consider themselves as Magistrala adopters and that **publicly/officially** shared information and/or details of their adoption journey(optional).
Where users themselves directly maintain the list.
## Adding yourself as an adopter
If you are using Magistrala, please consider adding yourself as an adopter with a brief description of your use case by opening a pull request to this file and adding a section describing your adoption of Magistrala technology.
**Please send PRs to add or remove organizations/users**
### Format
```
N: Name of user (company or individual)
D: Short Use Case Description (optional)
L: Link with further information (optional)
T: Type of adaptation: Evaluation, Core Technology, Production Usage (optional)
```
## Requirements
* You must represent the user or organization listed. Do NOT add entries on behalf of other organizations or individuals.
Pull request commit must be [signed](https://docs.github.com/en/github/authenticating-to-github/signing-commits) and auto-checked with [ Developer Certificate of Origin (DCO)](https://probot.github.io/apps/dco/)
* There is no minimum requirement or adaptation size, but we request to list permanent deployments only, i.e., no demo or trial deployments. Commercial or production use is not required. A well-done home lab setup can be equally impressive as a large-scale commercial deployment.
**The list of organizations/users that have publicly shared the usage of Magistrala:**
**Note**: Several other organizations/users couldn't publicly share their usage details but are active project contributors and Magistrala Community members.
## Adopters list (alphabetical)
**Note:** The list is maintained by the users themselves. If you find yourself on this list, and you think it's inappropriate. Please contact [project maintainers](https://github.com/absmach/magistrala/blob/master/MAINTAINERS) and you will be permanently removed from the list.
+20 -38
View File
@@ -1,19 +1,14 @@
# Contributing to Magistrala
The following is a set of guidelines to contribute to Magistrala and its libraries, which are
hosted on the [Abstract Machines Organization](https://github.com/absmach) on GitHub.
The following is a set of guidelines to contribute to Magistrala and its libraries, which are hosted on the [Abstract Machines Organization](https://gitlab.com/DAVEEmbeddedSystems/innovation-lab/tlm/tlml/abstract-machines) on Gitlab.
This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0).
By participating, you are expected to uphold this code. Please report unacceptable behavior to
[abuse@magistrala.com](mailto:abuse@magistrala.com).
This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0). By participating, you are expected to uphold this code. Please report unacceptable behavior to [abuse@magistrala.com](mailto:abuse@magistrala.com).
## Reporting issues
Reporting issues are a great way to contribute to the project. We are perpetually grateful about a well-written,
thorough bug report.
Reporting issues are a great way to contribute to the project. We are perpetually grateful about a well-written, thorough bug report.
Before raising a new issue, check [our issue
list](https://github.com/absmach/magistrala/issues) to determine if it already contains the
Before raising a new issue, check [our issue list](https://gitlab.com/DAVEEmbeddedSystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/-/issues) to determine if it already contains the
problem that you are facing.
A good bug report shouldn't leave others needing to chase you for more information. Please be as detailed as possible. The following questions might serve as a template for writing a detailed
@@ -27,61 +22,48 @@ report:
## Pull requests
Good pull requests (e.g. patches, improvements, new features) are a fantastic help. They should
remain focused in scope and avoid unrelated commits.
Good pull requests (e.g. patches, improvements, new features) are a fantastic help. They should remain focused in scope and avoid unrelated commits.
**Please ask first** before embarking on any significant pull request (e.g. implementing new features,
refactoring code etc.), otherwise you risk spending a lot of time working on something that the
maintainers might not want to merge into the project.
**Please ask first** before embarking on any significant pull request (e.g. implementing new features, refactoring code etc.), otherwise you risk spending a lot of time working on something that the maintainers might not want to merge into the project.
Please adhere to the coding conventions used throughout the project. If in doubt, consult the
[Effective Go](https://golang.org/doc/effective_go.html) style guide.
Please adhere to the coding conventions used throughout the project. If in doubt, consult the [Effective Go](https://golang.org/doc/effective_go.html) style guide.
To contribute to the project, [fork](https://help.github.com/articles/fork-a-repo/) it,
clone your fork repository, and configure the remotes:
To contribute to the project, clone the repository:
```
git clone https://github.com/<your-username>/magistrala.git
```bash
git clone https://gitlab.com/DAVEEmbeddedSystems/innovation-lab/tlm/tlml/abstract-machines/magistrala.git
cd magistrala
git remote add upstream https://github.com/absmach/magistrala.git
```
If your cloned repository is behind the upstream commits, then get the latest changes from upstream:
```
git checkout master
```bash
git checkout main
git pull --rebase upstream main
```
Create a new topic branch from `master` using the naming convention `MG-[issue-number]`
to help us keep track of your contribution scope:
Create a new topic branch from `main` using the naming convention `MG-[issue-number]` to help us keep track of your contribution scope:
```
```bash
git checkout -b MG-[issue-number]
```
Commit your changes in logical chunks. When you are ready to commit, make sure
to write a Good Commit Message™. Consult the [Erlang's contributing guide](https://github.com/erlang/otp/wiki/Writing-good-commit-messages)
if you're unsure of what constitutes a Good Commit Message™. Use [interactive rebase](https://help.github.com/articles/about-git-rebase)
to group your commits into logical units of work before making it public.
Commit your changes in logical chunks. When you are ready to commit, make sure to write a Good Commit Message™. Consult the [Erlang's contributing guide](https://github.com/erlang/otp/wiki/Writing-good-commit-messages) if you're unsure of what constitutes a Good Commit Message™. Use [interactive rebase](https://docs.gitlab.com/ee/topics/git/git_rebase.html) to group your commits into logical units of work before making it public.
Note that every commit you make must be signed. By signing off your work you indicate that you
are accepting the [Developer Certificate of Origin](https://developercertificate.org/).
Note that every commit you make must be signed. By signing off your work you indicate that you are accepting the [Developer Certificate of Origin](https://developercertificate.org/).
Use your real name (sorry, no pseudonyms or anonymous contributions). If you set your `user.name`
and `user.email` git configs, you can sign your commit automatically with `git commit -s`.
Use your real name (sorry, no pseudonyms or anonymous contributions). If you set your `user.name` and `user.email` git configs, you can sign your commit automatically with `git commit -s`.
Locally merge (or rebase) the upstream development branch into your topic branch:
```
```bash
git pull --rebase upstream main
```
Push your topic branch up to your fork:
```
```bash
git push origin MG-[issue-number]
```
[Open a Pull Request](https://help.github.com/articles/using-pull-requests/) with a clear title
and detailed description.
[Open a Pull Request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html) with a clear title and detailed description.
+16 -4
View File
@@ -116,18 +116,29 @@ install:
cp $$file $(GOBIN)/magistrala-`basename $$file`; \
done
check-generated-files:
$(MAKE) proto
@if git diff --name-only | grep .pb.go; then \
echo "Error generated files are out of sync. Please run 'make proto' and commit the changes."; \
exit 1; \
fi
$(MAKE) mocks
@if git diff --name-only | grep mocks; then \
echo "Error mocks are out of sync. Please run 'make mocks' and commit the changes."; \
exit 1; \
fi
mocks:
@which mockery > /dev/null || go install github.com/vektra/mockery/v2@$(MOCKERY_VERSION)
@unset MOCKERY_VERSION && go generate ./...
DIRS = consumers readers postgres internal opcua
DIRS = consumers readers events cache messaging postgres internal opcua
test: mocks
mkdir -p coverage
@for dir in $(DIRS); do \
go test -v --race -count 1 -tags test -coverprofile=coverage/$$dir.out $$(go list ./... | grep $$dir | grep -v 'cmd'); \
done
go test -v --race -count 1 -tags test -coverprofile=coverage/coverage.out $$(go list ./... | grep -v 'consumers\|readers\|postgres\|internal\|opcua\|cmd')
go test -v --race -count 1 -tags test -coverprofile=coverage/coverage.out $$(go list ./... | grep -v 'consumers\|readers\|events\|cache\|messaging\|postgres\|mongodb\|internal\|opcua\|cmd')
proto:
protoc -I. --go_out=. --go_opt=paths=source_relative pkg/messaging/*.proto
@@ -154,7 +165,8 @@ endef
changelog:
git log $(shell git describe --tags --abbrev=0)..HEAD --pretty=format:"- %s"
latest: dockers
# using dev since it takes less time to build for CI
latest: dockers_dev
$(call docker_push,latest)
release:
+2 -12
View File
@@ -1,8 +1,5 @@
# Magistrala
[![Check License Header](https://github.com/absmach/magistrala/actions/workflows/check-license.yaml/badge.svg?branch=main)](https://github.com/absmach/magistrala/actions/workflows/check-license.yaml)
[![Check the consistency of generated files](https://github.com/absmach/magistrala/actions/workflows/check-generated-files.yml/badge.svg?branch=main)](https://github.com/absmach/magistrala/actions/workflows/check-generated-files.yml)
[![Continuous Delivery](https://github.com/absmach/magistrala/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/absmach/magistrala/actions/workflows/build.yml)
[![go report card][grc-badge]][grc-url]
[![coverage][cov-badge]][cov-url]
[![license][license]](LICENSE)
@@ -60,12 +57,11 @@ This will bring up the Magistrala docker services and interconnect them. This co
make run
```
If you want to run services from specific release checkout code from github and make sure that
`MG_RELEASE_TAG` in [.env](.env) is being set to match the release version
If you want to run services from specific release checkout code from github and make sure that `MG_RELEASE_TAG` in [.env](.env) is being set to match the release version
```bash
git checkout tags/<release_number> -b <release_number>
# e.g. `git checkout tags/0.13.0 -b 0.13.0`
# e.g. `git checkout tags/0.14.0 -b 0.14.0`
```
Check that `.env` file contains:
@@ -121,12 +117,6 @@ Thank you for your interest in Magistrala and the desire to contribute!
2. Checkout the [contribution guide](CONTRIBUTING.md) to learn more about our style and conventions.
3. Make your changes compatible to our workflow.
### We're Hiring
You like Magistrala and you would like to make it your day job? We're always looking for talented engineers interested in open-source, IoT and distributed systems. If you recognize yourself, reach out to [@drasko][drasko] - he will contact you back.
> The best way to grab our attention is, of course, by sending PRs :sunglasses:.
## Community
- [Google group][forum]
+38 -7
View File
@@ -26,7 +26,7 @@ servers:
- url: https://localhost:9009
- url: http://localhost:9011
- url: https://localhost:9011
tags:
- name: readers
description: Everything about your Readers
@@ -57,14 +57,16 @@ paths:
- $ref: "#/components/parameters/DataValue"
- $ref: "#/components/parameters/From"
- $ref: "#/components/parameters/To"
- $ref: "#/components/parameters/Aggregation"
- $ref: "#/components/parameters/Interval"
responses:
'200':
"200":
$ref: "#/components/responses/MessagesPageRes"
'400':
"400":
description: Failed due to malformed query parameters.
'401':
"401":
description: Missing or invalid access token provided.
'500':
"500":
$ref: "#/components/responses/ServiceError"
/health:
get:
@@ -72,9 +74,9 @@ paths:
tags:
- health
responses:
'200':
"200":
$ref: "#/components/responses/HealthRes"
'500':
"500":
$ref: "#/components/responses/ServiceError"
components:
@@ -226,6 +228,7 @@ components:
in: query
schema:
type: number
example: 1709218556069
required: false
To:
name: to
@@ -233,6 +236,34 @@ components:
in: query
schema:
type: number
example: 1709218757503
required: false
Aggregation:
name: aggregation
description: Aggregation function.
in: query
schema:
type: string
enum:
- MAX
- AVG
- MIN
- SUM
- COUNT
- max
- min
- sum
- avg
- count
example: MAX
required: false
Interval:
name: interval
description: Aggregation interval.
in: query
schema:
type: string
example: 10s
required: false
responses:
+287 -320
View File
@@ -204,12 +204,9 @@ type IssueReq struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
DomainId *string `protobuf:"bytes,2,opt,name=domain_id,json=domainId,proto3,oneof" json:"domain_id,omitempty"`
Type uint32 `protobuf:"varint,3,opt,name=type,proto3" json:"type,omitempty"`
OauthProvider string `protobuf:"bytes,4,opt,name=oauth_provider,json=oauthProvider,proto3" json:"oauth_provider,omitempty"`
OauthAccessToken string `protobuf:"bytes,5,opt,name=oauth_access_token,json=oauthAccessToken,proto3" json:"oauth_access_token,omitempty"`
OauthRefreshToken string `protobuf:"bytes,6,opt,name=oauth_refresh_token,json=oauthRefreshToken,proto3" json:"oauth_refresh_token,omitempty"`
UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
DomainId *string `protobuf:"bytes,2,opt,name=domain_id,json=domainId,proto3,oneof" json:"domain_id,omitempty"`
Type uint32 `protobuf:"varint,3,opt,name=type,proto3" json:"type,omitempty"`
}
func (x *IssueReq) Reset() {
@@ -265,27 +262,6 @@ func (x *IssueReq) GetType() uint32 {
return 0
}
func (x *IssueReq) GetOauthProvider() string {
if x != nil {
return x.OauthProvider
}
return ""
}
func (x *IssueReq) GetOauthAccessToken() string {
if x != nil {
return x.OauthAccessToken
}
return ""
}
func (x *IssueReq) GetOauthRefreshToken() string {
if x != nil {
return x.OauthRefreshToken
}
return ""
}
type RefreshReq struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -1901,162 +1877,217 @@ var file_auth_proto_rawDesc = []byte{
0x69, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x22, 0xec, 0x01, 0x0a, 0x08, 0x49, 0x73, 0x73,
0x75, 0x65, 0x52, 0x65, 0x71, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x20,
0x0a, 0x09, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x48, 0x00, 0x52, 0x08, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x88, 0x01, 0x01,
0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04,
0x74, 0x79, 0x70, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72,
0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6f, 0x61,
0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x2c, 0x0a, 0x12, 0x6f,
0x61, 0x75, 0x74, 0x68, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65,
0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x41, 0x63,
0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2e, 0x0a, 0x13, 0x6f, 0x61, 0x75,
0x74, 0x68, 0x5f, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e,
0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x52, 0x65, 0x66,
0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x64, 0x6f,
0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x22, 0x61, 0x0a, 0x0a, 0x52, 0x65, 0x66, 0x72, 0x65,
0x73, 0x68, 0x52, 0x65, 0x71, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68,
0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65,
0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x20, 0x0a, 0x09, 0x64, 0x6f,
0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52,
0x08, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a,
0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x22, 0xa6, 0x02, 0x0a, 0x0c, 0x41,
0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x64,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d,
0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74,
0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63,
0x74, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75,
0x62, 0x6a, 0x65, 0x63, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x75, 0x62,
0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20,
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x22, 0x67, 0x0a, 0x08, 0x49, 0x73, 0x73, 0x75,
0x65, 0x52, 0x65, 0x71, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x20, 0x0a,
0x09, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x48, 0x00, 0x52, 0x08, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12,
0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x74,
0x79, 0x70, 0x65, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x69,
0x64, 0x22, 0x61, 0x0a, 0x0a, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x65, 0x71, 0x12,
0x23, 0x0a, 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54,
0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x20, 0x0a, 0x09, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x69,
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x64, 0x6f, 0x6d, 0x61, 0x69,
0x6e, 0x49, 0x64, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69,
0x6e, 0x5f, 0x69, 0x64, 0x22, 0xa6, 0x02, 0x0a, 0x0c, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
0x7a, 0x65, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a,
0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65,
0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6b, 0x69, 0x6e, 0x64,
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4b,
0x69, 0x6e, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72,
0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73,
0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18,
0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52,
0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69,
0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73,
0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x08,
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b,
0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x3e, 0x0a,
0x0c, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x12, 0x1e, 0x0a,
0x0a, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
0x08, 0x52, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x0e, 0x0a,
0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0xc7, 0x02,
0x0a, 0x0c, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x12, 0x16,
0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63,
0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75,
0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x75, 0x62,
0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6c, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f,
0x6b, 0x69, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a,
0x65, 0x63, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63,
0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20,
0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a,
0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a,
0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f,
0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f,
0x6b, 0x69, 0x6e, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74,
0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a,
0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x52, 0x0a, 0x0e, 0x41, 0x64, 0x64, 0x50, 0x6f,
0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x12, 0x40, 0x0a, 0x0e, 0x61, 0x64, 0x64,
0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x18, 0x01, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41,
0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x52, 0x0e, 0x61, 0x64, 0x64,
0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x22, 0x24, 0x0a, 0x0c, 0x41,
0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x61,
0x64, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65,
0x64, 0x22, 0x26, 0x0a, 0x0e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73,
0x52, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x08, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x22, 0xca, 0x02, 0x0a, 0x0f, 0x44, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a,
0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74,
0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, 0x62,
0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a,
0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01,
0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6b,
0x69, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63,
0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74,
0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01,
0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a,
0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06,
0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x62,
0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6b,
0x69, 0x6e, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63,
0x74, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f,
0x74, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x5e, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x12, 0x49, 0x0a, 0x11, 0x64,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71,
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72,
0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79,
0x52, 0x65, 0x71, 0x52, 0x11, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63,
0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x22, 0x2b, 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65,
0x74, 0x65, 0x64, 0x22, 0x2d, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c,
0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65,
0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x64, 0x22, 0xc1, 0x02, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63,
0x74, 0x73, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a,
0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65,
0x12, 0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a,
0x65, 0x63, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73,
0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75,
0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18,
0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f,
0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28,
0x09, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a,
0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x6e, 0x65,
0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52,
0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x52, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62,
0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69,
0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69,
0x63, 0x69, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65,
0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78,
0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xac, 0x02, 0x0a, 0x0f, 0x43,
0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x12, 0x16,
0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63,
0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75,
0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x75, 0x62,
0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6c, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18,
0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1a,
0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09,
0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1a,
0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09,
0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65,
0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62,
0x6a, 0x65, 0x63, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65,
0x6a, 0x65, 0x63, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70,
0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54,
0x79, 0x70, 0x65, 0x22, 0x3e, 0x0a, 0x0c, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65,
0x52, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65,
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
0x7a, 0x65, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x02, 0x69, 0x64, 0x22, 0xc7, 0x02, 0x0a, 0x0c, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63,
0x79, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c,
0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12,
0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75,
0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x18, 0x0a,
0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f,
0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73,
0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x08, 0x20,
0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f,
0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x1f, 0x0a, 0x0b,
0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x52, 0x0a,
0x0e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x12,
0x40, 0x0a, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65,
0x71, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74,
0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65,
0x71, 0x52, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65,
0x71, 0x22, 0x24, 0x0a, 0x0c, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65,
0x73, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,
0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x22, 0x26, 0x0a, 0x0e, 0x41, 0x64, 0x64, 0x50, 0x6f,
0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x64, 0x64,
0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x22,
0xca, 0x02, 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79,
0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73,
0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29,
0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63,
0x74, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62,
0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07,
0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73,
0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54,
0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54,
0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74,
0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x27, 0x0a, 0x0f, 0x43, 0x6f, 0x75,
0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75,
0x6e, 0x74, 0x22, 0xc2, 0x02, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21,
0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70,
0x65, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62,
0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07,
0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73,
0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e,
0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69,
0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x08, 0x20, 0x01,
0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69,
0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x07, 0x20, 0x01,
0x28, 0x09, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62,
0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x6f,
0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x5e, 0x0a, 0x11,
0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65,
0x71, 0x12, 0x49, 0x0a, 0x11, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63,
0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6d,
0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x52, 0x11, 0x64, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x22, 0x2b, 0x0a, 0x0f,
0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x12,
0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,
0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x22, 0x2d, 0x0a, 0x11, 0x44, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x12, 0x18,
0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x22, 0xc1, 0x02, 0x0a, 0x0e, 0x4c, 0x69, 0x73,
0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x64,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d,
0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74,
0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63,
0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01,
0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72,
0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72,
0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69,
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x65, 0x72,
0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63,
0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12,
0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x08,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65,
0x12, 0x24, 0x0a, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65,
0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67,
0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18,
0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x52, 0x0a, 0x0e,
0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x12, 0x1a,
0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09,
0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x6e, 0x65,
0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
0x22, 0xac, 0x02, 0x0a, 0x0f, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74,
0x73, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c,
0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12,
0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75,
0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62,
0x6a, 0x65, 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e,
0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09,
0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f,
0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x6e, 0x65, 0x78,
0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22,
0x27, 0x0a, 0x0f, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52,
0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28,
0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xc2, 0x02, 0x0a, 0x0f, 0x4c, 0x69, 0x73,
0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06,
0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x6e,
0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x09, 0x20, 0x01,
0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65,
0x6e, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05,
0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x53, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x53,
0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f,
0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f,
0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61,
0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e,
0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xad, 0x02, 0x0a,
0x10, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65,
0x71, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62,
0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x10,
0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52,
0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63,
0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20,
0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a,
0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a,
0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f,
0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f,
0x74, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61,
0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e,
0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x28, 0x0a, 0x10,
0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73,
0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52,
0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xfc, 0x01, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x50,
0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a,
0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74,
0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, 0x62,
0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a,
0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01,
0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x04,
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x16, 0x0a,
0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f,
0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f,
0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2d, 0x0a, 0x12, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72,
0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x03,
0x28, 0x09, 0x52, 0x11, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73,
0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xef, 0x01, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65,
0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06,
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f,
0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f,
0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a,
@@ -2064,152 +2095,88 @@ var file_auth_proto_rawDesc = []byte{
0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x04, 0x20,
0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08,
0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65, 0x72, 0x6d,
0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x65,
0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74,
0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18,
0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70,
0x65, 0x12, 0x24, 0x0a, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b,
0x65, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61,
0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74,
0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x53, 0x0a,
0x0f, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73,
0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03,
0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0d,
0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b,
0x65, 0x6e, 0x22, 0xad, 0x02, 0x0a, 0x10, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a,
0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69,
0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12,
0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79,
0x70, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65,
0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75,
0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a,
0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f,
0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73,
0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x07, 0x20,
0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f,
0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0d,
0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x09, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b,
0x65, 0x6e, 0x22, 0x28, 0x0a, 0x10, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18,
0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xfc, 0x01, 0x0a,
0x12, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73,
0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73,
0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29,
0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63,
0x74, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62,
0x6a, 0x65, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a,
0x65, 0x63, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x05, 0x20,
0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f,
0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2d, 0x0a, 0x12,
0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f,
0x6e, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72,
0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xef, 0x01, 0x0a, 0x12,
0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52,
0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75,
0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a,
0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74,
0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a,
0x65, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x05, 0x20, 0x01,
0x28, 0x09, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62,
0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x70,
0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09,
0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0x51, 0x0a,
0x0c, 0x41, 0x75, 0x74, 0x68, 0x7a, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x41, 0x0a,
0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67,
0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a,
0x65, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c,
0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x22, 0x00,
0x32, 0xc6, 0x08, 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
0x12, 0x32, 0x0a, 0x05, 0x49, 0x73, 0x73, 0x75, 0x65, 0x12, 0x14, 0x2e, 0x6d, 0x61, 0x67, 0x69,
0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x52, 0x65, 0x71, 0x1a,
0x11, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x54, 0x6f, 0x6b,
0x65, 0x6e, 0x22, 0x00, 0x12, 0x36, 0x0a, 0x07, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x12,
0x16, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x52, 0x65, 0x66,
0x72, 0x65, 0x73, 0x68, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74,
0x72, 0x61, 0x6c, 0x61, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x08,
0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x12, 0x17, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73,
0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65,
0x71, 0x1a, 0x17, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x49,
0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x09,
0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69,
0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65,
0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61,
0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12,
0x41, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x18, 0x2e, 0x6d,
0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c,
0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72,
0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73,
0x22, 0x00, 0x12, 0x47, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65,
0x73, 0x12, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41,
0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e,
0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f,
0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, 0x44,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x1b, 0x2e, 0x6d, 0x61,
0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50,
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73,
0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69,
0x63, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x6d, 0x61, 0x67, 0x69,
0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c,
0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1d, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73,
0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69,
0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x0b, 0x4c, 0x69, 0x73,
0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73,
0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74,
0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c,
0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73,
0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x4f, 0x62, 0x6a,
0x65, 0x63, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c,
0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71,
0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69,
0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a,
0x0a, 0x0c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b,
0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x16, 0x0a, 0x06,
0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x62,
0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74,
0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63,
0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73,
0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d,
0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0x51, 0x0a, 0x0c, 0x41, 0x75, 0x74, 0x68, 0x7a,
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x41, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f,
0x72, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c,
0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x18,
0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68,
0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x22, 0x00, 0x32, 0xc6, 0x08, 0x0a, 0x0b, 0x41,
0x75, 0x74, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x32, 0x0a, 0x05, 0x49, 0x73,
0x73, 0x75, 0x65, 0x12, 0x14, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61,
0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x67, 0x69,
0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x00, 0x12, 0x36,
0x0a, 0x07, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x16, 0x2e, 0x6d, 0x61, 0x67, 0x69,
0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x65,
0x71, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x54,
0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x08, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69,
0x66, 0x79, 0x12, 0x17, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e,
0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x6d, 0x61,
0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74,
0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61,
0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e,
0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f,
0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x09, 0x41, 0x64, 0x64,
0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72,
0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71,
0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64,
0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x0b,
0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x6d, 0x61,
0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69,
0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74,
0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73,
0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50,
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61,
0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52,
0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e,
0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x22,
0x00, 0x12, 0x50, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63,
0x69, 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61,
0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52,
0x65, 0x71, 0x1a, 0x1d, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e,
0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65,
0x73, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63,
0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e,
0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a,
0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74,
0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0e,
0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1a,
0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74,
0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67,
0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, 0x43, 0x6f, 0x75, 0x6e,
0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73,
0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63,
0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61,
0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52,
0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a,
0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c,
0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65,
0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c,
0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00,
0x12, 0x4d, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61,
0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71,
0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69,
0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12,
0x4d, 0x0a, 0x0d, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73,
0x12, 0x1c, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f,
0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1c,
0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e,
0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61,
0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x62,
0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0c, 0x4c, 0x69,
0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67,
0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a,
0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74,
0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74,
0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c,
0x6c, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69,
0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72,
0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73,
0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x0d, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75,
0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1c, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72,
0x61, 0x6c, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74,
0x73, 0x52, 0x65, 0x71, 0x1a, 0x1c, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c,
0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52,
0x65, 0x73, 0x22, 0x00, 0x12, 0x53, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d,
0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74,
0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73,
0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74,
0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73,
0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x42, 0x0e, 0x5a, 0x0c, 0x2e, 0x2f, 0x6d,
0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x53,
0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e,
0x73, 0x12, 0x1e, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c,
0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65,
0x71, 0x1a, 0x1e, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x4c,
0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65,
0x73, 0x22, 0x00, 0x42, 0x0e, 0x5a, 0x0c, 0x2e, 0x2f, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72,
0x61, 0x6c, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
+1 -4
View File
@@ -56,10 +56,7 @@ message IdentityRes {
message IssueReq {
string user_id = 1;
optional string domain_id = 2;
uint32 type = 3;
string oauth_provider = 4;
string oauth_access_token = 5;
string oauth_refresh_token = 6;
uint32 type = 3;
}
message RefreshReq {
+46 -34
View File
@@ -59,40 +59,46 @@ Domain consists of the following fields:
The service is configured using the environment variables presented in the following table. Note that any unset variables will be replaced with their default values.
| Variable | Description | Default |
| ------------------------------ | ----------------------------------------------------------------------- | -------------------------------- |
| MG_AUTH_LOG_LEVEL | Log level for the Auth service (debug, info, warn, error) | info |
| MG_AUTH_DB_HOST | Database host address | localhost |
| MG_AUTH_DB_PORT | Database host port | 5432 |
| MG_AUTH_DB_USER | Database user | magistrala |
| MG_AUTH_DB_PASSWORD | Database password | magistrala |
| MG_AUTH_DB_NAME | Name of the database used by the service | auth |
| MG_AUTH_DB_SSL_MODE | Database connection SSL mode (disable, require, verify-ca, verify-full) | disable |
| MG_AUTH_DB_SSL_CERT | Path to the PEM encoded certificate file | "" |
| MG_AUTH_DB_SSL_KEY | Path to the PEM encoded key file | "" |
| MG_AUTH_DB_SSL_ROOT_CERT | Path to the PEM encoded root certificate file | "" |
| MG_AUTH_HTTP_HOST | Auth service HTTP host | "" |
| MG_AUTH_HTTP_PORT | Auth service HTTP port | 8189 |
| MG_AUTH_HTTP_SERVER_CERT | Path to the PEM encoded HTTP server certificate file | "" |
| MG_AUTH_HTTP_SERVER_KEY | Path to the PEM encoded HTTP server key file | "" |
| MG_AUTH_GRPC_HOST | Auth service gRPC host | "" |
| MG_AUTH_GRPC_PORT | Auth service gRPC port | 8181 |
| MG_AUTH_GRPC_SERVER_CERT | Path to the PEM encoded gRPC server certificate file | "" |
| MG_AUTH_GRPC_SERVER_KEY | Path to the PEM encoded gRPC server key file | "" |
| MG_AUTH_GRPC_SERVER_CA_CERTS | Path to the PEM encoded gRPC server CA certificate file | "" |
| MG_AUTH_GRPC_CLIENT_CA_CERTS | Path to the PEM encoded gRPC client CA certificate file | "" |
| MG_AUTH_SECRET_KEY | String used for signing tokens | secret |
| MG_AUTH_ACCESS_TOKEN_DURATION | The access token expiration period | 1h |
| MG_AUTH_REFRESH_TOKEN_DURATION | The refresh token expiration period | 24h |
| MG_AUTH_INVITATION_DURATION | The invitation token expiration period | 168h |
| MG_SPICEDB_HOST | SpiceDB host address | localhost |
| MG_SPICEDB_PORT | SpiceDB host port | 50051 |
| MG_SPICEDB_PRE_SHARED_KEY | SpiceDB pre-shared key | 12345678 |
| MG_SPICEDB_SCHEMA_FILE | Path to SpiceDB schema file | ./docker/spicedb/schema.zed |
| MG_JAEGER_URL | Jaeger server URL | <http://jaeger:14268/api/traces> |
| MG_JAEGER_TRACE_RATIO | Jaeger sampling ratio | 1.0 |
| MG_SEND_TELEMETRY | Send telemetry to magistrala call home server | true |
| MG_AUTH_ADAPTER_INSTANCE_ID | Adapter instance ID | "" |
| Variable | Description | Default |
| ------------------------------ | ----------------------------------------------------------------------- | ---------------------------------------- |
| MG_AUTH_LOG_LEVEL | Log level for the Auth service (debug, info, warn, error) | info |
| MG_AUTH_DB_HOST | Database host address | localhost |
| MG_AUTH_DB_PORT | Database host port | 5432 |
| MG_AUTH_DB_USER | Database user | magistrala |
| MG_AUTH_DB_PASSWORD | Database password | magistrala |
| MG_AUTH_DB_NAME | Name of the database used by the service | auth |
| MG_AUTH_DB_SSL_MODE | Database connection SSL mode (disable, require, verify-ca, verify-full) | disable |
| MG_AUTH_DB_SSL_CERT | Path to the PEM encoded certificate file | "" |
| MG_AUTH_DB_SSL_KEY | Path to the PEM encoded key file | "" |
| MG_AUTH_DB_SSL_ROOT_CERT | Path to the PEM encoded root certificate file | "" |
| MG_AUTH_HTTP_HOST | Auth service HTTP host | "" |
| MG_AUTH_HTTP_PORT | Auth service HTTP port | 8189 |
| MG_AUTH_HTTP_SERVER_CERT | Path to the PEM encoded HTTP server certificate file | "" |
| MG_AUTH_HTTP_SERVER_KEY | Path to the PEM encoded HTTP server key file | "" |
| MG_AUTH_GRPC_HOST | Auth service gRPC host | "" |
| MG_AUTH_GRPC_PORT | Auth service gRPC port | 8181 |
| MG_AUTH_GRPC_SERVER_CERT | Path to the PEM encoded gRPC server certificate file | "" |
| MG_AUTH_GRPC_SERVER_KEY | Path to the PEM encoded gRPC server key file | "" |
| MG_AUTH_GRPC_SERVER_CA_CERTS | Path to the PEM encoded gRPC server CA certificate file | "" |
| MG_AUTH_GRPC_CLIENT_CA_CERTS | Path to the PEM encoded gRPC client CA certificate file | "" |
| MG_AUTH_SECRET_KEY | String used for signing tokens | secret |
| MG_AUTH_ACCESS_TOKEN_DURATION | The access token expiration period | 1h |
| MG_AUTH_REFRESH_TOKEN_DURATION | The refresh token expiration period | 24h |
| MG_AUTH_INVITATION_DURATION | The invitation token expiration period | 168h |
| MG_SPICEDB_HOST | SpiceDB host address | localhost |
| MG_SPICEDB_PORT | SpiceDB host port | 50051 |
| MG_SPICEDB_PRE_SHARED_KEY | SpiceDB pre-shared key | 12345678 |
| MG_SPICEDB_SCHEMA_FILE | Path to SpiceDB schema file | ./docker/spicedb/schema.zed |
| MG_JAEGER_URL | Jaeger server URL | <http://jaeger:14268/api/traces> |
| MG_JAEGER_TRACE_RATIO | Jaeger sampling ratio | 1.0 |
| MG_SEND_TELEMETRY | Send telemetry to magistrala call home server | true |
| MG_AUTH_ADAPTER_INSTANCE_ID | Adapter instance ID | "" |
| MG_KRATOS_CLIENT_ID | Kratos client ID | "" |
| MG_KRATOS_CLIENT_SECRET | Kratos client secret | "" |
| MG_KRATOS_REDIRECT_URL | Kratos redirect URL | <http://localhost/oauth/callback/kratos> |
| MG_KRATOS_STATE | Kratos state | "" |
| MG_KRATOS_URL | Kratos URL | <http://localhost:4433> |
| MG_KRATOS_API_KEY | Kratos API key | "" |
## Deployment
@@ -146,6 +152,12 @@ MG_JAEGER_URL=http://localhost:14268/api/traces \
MG_JAEGER_TRACE_RATIO=1.0 \
MG_SEND_TELEMETRY=true \
MG_AUTH_ADAPTER_INSTANCE_ID="" \
MG_KRATOS_CLIENT_ID="" \
MG_KRATOS_CLIENT_SECRET="" \
MG_KRATOS_REDIRECT_URL=http://localhost/oauth/callback/kratos \
MG_KRATOS_STATE="" \
MG_KRATOS_URL=http://localhost:4433 \
MG_KRATOS_API_KEY="" \
$GOBIN/magistrala-auth
```
+3 -11
View File
@@ -178,11 +178,6 @@ func (client grpcClient) Issue(ctx context.Context, req *magistrala.IssueReq, _
userID: req.GetUserId(),
domainID: req.GetDomainId(),
keyType: auth.KeyType(req.GetType()),
oauthToken: auth.OAuthToken{
Provider: req.GetOauthProvider(),
AccessToken: req.GetOauthAccessToken(),
RefreshToken: req.GetOauthRefreshToken(),
},
})
if err != nil {
return &magistrala.Token{}, decodeError(err)
@@ -193,12 +188,9 @@ func (client grpcClient) Issue(ctx context.Context, req *magistrala.IssueReq, _
func encodeIssueRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
req := grpcReq.(issueReq)
return &magistrala.IssueReq{
UserId: req.userID,
DomainId: &req.domainID,
Type: uint32(req.keyType),
OauthProvider: req.oauthToken.Provider,
OauthAccessToken: req.oauthToken.AccessToken,
OauthRefreshToken: req.oauthToken.RefreshToken,
UserId: req.userID,
DomainId: &req.domainID,
Type: uint32(req.keyType),
}, nil
}
-1
View File
@@ -21,7 +21,6 @@ func issueEndpoint(svc auth.Service) endpoint.Endpoint {
Type: req.keyType,
User: req.userID,
Domain: req.domainID,
OAuth: req.oauthToken,
}
tkn, err := svc.Issue(ctx, "", key)
if err != nil {
+3 -4
View File
@@ -21,10 +21,9 @@ func (req identityReq) validate() error {
}
type issueReq struct {
userID string
domainID string // optional
keyType auth.KeyType
oauthToken auth.OAuthToken
userID string
domainID string // optional
keyType auth.KeyType
}
func (req issueReq) validate() error {
-5
View File
@@ -277,11 +277,6 @@ func decodeIssueRequest(_ context.Context, grpcReq interface{}) (interface{}, er
userID: req.GetUserId(),
domainID: req.GetDomainId(),
keyType: auth.KeyType(req.GetType()),
oauthToken: auth.OAuthToken{
Provider: req.GetOauthProvider(),
AccessToken: req.GetOauthAccessToken(),
RefreshToken: req.GetOauthRefreshToken(),
},
}, nil
}
+1 -4
View File
@@ -21,7 +21,6 @@ import (
"github.com/absmach/magistrala/internal/apiutil"
mglog "github.com/absmach/magistrala/logger"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
oauth2mocks "github.com/absmach/magistrala/pkg/oauth2/mocks"
"github.com/absmach/magistrala/pkg/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
@@ -73,9 +72,7 @@ func newService() (auth.Service, *mocks.KeyRepository) {
drepo := new(mocks.DomainsRepository)
idProvider := uuid.NewMock()
provider := new(oauth2mocks.Provider)
provider.On("Name").Return("test")
t := jwt.New([]byte(secret), provider)
t := jwt.New([]byte(secret))
return auth.New(krepo, drepo, idProvider, t, prepo, loginDuration, refreshDuration, invalidDuration), krepo
}
+2 -156
View File
@@ -4,9 +4,7 @@
package jwt_test
import (
"context"
"fmt"
"strings"
"testing"
"time"
@@ -15,13 +13,10 @@ import (
"github.com/absmach/magistrala/internal/testsutil"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
oauth2mocks "github.com/absmach/magistrala/pkg/oauth2/mocks"
"github.com/lestrrat-go/jwx/v2/jwa"
"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"golang.org/x/oauth2"
)
const (
@@ -56,9 +51,7 @@ func newToken(issuerName string, key auth.Key) string {
}
func TestIssue(t *testing.T) {
provider := new(oauth2mocks.Provider)
provider.On("Name").Return("test")
tokenizer := authjwt.New([]byte(secret), provider)
tokenizer := authjwt.New([]byte(secret))
cases := []struct {
desc string
@@ -80,11 +73,6 @@ func TestIssue(t *testing.T) {
Domain: testsutil.GenerateUUID(t),
IssuedAt: time.Now().Add(-10 * time.Second).Round(time.Second),
ExpiresAt: time.Now().Add(10 * time.Minute).Round(time.Second),
OAuth: auth.OAuthToken{
Provider: "test",
AccessToken: strings.Repeat("a", 1024),
RefreshToken: strings.Repeat("b", 1024),
},
},
err: nil,
},
@@ -100,9 +88,7 @@ func TestIssue(t *testing.T) {
}
func TestParse(t *testing.T) {
provider := new(oauth2mocks.Provider)
provider.On("Name").Return("test")
tokenizer := authjwt.New([]byte(secret), provider)
tokenizer := authjwt.New([]byte(secret))
token, err := tokenizer.Issue(key())
require.Nil(t, err, fmt.Sprintf("issuing key expected to succeed: %s", err))
@@ -173,99 +159,6 @@ func TestParse(t *testing.T) {
}
}
func TestParseOAuthToken(t *testing.T) {
provider := new(oauth2mocks.Provider)
provider.On("Name").Return("test")
tokenizer := authjwt.New([]byte(secret), provider)
validKey := oauthKey(t)
invalidKey := oauthKey(t)
invalidKey.OAuth.Provider = "invalid"
cases := []struct {
desc string
token auth.Key
issuedToken string
key auth.Key
validateErr error
refreshToken oauth2.Token
refreshErr error
err error
}{
{
desc: "parse valid key",
token: validKey,
issuedToken: "",
key: validKey,
validateErr: nil,
refreshErr: nil,
err: nil,
},
{
desc: "parse invalid key but refreshed",
token: validKey,
issuedToken: "",
key: validKey,
validateErr: svcerr.ErrAuthentication,
refreshToken: oauth2.Token{
AccessToken: strings.Repeat("a", 10),
RefreshToken: strings.Repeat("b", 10),
},
refreshErr: nil,
err: nil,
},
{
desc: "parse invalid key but not refreshed",
token: validKey,
issuedToken: "",
key: validKey,
validateErr: svcerr.ErrAuthentication,
refreshToken: oauth2.Token{},
refreshErr: svcerr.ErrAuthentication,
err: svcerr.ErrAuthentication,
},
{
desc: "parse invalid key with different provider",
issuedToken: invalidOauthToken(t, invalidKey, "invalid", "a", "b"),
err: svcerr.ErrAuthentication,
},
{
desc: "parse invalid key with invalid access token",
issuedToken: invalidOauthToken(t, invalidKey, "invalid", 123, "b"),
err: svcerr.ErrAuthentication,
},
{
desc: "parse invalid key with invalid refresh token",
issuedToken: invalidOauthToken(t, invalidKey, "invalid", "a", 123),
err: svcerr.ErrAuthentication,
},
{
desc: "parse invalid key with invalid provider",
issuedToken: invalidOauthToken(t, invalidKey, "test", "a", "b"),
err: svcerr.ErrAuthentication,
},
}
for _, tc := range cases {
tokenCall := provider.On("Name").Return("test")
tokenCall1 := provider.On("Validate", context.Background(), mock.Anything).Return(tc.validateErr)
tokenCall2 := provider.On("Refresh", context.Background(), mock.Anything).Return(tc.refreshToken, tc.refreshErr)
if tc.issuedToken == "" {
var err error
tc.issuedToken, err = tokenizer.Issue(tc.token)
require.Nil(t, err, fmt.Sprintf("issuing key expected to succeed: %s", err))
}
key, err := tokenizer.Parse(tc.issuedToken)
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s, got %s", tc.desc, tc.err, err))
if err == nil {
assert.Equal(t, tc.key, key, fmt.Sprintf("%s expected %v, got %v", tc.desc, tc.key, key))
}
tokenCall.Unset()
tokenCall1.Unset()
tokenCall2.Unset()
}
}
func key() auth.Key {
exp := time.Now().UTC().Add(10 * time.Minute).Round(time.Second)
return auth.Key{
@@ -277,50 +170,3 @@ func key() auth.Key {
ExpiresAt: exp,
}
}
func oauthKey(t *testing.T) auth.Key {
return auth.Key{
ID: testsutil.GenerateUUID(t),
Type: auth.AccessKey,
Issuer: "magistrala.auth",
Subject: testsutil.GenerateUUID(t),
User: testsutil.GenerateUUID(t),
Domain: testsutil.GenerateUUID(t),
IssuedAt: time.Now().UTC().Add(-10 * time.Second).Round(time.Second),
ExpiresAt: time.Now().UTC().Add(10 * time.Minute).Round(time.Second),
OAuth: auth.OAuthToken{
Provider: "test",
AccessToken: strings.Repeat("a", 10),
RefreshToken: strings.Repeat("b", 10),
},
}
}
func invalidOauthToken(t *testing.T, key auth.Key, provider, accessToken, refreshToken interface{}) string {
builder := jwt.NewBuilder()
builder.
Issuer(issuerName).
IssuedAt(key.IssuedAt).
Subject(key.Subject).
Claim(tokenType, key.Type).
Expiration(key.ExpiresAt)
builder.Claim(userField, key.User)
builder.Claim(domainField, key.Domain)
if provider != nil {
builder.Claim("oauth_provider", provider)
if accessToken != nil {
builder.Claim(provider.(string), map[string]interface{}{"access_token": accessToken})
}
if refreshToken != nil {
builder.Claim(provider.(string), map[string]interface{}{"refresh_token": refreshToken})
}
}
if key.ID != "" {
builder.JwtID(key.ID)
}
tkn, err := builder.Build()
require.Nil(t, err, fmt.Sprintf("building token expected to succeed: %s", err))
signedTkn, err := jwt.Sign(tkn, jwt.WithKey(jwa.HS512, reposecret))
require.Nil(t, err, fmt.Sprintf("signing token expected to succeed: %s", err))
return string(signedTkn)
}
+28 -92
View File
@@ -12,7 +12,6 @@ import (
"github.com/absmach/magistrala/auth"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
"github.com/absmach/magistrala/pkg/oauth2"
"github.com/lestrrat-go/jwx/v2/jwa"
"github.com/lestrrat-go/jwx/v2/jwt"
)
@@ -33,9 +32,6 @@ var (
ErrValidateJWTToken = errors.New("failed to validate jwt token")
// ErrJSONHandle indicates an error in handling JSON.
ErrJSONHandle = errors.New("failed to perform operation JSON")
// errInvalidProvider indicates an invalid OAuth2.0 provider.
errInvalidProvider = errors.New("invalid OAuth2.0 provider")
)
const (
@@ -49,21 +45,15 @@ const (
)
type tokenizer struct {
secret []byte
providers map[string]oauth2.Provider
secret []byte
}
var _ auth.Tokenizer = (*tokenizer)(nil)
// NewRepository instantiates an implementation of Token repository.
func New(secret []byte, providers ...oauth2.Provider) auth.Tokenizer {
providersMap := make(map[string]oauth2.Provider)
for _, provider := range providers {
providersMap[provider.Name()] = provider
}
func New(secret []byte) auth.Tokenizer {
return &tokenizer{
secret: secret,
providers: providersMap,
secret: secret,
}
}
@@ -78,18 +68,6 @@ func (tok *tokenizer) Issue(key auth.Key) (string, error) {
builder.Claim(userField, key.User)
builder.Claim(domainField, key.Domain)
if key.OAuth.Provider != "" {
provider, ok := tok.providers[key.OAuth.Provider]
if !ok {
return "", errors.Wrap(svcerr.ErrAuthentication, errInvalidProvider)
}
builder.Claim(oauthProviderField, provider.Name())
builder.Claim(provider.Name(), map[string]interface{}{
oauthAccessTokenField: key.OAuth.AccessToken,
oauthRefreshTokenField: key.OAuth.RefreshToken,
})
}
if key.ID != "" {
builder.JwtID(key.ID)
}
@@ -105,6 +83,20 @@ func (tok *tokenizer) Issue(key auth.Key) (string, error) {
}
func (tok *tokenizer) Parse(token string) (auth.Key, error) {
tkn, err := tok.validateToken(token)
if err != nil {
return auth.Key{}, errors.Wrap(svcerr.ErrAuthentication, err)
}
key, err := toKey(tkn)
if err != nil {
return auth.Key{}, errors.Wrap(svcerr.ErrAuthentication, err)
}
return key, nil
}
func (tok *tokenizer) validateToken(token string) (jwt.Token, error) {
tkn, err := jwt.Parse(
[]byte(token),
jwt.WithValidate(true),
@@ -112,10 +104,10 @@ func (tok *tokenizer) Parse(token string) (auth.Key, error) {
)
if err != nil {
if errors.Contains(err, errJWTExpiryKey) {
return auth.Key{}, ErrExpiry
return nil, ErrExpiry
}
return auth.Key{}, errors.Wrap(svcerr.ErrAuthentication, err)
return nil, err
}
validator := jwt.ValidatorFunc(func(_ context.Context, t jwt.Token) jwt.ValidationError {
if t.Issuer() != issuerName {
@@ -124,25 +116,29 @@ func (tok *tokenizer) Parse(token string) (auth.Key, error) {
return nil
})
if err := jwt.Validate(tkn, jwt.WithValidator(validator)); err != nil {
return auth.Key{}, errors.Wrap(ErrValidateJWTToken, err)
return nil, errors.Wrap(ErrValidateJWTToken, err)
}
jsn, err := json.Marshal(tkn.PrivateClaims())
return tkn, nil
}
func toKey(tkn jwt.Token) (auth.Key, error) {
data, err := json.Marshal(tkn.PrivateClaims())
if err != nil {
return auth.Key{}, errors.Wrap(ErrJSONHandle, err)
}
var key auth.Key
if err := json.Unmarshal(jsn, &key); err != nil {
if err := json.Unmarshal(data, &key); err != nil {
return auth.Key{}, errors.Wrap(ErrJSONHandle, err)
}
tType, ok := tkn.Get(tokenType)
if !ok {
return auth.Key{}, errors.Wrap(svcerr.ErrAuthentication, err)
return auth.Key{}, err
}
ktype, err := strconv.ParseInt(fmt.Sprintf("%v", tType), 10, 64)
if err != nil {
return auth.Key{}, errors.Wrap(svcerr.ErrAuthentication, err)
return auth.Key{}, err
}
key.ID = tkn.JwtID()
@@ -152,65 +148,5 @@ func (tok *tokenizer) Parse(token string) (auth.Key, error) {
key.IssuedAt = tkn.IssuedAt()
key.ExpiresAt = tkn.Expiration()
oauthProvider, ok := tkn.Get(oauthProviderField)
if ok {
provider, ok := oauthProvider.(string)
if !ok {
return auth.Key{}, errors.Wrap(svcerr.ErrAuthentication, errInvalidProvider)
}
if provider != "" {
prov, ok := tok.providers[provider]
if !ok {
return auth.Key{}, errors.Wrap(svcerr.ErrAuthentication, errInvalidProvider)
}
key.OAuth.Provider = prov.Name()
key, err = parseOAuthToken(context.Background(), prov, tkn, key)
if err != nil {
return auth.Key{}, errors.Wrap(svcerr.ErrAuthentication, err)
}
return key, nil
}
}
return key, nil
}
func parseOAuthToken(ctx context.Context, provider oauth2.Provider, token jwt.Token, key auth.Key) (auth.Key, error) {
oauthToken, ok := token.Get(provider.Name())
if ok {
claims, ok := oauthToken.(map[string]interface{})
if !ok {
return auth.Key{}, errors.Wrap(ErrParseToken, fmt.Errorf("invalid claims for %s token", provider.Name()))
}
accessToken, ok := claims[oauthAccessTokenField].(string)
if !ok {
return auth.Key{}, errors.Wrap(ErrParseToken, fmt.Errorf("invalid access token claim for %s token", provider.Name()))
}
refreshToken, ok := claims[oauthRefreshTokenField].(string)
if !ok {
return auth.Key{}, errors.Wrap(ErrParseToken, fmt.Errorf("invalid refresh token claim for %s token", provider.Name()))
}
switch provider.Validate(ctx, accessToken) {
case nil:
key.OAuth.AccessToken = accessToken
default:
token, err := provider.Refresh(ctx, refreshToken)
if err != nil {
return auth.Key{}, errors.Wrap(svcerr.ErrAuthentication, err)
}
key.OAuth.AccessToken = token.AccessToken
key.OAuth.RefreshToken = token.RefreshToken
return key, nil
}
key.OAuth.RefreshToken = refreshToken
return key, nil
}
return key, nil
}
+8 -16
View File
@@ -58,24 +58,16 @@ func (kt KeyType) String() string {
}
}
// OAuthToken represents OAuth token.
type OAuthToken struct {
Provider string `json:"provider,omitempty"`
AccessToken string `json:"access_token,omitempty"`
RefreshToken string `json:"refresh_token,omitempty"`
}
// Key represents API key.
type Key struct {
ID string `json:"id,omitempty"`
Type KeyType `json:"type,omitempty"`
Issuer string `json:"issuer,omitempty"`
Subject string `json:"subject,omitempty"` // user ID
User string `json:"user,omitempty"`
Domain string `json:"domain,omitempty"` // domain user ID
IssuedAt time.Time `json:"issued_at,omitempty"`
ExpiresAt time.Time `json:"expires_at,omitempty"`
OAuth OAuthToken `json:"oauth,omitempty"`
ID string `json:"id,omitempty"`
Type KeyType `json:"type,omitempty"`
Issuer string `json:"issuer,omitempty"`
Subject string `json:"subject,omitempty"` // user ID
User string `json:"user,omitempty"`
Domain string `json:"domain,omitempty"` // domain user ID
IssuedAt time.Time `json:"issued_at,omitempty"`
ExpiresAt time.Time `json:"expires_at,omitempty"`
}
func (key Key) String() string {
+2 -4
View File
@@ -385,6 +385,7 @@ func (svc service) accessKey(ctx context.Context, key Key) (Token, error) {
if err != nil {
return Token{}, errors.Wrap(errIssueTmp, err)
}
key.ExpiresAt = time.Now().Add(svc.refreshDuration)
key.Type = RefreshKey
refresh, err := svc.tokenizer.Issue(key)
@@ -428,10 +429,6 @@ func (svc service) refreshKey(ctx context.Context, token string, key Key) (Token
key.User = k.User
key.Type = AccessKey
key.OAuth.Provider = k.OAuth.Provider
key.OAuth.AccessToken = k.OAuth.AccessToken
key.OAuth.RefreshToken = k.OAuth.RefreshToken
key.Subject, err = svc.checkUserDomain(ctx, key)
if err != nil {
return Token{}, errors.Wrap(svcerr.ErrAuthorization, err)
@@ -442,6 +439,7 @@ func (svc service) refreshKey(ctx context.Context, token string, key Key) (Token
if err != nil {
return Token{}, errors.Wrap(errIssueTmp, err)
}
key.ExpiresAt = time.Now().Add(svc.refreshDuration)
key.Type = RefreshKey
refresh, err := svc.tokenizer.Issue(key)
+4 -13
View File
@@ -15,7 +15,6 @@ import (
"github.com/absmach/magistrala/pkg/errors"
repoerr "github.com/absmach/magistrala/pkg/errors/repository"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
oauth2mocks "github.com/absmach/magistrala/pkg/oauth2/mocks"
"github.com/absmach/magistrala/pkg/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
@@ -70,9 +69,7 @@ func newService() (auth.Service, string) {
drepo = new(mocks.DomainsRepository)
idProvider := uuid.NewMock()
provider := new(oauth2mocks.Provider)
provider.On("Name").Return("test")
t := jwt.New([]byte(secret), provider)
t := jwt.New([]byte(secret))
key := auth.Key{
IssuedAt: time.Now(),
ExpiresAt: time.Now().Add(refreshDuration),
@@ -89,9 +86,7 @@ func newService() (auth.Service, string) {
func TestIssue(t *testing.T) {
svc, accessToken := newService()
provider := new(oauth2mocks.Provider)
provider.On("Name").Return("test")
n := jwt.New([]byte(secret), provider)
n := jwt.New([]byte(secret))
apikey := auth.Key{
IssuedAt: time.Now(),
@@ -633,9 +628,7 @@ func TestIdentify(t *testing.T) {
assert.Nil(t, err, fmt.Sprintf("Issuing expired login key expected to succeed: %s", err))
repocall4.Unset()
provider := new(oauth2mocks.Provider)
provider.On("Name").Return("test")
te := jwt.New([]byte(secret), provider)
te := jwt.New([]byte(secret))
key := auth.Key{
IssuedAt: time.Now(),
ExpiresAt: time.Now().Add(refreshDuration),
@@ -729,9 +722,7 @@ func TestAuthorize(t *testing.T) {
repocall2.Unset()
repocall3.Unset()
provider := new(oauth2mocks.Provider)
provider.On("Name").Return("test")
te := jwt.New([]byte(secret), provider)
te := jwt.New([]byte(secret))
key := auth.Key{
IssuedAt: time.Now(),
ExpiresAt: time.Now().Add(refreshDuration),
+62 -17
View File
@@ -17,10 +17,28 @@ import (
"github.com/spf13/cobra"
)
const (
defURL string = "http://localhost"
defUsersURL string = defURL + ":9002"
defThingsURL string = defURL + ":9000"
defReaderURL string = defURL + ":9011"
defBootstrapURL string = defURL + ":9013"
defDomainsURL string = defURL + ":8189"
defCertsURL string = defURL + ":9019"
defInvitationsURL string = defURL + ":9020"
defHTTPURL string = defURL + ":9016/http"
defTLSVerification bool = false
defOffset string = "0"
defLimit string = "10"
defTopic string = ""
defRawOutput string = "false"
)
type remotes struct {
ThingsURL string `toml:"things_url"`
UsersURL string `toml:"users_url"`
ReaderURL string `toml:"reader_url"`
DomainsURL string `toml:"domains_url"`
HTTPAdapterURL string `toml:"http_adapter_url"`
BootstrapURL string `toml:"bootstrap_url"`
CertsURL string `toml:"certs_url"`
@@ -85,14 +103,21 @@ func ParseConfig(sdkConf mgxsdk.Config) (mgxsdk.Config, error) {
case os.IsNotExist(err):
defaultConfig := config{
Remotes: remotes{
ThingsURL: "http://localhost:9000",
UsersURL: "http://localhost:9002",
ReaderURL: "http://localhost",
HTTPAdapterURL: "http://localhost/http:9016",
BootstrapURL: "http://localhost",
CertsURL: "http://localhost:9019",
TLSVerification: false,
ThingsURL: defThingsURL,
UsersURL: defUsersURL,
ReaderURL: defReaderURL,
DomainsURL: defDomainsURL,
HTTPAdapterURL: defHTTPURL,
BootstrapURL: defBootstrapURL,
CertsURL: defCertsURL,
TLSVerification: defTLSVerification,
},
Filter: filter{
Offset: defOffset,
Limit: defLimit,
Topic: defTopic,
},
RawOutput: defRawOutput,
}
buf, err := toml.Marshal(defaultConfig)
if err != nil {
@@ -110,7 +135,7 @@ func ParseConfig(sdkConf mgxsdk.Config) (mgxsdk.Config, error) {
return sdkConf, err
}
if config.Filter.Offset != "" {
if config.Filter.Offset != "" && Offset == 0 {
offset, err := strconv.ParseUint(config.Filter.Offset, 10, 64)
if err != nil {
return sdkConf, err
@@ -118,7 +143,7 @@ func ParseConfig(sdkConf mgxsdk.Config) (mgxsdk.Config, error) {
Offset = offset
}
if config.Filter.Limit != "" {
if config.Filter.Limit != "" && Limit == 0 {
limit, err := strconv.ParseUint(config.Filter.Limit, 10, 64)
if err != nil {
return sdkConf, err
@@ -126,7 +151,7 @@ func ParseConfig(sdkConf mgxsdk.Config) (mgxsdk.Config, error) {
Limit = limit
}
if config.Filter.Topic != "" {
if config.Filter.Topic != "" && Topic == "" {
Topic = config.Filter.Topic
}
@@ -135,15 +160,35 @@ func ParseConfig(sdkConf mgxsdk.Config) (mgxsdk.Config, error) {
if err != nil {
return sdkConf, err
}
RawOutput = rawOutput
// check for config file value or flag input value is true
RawOutput = rawOutput || RawOutput
}
sdkConf.ThingsURL = config.Remotes.ThingsURL
sdkConf.UsersURL = config.Remotes.UsersURL
sdkConf.ReaderURL = config.Remotes.ReaderURL
sdkConf.HTTPAdapterURL = config.Remotes.HTTPAdapterURL
sdkConf.BootstrapURL = config.Remotes.BootstrapURL
sdkConf.CertsURL = config.Remotes.CertsURL
if sdkConf.ThingsURL == "" && config.Remotes.ThingsURL != "" {
sdkConf.ThingsURL = config.Remotes.ThingsURL
}
if sdkConf.UsersURL == "" && config.Remotes.UsersURL != "" {
sdkConf.UsersURL = config.Remotes.UsersURL
}
if sdkConf.ReaderURL == "" && config.Remotes.ReaderURL != "" {
sdkConf.ReaderURL = config.Remotes.ReaderURL
}
if sdkConf.HTTPAdapterURL == "" && config.Remotes.HTTPAdapterURL != "" {
sdkConf.HTTPAdapterURL = config.Remotes.HTTPAdapterURL
}
if sdkConf.BootstrapURL == "" && config.Remotes.BootstrapURL != "" {
sdkConf.BootstrapURL = config.Remotes.BootstrapURL
}
if sdkConf.CertsURL == "" && config.Remotes.CertsURL != "" {
sdkConf.CertsURL = config.Remotes.CertsURL
}
sdkConf.TLSVerification = config.Remotes.TLSVerification || sdkConf.TLSVerification
return sdkConf, nil
}
+5 -3
View File
@@ -38,9 +38,11 @@ var cmdMessages = []cobra.Command{
logUsage(cmd.Use)
return
}
pageMetadata := mgxsdk.PageMetadata{
Offset: Offset,
Limit: Limit,
pageMetadata := mgxsdk.MessagePageMetadata{
PageMetadata: mgxsdk.PageMetadata{
Offset: Offset,
Limit: Limit,
},
}
m, err := sdk.ReadMessages(pageMetadata, args[0], args[1])
+12 -21
View File
@@ -30,8 +30,6 @@ import (
grpcserver "github.com/absmach/magistrala/internal/server/grpc"
httpserver "github.com/absmach/magistrala/internal/server/http"
mglog "github.com/absmach/magistrala/logger"
"github.com/absmach/magistrala/pkg/oauth2"
"github.com/absmach/magistrala/pkg/oauth2/google"
"github.com/absmach/magistrala/pkg/uuid"
v1 "github.com/authzed/authzed-go/proto/authzed/api/v1"
"github.com/authzed/authzed-go/v1"
@@ -46,14 +44,13 @@ import (
)
const (
svcName = "auth"
envPrefixHTTP = "MG_AUTH_HTTP_"
envPrefixGrpc = "MG_AUTH_GRPC_"
envPrefixDB = "MG_AUTH_DB_"
envPrefixGoogle = "MG_GOOGLE_"
defDB = "auth"
defSvcHTTPPort = "8180"
defSvcGRPCPort = "8181"
svcName = "auth"
envPrefixHTTP = "MG_AUTH_HTTP_"
envPrefixGrpc = "MG_AUTH_GRPC_"
envPrefixDB = "MG_AUTH_DB_"
defDB = "auth"
defSvcHTTPPort = "8180"
defSvcGRPCPort = "8181"
)
type config struct {
@@ -70,6 +67,8 @@ type config struct {
SpicedbSchemaFile string `env:"MG_SPICEDB_SCHEMA_FILE" envDefault:"./docker/spicedb/schema.zed"`
SpicedbPreSharedKey string `env:"MG_SPICEDB_PRE_SHARED_KEY" envDefault:"12345678"`
TraceRatio float64 `env:"MG_JAEGER_TRACE_RATIO" envDefault:"1.0"`
KratosURL string `env:"MG_KRATOS_URL" envDefault:"http://localhost:4433"`
KratosAPIKey string `env:"MG_KRATOS_API_KEY" envDefault:""`
}
func main() {
@@ -130,15 +129,7 @@ func main() {
return
}
oauthConfig := oauth2.Config{}
if err := env.ParseWithOptions(&oauthConfig, env.Options{Prefix: envPrefixGoogle}); err != nil {
logger.Error(fmt.Sprintf("failed to load %s Google configuration : %s", svcName, err.Error()))
exitCode = 1
return
}
oauthProvider := google.NewProvider(oauthConfig, "", "")
svc := newService(db, tracer, cfg, dbConfig, logger, spicedbclient, oauthProvider)
svc := newService(db, tracer, cfg, dbConfig, logger, spicedbclient)
httpServerConfig := server.Config{Port: defSvcHTTPPort}
if err := env.ParseWithOptions(&httpServerConfig, env.Options{Prefix: envPrefixHTTP}); err != nil {
@@ -212,14 +203,14 @@ func initSchema(ctx context.Context, client *authzed.ClientWithExperimental, sch
return nil
}
func newService(db *sqlx.DB, tracer trace.Tracer, cfg config, dbConfig pgclient.Config, logger *slog.Logger, spicedbClient *authzed.ClientWithExperimental, providers ...oauth2.Provider) auth.Service {
func newService(db *sqlx.DB, tracer trace.Tracer, cfg config, dbConfig pgclient.Config, logger *slog.Logger, spicedbClient *authzed.ClientWithExperimental) auth.Service {
database := postgres.NewDatabase(db, dbConfig, tracer)
keysRepo := apostgres.New(database)
domainsRepo := apostgres.NewDomainRepository(database)
pa := spicedb.NewPolicyAgent(spicedbClient, logger)
idProvider := uuid.New()
t := jwt.New([]byte(cfg.SecretKey), providers...)
t := jwt.New([]byte(cfg.SecretKey))
svc := auth.New(keysRepo, domainsRepo, idProvider, t, pa, cfg.AccessDuration, cfg.RefreshDuration, cfg.InvitationDuration)
svc = api.LoggingMiddleware(svc, logger)
+3 -19
View File
@@ -5,7 +5,6 @@
package main
import (
"fmt"
"log"
"github.com/absmach/magistrala/cli"
@@ -14,29 +13,14 @@ import (
)
const (
defURL string = "http://localhost"
defUsersURL string = defURL + ":9002"
defThingsURL string = defURL + ":9000"
defBootstrapURL string = defURL + ":9013"
defDomainsURL string = defURL + ":8189"
defCertsURL string = defURL + ":9019"
defInvitationsURL string = defURL + ":9020"
defURL string = "http://localhost"
)
func main() {
msgContentType := string(sdk.CTJSONSenML)
sdkConf := sdk.Config{
ThingsURL: defThingsURL,
UsersURL: defUsersURL,
ReaderURL: defURL,
HTTPAdapterURL: fmt.Sprintf("%s/http", defURL),
BootstrapURL: defBootstrapURL,
CertsURL: defCertsURL,
DomainsURL: defDomainsURL,
InvitationsURL: defInvitationsURL,
MsgContentType: sdk.ContentType(msgContentType),
TLSVerification: false,
HostURL: defURL,
MsgContentType: sdk.ContentType(msgContentType),
HostURL: defURL,
}
// Root
+52 -43
View File
@@ -35,18 +35,20 @@ import (
svcerr "github.com/absmach/magistrala/pkg/errors/service"
"github.com/absmach/magistrala/pkg/groups"
"github.com/absmach/magistrala/pkg/oauth2"
googleoauth "github.com/absmach/magistrala/pkg/oauth2/google"
kratosoauth "github.com/absmach/magistrala/pkg/oauth2/kratos"
"github.com/absmach/magistrala/pkg/uuid"
"github.com/absmach/magistrala/users"
capi "github.com/absmach/magistrala/users/api"
"github.com/absmach/magistrala/users/emailer"
uevents "github.com/absmach/magistrala/users/events"
"github.com/absmach/magistrala/users/hasher"
clientspg "github.com/absmach/magistrala/users/postgres"
"github.com/absmach/magistrala/users/kratos"
ctracing "github.com/absmach/magistrala/users/tracing"
"github.com/caarlos0/env/v10"
"github.com/go-chi/chi/v5"
"github.com/hashicorp/go-retryablehttp"
"github.com/jmoiron/sqlx"
ory "github.com/ory/client-go"
"go.opentelemetry.io/otel/trace"
"golang.org/x/sync/errgroup"
)
@@ -56,27 +58,33 @@ const (
envPrefixDB = "MG_USERS_DB_"
envPrefixHTTP = "MG_USERS_HTTP_"
envPrefixAuth = "MG_AUTH_GRPC_"
envPrefixGoogle = "MG_GOOGLE_"
envPrefixKratos = "MG_KRATOS_"
defDB = "users"
defSvcHTTPPort = "9002"
defKratosRetryCount = 10
defKratosRetryWaitMax = 1 * time.Minute
streamID = "magistrala.users"
)
type config struct {
LogLevel string `env:"MG_USERS_LOG_LEVEL" envDefault:"info"`
AdminEmail string `env:"MG_USERS_ADMIN_EMAIL" envDefault:"admin@example.com"`
AdminPassword string `env:"MG_USERS_ADMIN_PASSWORD" envDefault:"12345678"`
PassRegexText string `env:"MG_USERS_PASS_REGEX" envDefault:"^.{8,}$"`
ResetURL string `env:"MG_TOKEN_RESET_ENDPOINT" envDefault:"/reset-request"`
JaegerURL url.URL `env:"MG_JAEGER_URL" envDefault:"http://localhost:14268/api/traces"`
SendTelemetry bool `env:"MG_SEND_TELEMETRY" envDefault:"true"`
InstanceID string `env:"MG_USERS_INSTANCE_ID" envDefault:""`
ESURL string `env:"MG_ES_URL" envDefault:"nats://localhost:4222"`
TraceRatio float64 `env:"MG_JAEGER_TRACE_RATIO" envDefault:"1.0"`
SelfRegister bool `env:"MG_USERS_ALLOW_SELF_REGISTER" envDefault:"false"`
OAuthUIRedirectURL string `env:"MG_OAUTH_UI_REDIRECT_URL" envDefault:"http://localhost:9095/domains"`
OAuthUIErrorURL string `env:"MG_OAUTH_UI_ERROR_URL" envDefault:"http://localhost:9095/error"`
LogLevel string `env:"MG_USERS_LOG_LEVEL" envDefault:"info"`
AdminEmail string `env:"MG_USERS_ADMIN_EMAIL" envDefault:"admin@example.com"`
AdminPassword string `env:"MG_USERS_ADMIN_PASSWORD" envDefault:"12345678"`
PassRegexText string `env:"MG_USERS_PASS_REGEX" envDefault:"^.{8,}$"`
ResetURL string `env:"MG_TOKEN_RESET_ENDPOINT" envDefault:"/reset-request"`
JaegerURL url.URL `env:"MG_JAEGER_URL" envDefault:"http://localhost:14268/api/traces"`
SendTelemetry bool `env:"MG_SEND_TELEMETRY" envDefault:"true"`
InstanceID string `env:"MG_USERS_INSTANCE_ID" envDefault:""`
ESURL string `env:"MG_ES_URL" envDefault:"nats://localhost:4222"`
TraceRatio float64 `env:"MG_JAEGER_TRACE_RATIO" envDefault:"1.0"`
SelfRegister bool `env:"MG_USERS_ALLOW_SELF_REGISTER" envDefault:"false"`
OAuthUIRedirectURL string `env:"MG_OAUTH_UI_REDIRECT_URL" envDefault:"http://localhost:9095/domains"`
OAuthUIErrorURL string `env:"MG_OAUTH_UI_ERROR_URL" envDefault:"http://localhost:9095/error"`
KratosURL string `env:"MG_KRATOS_URL" envDefault:"http://localhost:4433"`
KratosAPIKey string `env:"MG_KRATOS_API_KEY" envDefault:""`
KratosSchemaID string `env:"MG_KRATOS_SCHEMA_ID" envDefault:""`
PassRegex *regexp.Regexp
}
@@ -123,10 +131,8 @@ func main() {
exitCode = 1
return
}
cm := clientspg.Migration()
gm := gpostgres.Migration()
cm.Migrations = append(cm.Migrations, gm.Migrations...)
db, err := pgclient.Setup(dbConfig, *cm)
db, err := pgclient.Setup(dbConfig, *gm)
if err != nil {
logger.Error(err.Error())
exitCode = 1
@@ -178,15 +184,15 @@ func main() {
}
oauthConfig := oauth2.Config{}
if err := env.ParseWithOptions(&oauthConfig, env.Options{Prefix: envPrefixGoogle}); err != nil {
logger.Error(fmt.Sprintf("failed to load %s Google configuration : %s", svcName, err.Error()))
if err := env.ParseWithOptions(&oauthConfig, env.Options{Prefix: envPrefixKratos}); err != nil {
logger.Error(fmt.Sprintf("failed to load %s Kratos configuration : %s", svcName, err.Error()))
exitCode = 1
return
}
oauthProvider := googleoauth.NewProvider(oauthConfig, cfg.OAuthUIRedirectURL, cfg.OAuthUIErrorURL)
oauthProvider := kratosoauth.NewProvider(oauthConfig, cfg.KratosURL, cfg.OAuthUIRedirectURL, cfg.OAuthUIErrorURL, cfg.KratosAPIKey)
mux := chi.NewRouter()
httpSrv := httpserver.New(ctx, cancel, svcName, httpServerConfig, capi.MakeHandler(csvc, gsvc, mux, logger, cfg.InstanceID, oauthProvider), logger)
httpSrv := httpserver.New(ctx, cancel, svcName, httpServerConfig, capi.MakeHandler(csvc, gsvc, mux, logger, cfg.InstanceID, cfg.PassRegex, oauthProvider), logger)
if cfg.SendTelemetry {
chc := chclient.New(svcName, magistrala.Version, logger, cancel)
@@ -207,19 +213,32 @@ func main() {
}
func newService(ctx context.Context, authClient magistrala.AuthServiceClient, db *sqlx.DB, dbConfig pgclient.Config, tracer trace.Tracer, c config, ec email.Config, logger *slog.Logger) (users.Service, groups.Service, error) {
hsr := hasher.New()
database := postgres.NewDatabase(db, dbConfig, tracer)
cRepo := clientspg.NewRepository(database)
conf := ory.NewConfiguration()
conf.Servers = []ory.ServerConfiguration{{URL: c.KratosURL}}
conf.AddDefaultHeader("Authorization", "Bearer "+c.KratosAPIKey)
retryClient := retryablehttp.NewClient()
retryClient.Logger = logger
retryClient.RetryMax = defKratosRetryCount
retryClient.RetryWaitMax = defKratosRetryWaitMax
conf.HTTPClient = retryClient.StandardClient()
client := ory.NewAPIClient(conf)
cRepo := kratos.NewRepository(client, c.KratosSchemaID, hsr)
gRepo := gpostgres.New(database)
idp := uuid.New()
hsr := hasher.New()
emailerClient, err := emailer.New(c.ResetURL, &ec)
if err != nil {
logger.Error(fmt.Sprintf("failed to configure e-mailing util: %s", err.Error()))
}
csvc := users.NewService(cRepo, authClient, emailerClient, hsr, idp, c.PassRegex, c.SelfRegister)
csvc := users.NewService(cRepo, authClient, emailerClient, c.SelfRegister, client)
gsvc := mggroups.NewService(gRepo, idp, authClient)
csvc, err = uevents.NewEventStoreMiddleware(ctx, csvc, c.ESURL)
@@ -241,9 +260,9 @@ func newService(ctx context.Context, authClient magistrala.AuthServiceClient, db
counter, latency = internal.MakeMetrics("groups", "api")
gsvc = gapi.MetricsMiddleware(gsvc, counter, latency)
clientID, err := createAdmin(ctx, c, cRepo, hsr, csvc)
clientID, err := createAdmin(ctx, c, cRepo, csvc)
if err != nil {
logger.Error(fmt.Sprintf("failed to create admin client: %s", err))
return nil, nil, err
}
if err := createAdminPolicy(ctx, clientID, authClient); err != nil {
return nil, nil, err
@@ -251,22 +270,12 @@ func newService(ctx context.Context, authClient magistrala.AuthServiceClient, db
return csvc, gsvc, err
}
func createAdmin(ctx context.Context, c config, crepo clientspg.Repository, hsr users.Hasher, svc users.Service) (string, error) {
id, err := uuid.New().ID()
if err != nil {
return "", err
}
hash, err := hsr.Hash(c.AdminPassword)
if err != nil {
return "", err
}
func createAdmin(ctx context.Context, c config, crepo users.Repository, svc users.Service) (string, error) {
client := mgclients.Client{
ID: id,
Name: "admin",
Name: "admin-client",
Credentials: mgclients.Credentials{
Identity: c.AdminEmail,
Secret: hash,
Secret: c.AdminPassword,
},
Metadata: mgclients.Metadata{
"role": "admin",
@@ -282,10 +291,10 @@ func createAdmin(ctx context.Context, c config, crepo clientspg.Repository, hsr
}
// Create an admin
if _, err = crepo.Save(ctx, client); err != nil {
if _, err := crepo.Save(ctx, client); err != nil {
return "", err
}
if _, err = svc.IssueToken(ctx, c.AdminEmail, c.AdminPassword, ""); err != nil {
if _, err := svc.IssueToken(ctx, c.AdminEmail, c.AdminPassword, ""); err != nil {
return "", err
}
return client.ID, nil
+6 -5
View File
@@ -1,19 +1,20 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
raw_output = ""
raw_output = "false"
user_token = ""
[filter]
limit = ""
offset = ""
limit = "10"
offset = "0"
topic = ""
[remotes]
bootstrap_url = "http://localhost:9013"
certs_url = "http://localhost:9019"
http_adapter_url = "http://localhost/http"
reader_url = "http://localhost:9009"
domains_url = "http://localhost:8189"
http_adapter_url = "http://localhost:9016/http"
reader_url = "http://localhost:9011"
things_url = "http://localhost:9000"
tls_verification = false
users_url = "http://localhost:9002"
+39 -31
View File
@@ -140,6 +140,33 @@ MG_INVITATIONS_DB_SSL_KEY=
MG_INVITATIONS_DB_SSL_ROOT_CERT=
MG_INVITATIONS_INSTANCE_ID=
### UI
MG_UI_LOG_LEVEL=debug
MG_UI_PORT=9095
MG_HTTP_ADAPTER_URL=http://http-adapter:8008
MG_READER_URL=http://timescale-reader:9011
MG_THINGS_URL=http://things:9000
MG_USERS_URL=http://users:9002
MG_INVITATIONS_URL=http://invitations:9020
MG_DOMAINS_URL=http://auth:8189
MG_BOOTSTRAP_URL=http://bootstrap:9013
MG_UI_HOST_URL=http://localhost:9095
MG_UI_VERIFICATION_TLS=false
MG_UI_CONTENT_TYPE=application/senml+json
MG_UI_INSTANCE_ID=
MG_UI_DB_HOST=ui-db
MG_UI_DB_PORT=5432
MG_UI_DB_USER=magistrala
MG_UI_DB_PASS=magistrala
MG_UI_DB_NAME=ui
MG_UI_DB_SSL_MODE=disable
MG_UI_DB_SSL_CERT=
MG_UI_DB_SSL_KEY=
MG_UI_DB_SSL_ROOT_CERT=
MG_UI_HASH_KEY=5jx4x2Qg9OUmzpP5dbveWQ
MG_UI_BLOCK_KEY=UtgZjr92jwRY6SPUndHXiyl9QY8qTUyZ
MG_UI_PATH_PREFIX=/ui
### Users
MG_USERS_LOG_LEVEL=debug
MG_USERS_SECRET_KEY=HyE2D4RUt9nnKG6v8zKEqAp6g6ka8hhZsqUpzgKvnwpXrNVQSH
@@ -165,8 +192,13 @@ MG_USERS_DB_SSL_ROOT_CERT=
MG_USERS_RESET_PWD_TEMPLATE=users.tmpl
MG_USERS_INSTANCE_ID=
MG_USERS_ALLOW_SELF_REGISTER=true
MG_OAUTH_UI_REDIRECT_URL="http://localhost:9095/domains"
MG_OAUTH_UI_ERROR_URL="http://localhost:9095/error"
MG_OAUTH_UI_REDIRECT_URL=http://localhost:9095${MG_UI_PATH_PREFIX}/tokens/secure
MG_OAUTH_UI_ERROR_URL=http://localhost:9095${MG_UI_PATH_PREFIX}/error
#### Kratos
MG_KRATOS_URL=
MG_KRATOS_SCHEMA_ID=
MG_KRATOS_API_KEY=
### Email utility
MG_EMAIL_HOST=smtp.mailtrap.io
@@ -177,11 +209,11 @@ MG_EMAIL_FROM_ADDRESS=from@example.com
MG_EMAIL_FROM_NAME=Example
MG_EMAIL_TEMPLATE=email.tmpl
### Google OAuth2
MG_GOOGLE_CLIENT_ID=
MG_GOOGLE_CLIENT_SECRET=
MG_GOOGLE_REDIRECT_URL=
MG_GOOGLE_STATE=
### Kratos OAuth2
MG_KRATOS_CLIENT_ID=
MG_KRATOS_CLIENT_SECRET=
MG_KRATOS_REDIRECT_URL="http://localhost/oauth/callback/kratos"
MG_KRATOS_STATE=
### Things
MG_THINGS_LOG_LEVEL=debug
@@ -252,30 +284,6 @@ MG_WS_ADAPTER_HTTP_SERVER_CERT=
MG_WS_ADAPTER_HTTP_SERVER_KEY=
MG_WS_ADAPTER_INSTANCE_ID=
### UI
MG_UI_LOG_LEVEL=debug
MG_UI_PORT=9095
MG_HTTP_ADAPTER_URL=http://http-adapter:8008
MG_READER_URL=http://mongodb-reader:9007
MG_THINGS_URL=http://things:9000
MG_USERS_URL=http://users:9002
MG_INVITATIONS_URL=http://invitations:9020
MG_DOMAINS_URL=http://auth:8189
MG_BOOTSTRAP_URL=http://bootstrap:9013
MG_UI_HOST_URL=http://localhost:9095
MG_UI_VERIFICATION_TLS=false
MG_UI_CONTENT_TYPE=application/senml+json
MG_UI_INSTANCE_ID=
MG_UI_DB_HOST=ui-db
MG_UI_DB_PORT=5432
MG_UI_DB_USER=magistrala
MG_UI_DB_PASS=magistrala
MG_UI_DB_NAME=ui
MG_UI_DB_SSL_MODE=disable
MG_UI_DB_SSL_CERT=
MG_UI_DB_SSL_KEY=
MG_UI_DB_SSL_ROOT_CERT=
## Addons Services
### Bootstrap
MG_BOOTSTRAP_LOG_LEVEL=debug
+1 -1
View File
@@ -30,7 +30,7 @@ services:
- magistrala-bootstrap-db-volume:/var/lib/postgresql/data
bootstrap:
image: magistrala/bootstrap:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/bootstrap:${MG_RELEASE_TAG}
container_name: magistrala-bootstrap
depends_on:
- bootstrap-db
@@ -13,7 +13,7 @@ networks:
services:
cassandra-reader:
image: magistrala/cassandra-reader:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/cassandra-reader:${MG_RELEASE_TAG}
container_name: magistrala-cassandra-reader
restart: on-failure
environment:
@@ -38,7 +38,7 @@ services:
- magistrala-base-net
cassandra-writer:
image: magistrala/cassandra-writer:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/cassandra-writer:${MG_RELEASE_TAG}
container_name: magistrala-cassandra-writer
depends_on:
- cassandra
+1 -1
View File
@@ -30,7 +30,7 @@ services:
- magistrala-certs-db-volume:/var/lib/postgresql/data
certs:
image: magistrala/certs:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/certs:${MG_RELEASE_TAG}
container_name: magistrala-certs
depends_on:
- certs-db
@@ -15,7 +15,7 @@ networks:
services:
influxdb-reader:
image: magistrala/influxdb-reader:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/influxdb-reader:${MG_RELEASE_TAG}
container_name: magistrala-influxdb-reader
restart: on-failure
environment:
@@ -36,7 +36,7 @@ services:
- magistrala-influxdb-volume:/var/lib/influxdb
influxdb-writer:
image: magistrala/influxdb-writer:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/influxdb-writer:${MG_RELEASE_TAG}
container_name: magistrala-influxdb-writer
depends_on:
- influxdb
@@ -20,7 +20,7 @@ services:
- magistrala-base-net
lora-adapter:
image: magistrala/lora:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/lora:${MG_RELEASE_TAG}
container_name: magistrala-lora
restart: on-failure
environment:
@@ -14,7 +14,7 @@ networks:
services:
mongodb-reader:
image: magistrala/mongodb-reader:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/mongodb-reader:${MG_RELEASE_TAG}
container_name: magistrala-mongodb-reader
restart: on-failure
environment:
@@ -33,7 +33,7 @@ services:
- magistrala-mongodb-configdb-volume:/data/configdb
mongodb-writer:
image: magistrala/mongodb-writer:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/mongodb-writer:${MG_RELEASE_TAG}
container_name: magistrala-mongodb-writer
depends_on:
- mongodb
@@ -26,7 +26,7 @@ services:
- magistrala-opcua-redis-volume:/data
opcua-adapter:
image: magistrala/opcua:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/opcua:${MG_RELEASE_TAG}
container_name: magistrala-opcua
restart: on-failure
environment:
@@ -14,7 +14,7 @@ networks:
services:
postgres-reader:
image: magistrala/postgres-reader:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/postgres-reader:${MG_RELEASE_TAG}
container_name: magistrala-postgres-reader
restart: on-failure
environment:
@@ -31,7 +31,7 @@ services:
- magistrala-postgres-writer-volume:/var/lib/postgresql/data
postgres-writer:
image: magistrala/postgres-writer:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/postgres-writer:${MG_RELEASE_TAG}
container_name: magistrala-postgres-writer
depends_on:
- postgres
+1 -1
View File
@@ -13,7 +13,7 @@ networks:
services:
provision:
image: magistrala/provision:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/provision:${MG_RELEASE_TAG}
container_name: magistrala-provision
restart: on-failure
networks:
@@ -29,7 +29,7 @@ services:
- magistrala-smpp-notifier-volume:/var/lib/postgresql/datab
smpp-notifier:
image: magistrala/smpp-notifier:latest
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/smpp-notifier:latest
container_name: magistrala-smpp-notifier
depends_on:
- smpp-notifier-db
@@ -29,7 +29,7 @@ services:
- magistrala-smtp-notifier-volume:/var/lib/postgresql/datab
smtp-notifier:
image: magistrala/smtp-notifier:latest
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/smtp-notifier:latest
container_name: magistrala-smtp-notifier
depends_on:
- smtp-notifier-db
@@ -14,7 +14,7 @@ networks:
services:
timescale-reader:
image: magistrala/timescale-reader:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/timescale-reader:${MG_RELEASE_TAG}
container_name: magistrala-timescale-reader
restart: on-failure
environment:
@@ -33,7 +33,7 @@ services:
- magistrala-timescale-writer-volume:/var/lib/timescalesql/data
timescale-writer:
image: magistrala/timescale-writer:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/timescale-writer:${MG_RELEASE_TAG}
container_name: magistrala-timescale-writer
depends_on:
- timescale
+1 -1
View File
@@ -39,7 +39,7 @@ services:
- magistrala-twins-db-configdb-volume:/data/configdb
twins:
image: magistrala/twins:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/twins:${MG_RELEASE_TAG}
container_name: magistrala-twins
restart: on-failure
environment:
+25 -22
View File
@@ -81,7 +81,7 @@ services:
- magistrala-auth-db-volume:/var/lib/postgresql/data
auth:
image: magistrala/auth:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/auth:${MG_RELEASE_TAG}
container_name: magistrala-auth
depends_on:
- auth-db
@@ -125,10 +125,6 @@ services:
MG_JAEGER_TRACE_RATIO: ${MG_JAEGER_TRACE_RATIO}
MG_SEND_TELEMETRY: ${MG_SEND_TELEMETRY}
MG_AUTH_ADAPTER_INSTANCE_ID: ${MG_AUTH_ADAPTER_INSTANCE_ID}
MG_GOOGLE_CLIENT_ID: ${MG_GOOGLE_CLIENT_ID}
MG_GOOGLE_CLIENT_SECRET: ${MG_GOOGLE_CLIENT_SECRET}
MG_GOOGLE_REDIRECT_URL: ${MG_GOOGLE_REDIRECT_URL}
MG_GOOGLE_STATE: ${MG_GOOGLE_STATE}
ports:
- ${MG_AUTH_HTTP_PORT}:${MG_AUTH_HTTP_PORT}
- ${MG_AUTH_GRPC_PORT}:${MG_AUTH_GRPC_PORT}
@@ -176,7 +172,7 @@ services:
- magistrala-invitations-db-volume:/var/lib/postgresql/data
invitations:
image: magistrala/invitations:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/invitations:${MG_RELEASE_TAG}
container_name: magistrala-invitations
restart: on-failure
depends_on:
@@ -294,7 +290,7 @@ services:
- magistrala-things-redis-volume:/data
things:
image: magistrala/things:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/things:${MG_RELEASE_TAG}
container_name: magistrala-things
depends_on:
- things-db
@@ -399,7 +395,7 @@ services:
- magistrala-users-db-volume:/var/lib/postgresql/data
users:
image: magistrala/users:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/users:${MG_RELEASE_TAG}
container_name: magistrala-users
depends_on:
- users-db
@@ -445,12 +441,15 @@ services:
MG_AUTH_GRPC_CLIENT_CERT: ${MG_AUTH_GRPC_CLIENT_CERT:+/auth-grpc-client.crt}
MG_AUTH_GRPC_CLIENT_KEY: ${MG_AUTH_GRPC_CLIENT_KEY:+/auth-grpc-client.key}
MG_AUTH_GRPC_SERVER_CA_CERTS: ${MG_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt}
MG_GOOGLE_CLIENT_ID: ${MG_GOOGLE_CLIENT_ID}
MG_GOOGLE_CLIENT_SECRET: ${MG_GOOGLE_CLIENT_SECRET}
MG_GOOGLE_REDIRECT_URL: ${MG_GOOGLE_REDIRECT_URL}
MG_GOOGLE_STATE: ${MG_GOOGLE_STATE}
MG_KRATOS_CLIENT_ID: ${MG_KRATOS_CLIENT_ID}
MG_KRATOS_CLIENT_SECRET: ${MG_KRATOS_CLIENT_SECRET}
MG_KRATOS_REDIRECT_URL: ${MG_KRATOS_REDIRECT_URL}
MG_KRATOS_STATE: ${MG_KRATOS_STATE}
MG_OAUTH_UI_REDIRECT_URL: ${MG_OAUTH_UI_REDIRECT_URL}
MG_OAUTH_UI_ERROR_URL: ${MG_OAUTH_UI_ERROR_URL}
MG_KRATOS_URL: ${MG_KRATOS_URL}
MG_KRATOS_SCHEMA_ID: ${MG_KRATOS_SCHEMA_ID}
MG_KRATOS_API_KEY: ${MG_KRATOS_API_KEY}
ports:
- ${MG_USERS_HTTP_PORT}:${MG_USERS_HTTP_PORT}
networks:
@@ -487,7 +486,7 @@ services:
- magistrala-base-net
mqtt-adapter:
image: magistrala/mqtt:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/mqtt:${MG_RELEASE_TAG}
container_name: magistrala-mqtt
depends_on:
- things
@@ -539,7 +538,7 @@ services:
create_host_path: true
http-adapter:
image: magistrala/http:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/http:${MG_RELEASE_TAG}
container_name: magistrala-http
depends_on:
- things
@@ -584,7 +583,7 @@ services:
create_host_path: true
coap-adapter:
image: magistrala/coap:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/coap:${MG_RELEASE_TAG}
container_name: magistrala-coap
depends_on:
- things
@@ -634,7 +633,7 @@ services:
create_host_path: true
ws-adapter:
image: magistrala/ws:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/ws:${MG_RELEASE_TAG}
container_name: magistrala-ws
depends_on:
- things
@@ -679,7 +678,7 @@ services:
create_host_path: true
vernemq:
image: magistrala/vernemq:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/vernemq:${MG_RELEASE_TAG}
container_name: magistrala-vernemq
restart: on-failure
environment:
@@ -709,7 +708,7 @@ services:
- magistrala-base-net
ui:
image: magistrala/ui:${MG_RELEASE_TAG}
image: registry.gitlab.com/daveembeddedsystems/innovation-lab/tlm/tlml/abstract-machines/magistrala/ui:${MG_RELEASE_TAG}
container_name: magistrala-ui
restart: on-failure
environment:
@@ -735,10 +734,14 @@ services:
MG_UI_DB_SSL_CERT: ${MG_UI_DB_SSL_CERT}
MG_UI_DB_SSL_KEY: ${MG_UI_DB_SSL_KEY}
MG_UI_DB_SSL_ROOT_CERT: ${MG_UI_DB_SSL_ROOT_CERT}
MG_GOOGLE_CLIENT_ID: ${MG_GOOGLE_CLIENT_ID}
MG_GOOGLE_CLIENT_SECRET: ${MG_GOOGLE_CLIENT_SECRET}
MG_GOOGLE_REDIRECT_URL: ${MG_GOOGLE_REDIRECT_URL}
MG_GOOGLE_STATE: ${MG_GOOGLE_STATE}
MG_KRATOS_CLIENT_ID: ${MG_KRATOS_CLIENT_ID}
MG_KRATOS_CLIENT_SECRET: ${MG_KRATOS_CLIENT_SECRET}
MG_KRATOS_REDIRECT_URL: ${MG_KRATOS_REDIRECT_URL}
MG_KRATOS_STATE: ${MG_KRATOS_STATE}
MG_KRATOS_URL: ${MG_KRATOS_URL}
MG_UI_HASH_KEY: ${MG_UI_HASH_KEY}
MG_UI_BLOCK_KEY: ${MG_UI_BLOCK_KEY}
MG_UI_PATH_PREFIX: ${MG_UI_PATH_PREFIX}
ports:
- ${MG_UI_PORT}:${MG_UI_PORT}
networks:
+11 -10
View File
@@ -25,6 +25,7 @@ require (
github.com/gookit/color v1.5.4
github.com/gopcua/opcua v0.1.6
github.com/gorilla/websocket v1.5.1
github.com/hashicorp/go-retryablehttp v0.7.5
github.com/hashicorp/vault/api v1.12.0
github.com/hashicorp/vault/api/auth/approle v0.6.0
github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f
@@ -32,12 +33,13 @@ require (
github.com/ivanpirog/coloredcobra v1.0.1
github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa
github.com/jackc/pgtype v1.14.1
github.com/jackc/pgx/v5 v5.5.2
github.com/jackc/pgx/v5 v5.5.4
github.com/jmoiron/sqlx v1.3.5
github.com/lestrrat-go/jwx/v2 v2.0.19
github.com/lestrrat-go/jwx/v2 v2.0.21
github.com/mitchellh/mapstructure v1.5.0
github.com/nats-io/nats.go v1.32.0
github.com/oklog/ulid/v2 v2.1.0
github.com/ory/client-go v1.5.1
github.com/ory/dockertest/v3 v3.10.0
github.com/pelletier/go-toml v1.9.5
github.com/plgd-dev/go-coap/v2 v2.6.0
@@ -46,7 +48,7 @@ require (
github.com/rubenv/sql-migrate v1.6.1
github.com/spf13/cobra v1.8.0
github.com/spf13/viper v1.18.2
github.com/stretchr/testify v1.8.4
github.com/stretchr/testify v1.9.0
go.mongodb.org/mongo-driver v1.13.1
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0
@@ -55,14 +57,14 @@ require (
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0
go.opentelemetry.io/otel/sdk v1.22.0
go.opentelemetry.io/otel/trace v1.22.0
golang.org/x/crypto v0.19.0
golang.org/x/crypto v0.21.0
golang.org/x/net v0.21.0
golang.org/x/oauth2 v0.17.0
golang.org/x/sync v0.6.0
gonum.org/v1/gonum v0.14.0
google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac
google.golang.org/grpc v1.60.1
google.golang.org/protobuf v1.32.0
google.golang.org/protobuf v1.33.0
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
)
@@ -91,7 +93,7 @@ require (
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/fxamacker/cbor/v2 v2.5.0 // indirect
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
github.com/go-jose/go-jose/v3 v3.0.1 // indirect
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
@@ -108,7 +110,6 @@ require (
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.5 // indirect
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8 // indirect
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect
@@ -125,7 +126,7 @@ require (
github.com/klauspost/compress v1.17.4 // indirect
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/httprc v1.0.4 // indirect
github.com/lestrrat-go/httprc v1.0.5 // indirect
github.com/lestrrat-go/iter v1.0.2 // indirect
github.com/lestrrat-go/option v1.0.1 // indirect
github.com/lib/pq v1.10.9 // indirect
@@ -161,7 +162,7 @@ require (
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.1 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
@@ -178,7 +179,7 @@ require (
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.17.0 // indirect
+22 -15
View File
@@ -119,8 +119,9 @@ github.com/go-chi/chi/v5 v5.0.11 h1:BnpYbFZ3T3S1WMpD79r7R5ThWX40TaFB7L31Y8xqSwA=
github.com/go-chi/chi/v5 v5.0.11/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs=
github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw=
github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA=
github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k=
github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU=
github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg=
@@ -184,6 +185,7 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
@@ -297,8 +299,8 @@ github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c h1:Dznn52SgVIVst9UyOT9brctYUgxs+CvVfPaC3jKrA50=
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
github.com/jackc/pgx/v5 v5.5.2 h1:iLlpgp4Cp/gC9Xuscl7lFL1PhhW+ZLtXZcrfCt4C3tA=
github.com/jackc/pgx/v5 v5.5.2/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/pgx/v5 v5.5.4 h1:Xp2aQS8uXButQdnCMWNmvx6UysWQQC+u1EoizjguY+8=
github.com/jackc/pgx/v5 v5.5.4/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
@@ -334,14 +336,14 @@ github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N
github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
github.com/lestrrat-go/httprc v1.0.4 h1:bAZymwoZQb+Oq8MEbyipag7iSq6YIga8Wj6GOiJGdI8=
github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
github.com/lestrrat-go/httprc v1.0.5 h1:bsTfiH8xaKOJPrg1R+E3iE/AWZr/x0Phj9PBTG/OLUk=
github.com/lestrrat-go/httprc v1.0.5/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
github.com/lestrrat-go/iter v0.0.0-20200422075355-fc1769541911/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc=
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
github.com/lestrrat-go/jwx v1.0.2/go.mod h1:TPF17WiSFegZo+c20fdpw49QD+/7n4/IsGvEmCSWwT0=
github.com/lestrrat-go/jwx/v2 v2.0.19 h1:ekv1qEZE6BVct89QA+pRF6+4pCpfVrOnEJnTnT4RXoY=
github.com/lestrrat-go/jwx/v2 v2.0.19/go.mod h1:l3im3coce1lL2cDeAjqmaR+Awx+X8Ih+2k8BuHNJ4CU=
github.com/lestrrat-go/jwx/v2 v2.0.21 h1:jAPKupy4uHgrHFEdjVjNkUgoBKtVDgrQPB/h55FHrR0=
github.com/lestrrat-go/jwx/v2 v2.0.21/go.mod h1:09mLW8zto6bWL9GbwnqAli+ArLf+5M33QLQPDggkUWM=
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/lestrrat-go/pdebug v0.0.0-20200204225717-4d6bd78da58d/go.mod h1:B06CSso/AWxiPejj+fheUINGeBKeeEZNt8w+EoU7+L8=
@@ -409,6 +411,8 @@ github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zM
github.com/opencontainers/runc v1.1.12 h1:BOIssBaW1La0/qbNZHXOOa71dZfZEQOzW7dqQf3phss=
github.com/opencontainers/runc v1.1.12/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/ory/client-go v1.5.1 h1:lVi1f8j994uXMbi2+YahdtJw4+WZEalDXiRJbSQBYhU=
github.com/ory/client-go v1.5.1/go.mod h1:6dx0Ir6q8O9mUvl3sqrlyR+0LalXLwwKedVDDmSPNQs=
github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4=
github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg=
github.com/panjf2000/ants/v2 v2.4.3/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A=
@@ -506,8 +510,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0=
github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -516,10 +520,10 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
@@ -615,8 +619,9 @@ golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA=
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
@@ -709,8 +714,9 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -720,6 +726,7 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -797,8 +804,8 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+7 -3
View File
@@ -106,8 +106,7 @@ func EncodeError(_ context.Context, err error, w http.ResponseWriter) {
w.Header().Set("Content-Type", ContentType)
switch {
case errors.Contains(err, apiutil.ErrInvalidSecret),
errors.Contains(err, svcerr.ErrMalformedEntity),
case errors.Contains(err, svcerr.ErrMalformedEntity),
errors.Contains(err, errors.ErrMalformedEntity),
errors.Contains(err, apiutil.ErrMissingID),
errors.Contains(err, apiutil.ErrEmptyList),
@@ -121,7 +120,12 @@ func EncodeError(_ context.Context, err error, w http.ResponseWriter) {
errors.Contains(err, apiutil.ErrInvalidQueryParams),
errors.Contains(err, apiutil.ErrInvalidStatus),
errors.Contains(err, apiutil.ErrMissingRelation),
errors.Contains(err, apiutil.ErrValidation):
errors.Contains(err, apiutil.ErrValidation),
errors.Contains(err, apiutil.ErrMissingIdentity),
errors.Contains(err, apiutil.ErrMissingSecret),
errors.Contains(err, apiutil.ErrMissingPass),
errors.Contains(err, apiutil.ErrMissingConfPass),
errors.Contains(err, apiutil.ErrPasswordFormat):
w.WriteHeader(http.StatusBadRequest)
case errors.Contains(err, svcerr.ErrAuthentication),
errors.Contains(err, apiutil.ErrBearerToken):
+2 -2
View File
@@ -225,7 +225,7 @@ func TestEncodeError(t *testing.T) {
{
desc: "BadRequest",
errs: []error{
apiutil.ErrInvalidSecret,
apiutil.ErrMissingSecret,
svcerr.ErrMalformedEntity,
errors.ErrMalformedEntity,
apiutil.ErrMissingID,
@@ -240,7 +240,7 @@ func TestEncodeError(t *testing.T) {
{
desc: "BadRequest with validation error",
errs: []error{
errors.Wrap(apiutil.ErrValidation, apiutil.ErrInvalidSecret),
errors.Wrap(apiutil.ErrValidation, apiutil.ErrMissingSecret),
errors.Wrap(apiutil.ErrValidation, svcerr.ErrMalformedEntity),
errors.Wrap(apiutil.ErrValidation, errors.ErrMalformedEntity),
errors.Wrap(apiutil.ErrValidation, apiutil.ErrMissingID),
+15 -3
View File
@@ -132,6 +132,9 @@ var (
// ErrMissingSecret indicates missing secret.
ErrMissingSecret = errors.New("missing secret")
// ErrPasswordFormat indicates weak password.
ErrPasswordFormat = errors.New("password does not meet the requirements")
// ErrMissingOwner indicates missing entity owner.
ErrMissingOwner = errors.New("missing entity owner")
@@ -144,9 +147,6 @@ var (
// ErrMissingName indicates missing identity name.
ErrMissingName = errors.New("missing identity name")
// ErrInvalidSecret indicates invalid secret.
ErrInvalidSecret = errors.New("missing secret")
// ErrInvalidLevel indicates an invalid group level.
ErrInvalidLevel = errors.New("invalid group level (should be between 0 and 5)")
@@ -164,4 +164,16 @@ var (
// ErrRollbackTx indicates failed to rollback transaction.
ErrRollbackTx = errors.New("failed to rollback transaction")
// ErrInvalidAggregation indicates invalid aggregation value.
ErrInvalidAggregation = errors.New("invalid aggregation value")
// ErrInvalidInterval indicates invalid interval value.
ErrInvalidInterval = errors.New("invalid interval value")
// ErrMissingFrom indicates missing from value.
ErrMissingFrom = errors.New("missing from time value")
// ErrMissingTo indicates missing to value.
ErrMissingTo = errors.New("missing to time value")
)
+2 -2
View File
@@ -13,7 +13,7 @@ import (
pgClient "github.com/absmach/magistrala/internal/clients/postgres"
"github.com/absmach/magistrala/internal/postgres"
upostgres "github.com/absmach/magistrala/users/postgres"
tpostgres "github.com/absmach/magistrala/things/postgres"
"github.com/jmoiron/sqlx"
dockertest "github.com/ory/dockertest/v3"
"github.com/ory/dockertest/v3/docker"
@@ -76,7 +76,7 @@ func TestMain(m *testing.M) {
SSLRootCert: "",
}
if db, err = pgClient.Setup(dbConfig, *upostgres.Migration()); err != nil {
if db, err = pgClient.Setup(dbConfig, *tpostgres.Migration()); err != nil {
log.Fatalf("Could not setup test DB connection: %s", err)
}
+12
View File
@@ -9,6 +9,7 @@ import (
"strings"
"github.com/absmach/magistrala/internal/apiutil"
ory "github.com/ory/client-go"
)
// Status represents Client status.
@@ -89,3 +90,14 @@ func (s *Status) UnmarshalJSON(data []byte) error {
*s = val
return err
}
func ToOryState(status Status) ory.IdentityState {
switch status {
case EnabledStatus:
return ory.IDENTITYSTATE_ACTIVE
case DisabledStatus:
return ory.IDENTITYSTATE_INACTIVE
default: // AllStatus
return ory.IDENTITYSTATE_ACTIVE
}
}
+13 -65
View File
@@ -6,11 +6,9 @@ package google
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"strings"
"time"
mfclients "github.com/absmach/magistrala/pkg/clients"
@@ -77,28 +75,29 @@ func (cfg *config) IsEnabled() bool {
return cfg.config.ClientID != "" && cfg.config.ClientSecret != ""
}
func (cfg *config) UserDetails(ctx context.Context, code string) (mfclients.Client, oauth2.Token, error) {
func (cfg *config) Exchange(ctx context.Context, code string) (oauth2.Token, error) {
token, err := cfg.config.Exchange(ctx, code)
if err != nil {
return mfclients.Client{}, oauth2.Token{}, err
}
if token.RefreshToken == "" {
return mfclients.Client{}, oauth2.Token{}, svcerr.ErrAuthentication
return oauth2.Token{}, err
}
resp, err := http.Get(userInfoURL + url.QueryEscape(token.AccessToken))
return *token, nil
}
func (cfg *config) UserInfo(accessToken string) (mfclients.Client, error) {
resp, err := http.Get(userInfoURL + url.QueryEscape(accessToken))
if err != nil {
return mfclients.Client{}, oauth2.Token{}, err
return mfclients.Client{}, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return mfclients.Client{}, oauth2.Token{}, svcerr.ErrAuthentication
return mfclients.Client{}, svcerr.ErrAuthentication
}
data, err := io.ReadAll(resp.Body)
if err != nil {
return mfclients.Client{}, oauth2.Token{}, err
return mfclients.Client{}, err
}
var user struct {
@@ -108,11 +107,11 @@ func (cfg *config) UserDetails(ctx context.Context, code string) (mfclients.Clie
Picture string `json:"picture"`
}
if err := json.Unmarshal(data, &user); err != nil {
return mfclients.Client{}, oauth2.Token{}, err
return mfclients.Client{}, err
}
if user.ID == "" || user.Name == "" || user.Email == "" {
return mfclients.Client{}, oauth2.Token{}, svcerr.ErrAuthentication
return mfclients.Client{}, svcerr.ErrAuthentication
}
client := mfclients.Client{
@@ -128,56 +127,5 @@ func (cfg *config) UserDetails(ctx context.Context, code string) (mfclients.Clie
Status: mfclients.EnabledStatus,
}
return client, *token, nil
}
func (cfg *config) Validate(ctx context.Context, token string) error {
client := &http.Client{
Timeout: defTimeout,
}
req, err := http.NewRequest(http.MethodGet, tokenInfoURL+token, http.NoBody)
if err != nil {
return svcerr.ErrAuthentication
}
res, err := client.Do(req)
if err != nil {
return svcerr.ErrAuthentication
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return svcerr.ErrAuthentication
}
return nil
}
func (cfg *config) Refresh(ctx context.Context, token string) (oauth2.Token, error) {
payload := strings.NewReader(fmt.Sprintf("grant_type=refresh_token&refresh_token=%s&client_id=%s&client_secret=%s", token, cfg.config.ClientID, cfg.config.ClientSecret))
client := &http.Client{
Timeout: defTimeout,
}
req, err := http.NewRequest(http.MethodPost, cfg.config.Endpoint.TokenURL, payload)
if err != nil {
return oauth2.Token{}, err
}
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
res, err := client.Do(req)
if err != nil {
return oauth2.Token{}, err
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
return oauth2.Token{}, err
}
var tokenData oauth2.Token
if err := json.Unmarshal(body, &tokenData); err != nil {
return oauth2.Token{}, err
}
tokenData.RefreshToken = token
return tokenData, nil
return client, nil
}
+6
View File
@@ -0,0 +1,6 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
// Package kratos contains the domain concept definitions needed to support
// Magistrala services for kratos OAuth2 functionality.
package kratos
+143
View File
@@ -0,0 +1,143 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package kratos
import (
"context"
"encoding/json"
"io"
"net/http"
"net/url"
"time"
mfclients "github.com/absmach/magistrala/pkg/clients"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
mgoauth2 "github.com/absmach/magistrala/pkg/oauth2"
ory "github.com/ory/client-go"
"golang.org/x/oauth2"
)
const (
providerName = "kratos"
defTimeout = 1 * time.Minute
userInfoEndpoint = "/userinfo?access_token="
authEndpoint = "/oauth2/auth"
TokenEndpoint = "/oauth2/token"
)
var scopes = []string{
"email",
"profile",
"offline_access",
}
var _ mgoauth2.Provider = (*config)(nil)
type config struct {
config *oauth2.Config
client *ory.APIClient
state string
baseURL string
uiRedirectURL string
errorURL string
}
// NewProvider returns a new Google OAuth provider.
func NewProvider(cfg mgoauth2.Config, baseURL, uiRedirectURL, errorURL, apiKey string) mgoauth2.Provider {
conf := ory.NewConfiguration()
conf.Servers = []ory.ServerConfiguration{{URL: baseURL}}
conf.AddDefaultHeader("Authorization", "Bearer "+apiKey)
client := ory.NewAPIClient(conf)
return &config{
config: &oauth2.Config{
ClientID: cfg.ClientID,
ClientSecret: cfg.ClientSecret,
Endpoint: oauth2.Endpoint{
AuthURL: baseURL + authEndpoint,
TokenURL: baseURL + TokenEndpoint,
},
RedirectURL: cfg.RedirectURL,
Scopes: scopes,
},
client: client,
baseURL: baseURL,
state: cfg.State,
uiRedirectURL: uiRedirectURL,
errorURL: errorURL,
}
}
func (cfg *config) Name() string {
return providerName
}
func (cfg *config) State() string {
return cfg.state
}
func (cfg *config) RedirectURL() string {
return cfg.uiRedirectURL
}
func (cfg *config) ErrorURL() string {
return cfg.errorURL
}
func (cfg *config) IsEnabled() bool {
return cfg.config.ClientID != "" && cfg.config.ClientSecret != ""
}
func (cfg *config) Exchange(ctx context.Context, code string) (oauth2.Token, error) {
token, err := cfg.config.Exchange(ctx, code)
if err != nil {
return oauth2.Token{}, err
}
return *token, nil
}
func (cfg *config) UserInfo(token string) (mfclients.Client, error) {
resp, err := http.Get(cfg.baseURL + userInfoEndpoint + url.QueryEscape(token))
if err != nil {
return mfclients.Client{}, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return mfclients.Client{}, svcerr.ErrAuthentication
}
data, err := io.ReadAll(resp.Body)
if err != nil {
return mfclients.Client{}, err
}
var user struct {
ID string `json:"sub"`
Name string `json:"preferred_username"`
Email string `json:"email"`
}
if err := json.Unmarshal(data, &user); err != nil {
return mfclients.Client{}, err
}
if user.ID == "" || user.Name == "" || user.Email == "" {
return mfclients.Client{}, svcerr.ErrAuthentication
}
client := mfclients.Client{
ID: user.ID,
Name: user.Name,
Credentials: mfclients.Credentials{
Identity: user.Email,
},
Metadata: map[string]interface{}{
"oauth_provider": providerName,
},
Status: mfclients.EnabledStatus,
}
return client, nil
}
+41 -66
View File
@@ -37,6 +37,34 @@ func (_m *Provider) ErrorURL() string {
return r0
}
// Exchange provides a mock function with given fields: ctx, code
func (_m *Provider) Exchange(ctx context.Context, code string) (xoauth2.Token, error) {
ret := _m.Called(ctx, code)
if len(ret) == 0 {
panic("no return value specified for Exchange")
}
var r0 xoauth2.Token
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (xoauth2.Token, error)); ok {
return rf(ctx, code)
}
if rf, ok := ret.Get(0).(func(context.Context, string) xoauth2.Token); ok {
r0 = rf(ctx, code)
} else {
r0 = ret.Get(0).(xoauth2.Token)
}
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, code)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// IsEnabled provides a mock function with given fields:
func (_m *Provider) IsEnabled() bool {
ret := _m.Called()
@@ -91,34 +119,6 @@ func (_m *Provider) RedirectURL() string {
return r0
}
// Refresh provides a mock function with given fields: ctx, token
func (_m *Provider) Refresh(ctx context.Context, token string) (xoauth2.Token, error) {
ret := _m.Called(ctx, token)
if len(ret) == 0 {
panic("no return value specified for Refresh")
}
var r0 xoauth2.Token
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (xoauth2.Token, error)); ok {
return rf(ctx, token)
}
if rf, ok := ret.Get(0).(func(context.Context, string) xoauth2.Token); ok {
r0 = rf(ctx, token)
} else {
r0 = ret.Get(0).(xoauth2.Token)
}
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, token)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// State provides a mock function with given fields:
func (_m *Provider) State() string {
ret := _m.Called()
@@ -137,57 +137,32 @@ func (_m *Provider) State() string {
return r0
}
// UserDetails provides a mock function with given fields: ctx, code
func (_m *Provider) UserDetails(ctx context.Context, code string) (clients.Client, xoauth2.Token, error) {
ret := _m.Called(ctx, code)
// UserInfo provides a mock function with given fields: accessToken
func (_m *Provider) UserInfo(accessToken string) (clients.Client, error) {
ret := _m.Called(accessToken)
if len(ret) == 0 {
panic("no return value specified for UserDetails")
panic("no return value specified for UserInfo")
}
var r0 clients.Client
var r1 xoauth2.Token
var r2 error
if rf, ok := ret.Get(0).(func(context.Context, string) (clients.Client, xoauth2.Token, error)); ok {
return rf(ctx, code)
var r1 error
if rf, ok := ret.Get(0).(func(string) (clients.Client, error)); ok {
return rf(accessToken)
}
if rf, ok := ret.Get(0).(func(context.Context, string) clients.Client); ok {
r0 = rf(ctx, code)
if rf, ok := ret.Get(0).(func(string) clients.Client); ok {
r0 = rf(accessToken)
} else {
r0 = ret.Get(0).(clients.Client)
}
if rf, ok := ret.Get(1).(func(context.Context, string) xoauth2.Token); ok {
r1 = rf(ctx, code)
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(accessToken)
} else {
r1 = ret.Get(1).(xoauth2.Token)
r1 = ret.Error(1)
}
if rf, ok := ret.Get(2).(func(context.Context, string) error); ok {
r2 = rf(ctx, code)
} else {
r2 = ret.Error(2)
}
return r0, r1, r2
}
// Validate provides a mock function with given fields: ctx, token
func (_m *Provider) Validate(ctx context.Context, token string) error {
ret := _m.Called(ctx, token)
if len(ret) == 0 {
panic("no return value specified for Validate")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
r0 = rf(ctx, token)
} else {
r0 = ret.Error(0)
}
return r0
return r0, r1
}
// NewProvider creates a new instance of Provider. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+4 -7
View File
@@ -72,12 +72,9 @@ type Provider interface {
// IsEnabled checks if the OAuth2 provider is enabled.
IsEnabled() bool
// UserDetails retrieves the user's details and OAuth tokens from the OAuth2 provider.
UserDetails(ctx context.Context, code string) (mfclients.Client, oauth2.Token, error)
// Exchange converts an authorization code into a token.
Exchange(ctx context.Context, code string) (oauth2.Token, error)
// Validate checks the validity of the access token.
Validate(ctx context.Context, token string) error
// Refresh refreshes the access token using the refresh token.
Refresh(ctx context.Context, token string) (oauth2.Token, error)
// UserInfo retrieves the user's information using the access token.
UserInfo(accessToken string) (mfclients.Client, error)
}
+2 -2
View File
@@ -37,14 +37,14 @@ func setupGroups() (*httptest.Server, *mocks.Repository, *authmocks.AuthClient)
grepo := new(mocks.Repository)
auth := new(authmocks.AuthClient)
csvc := users.NewService(crepo, auth, emailer, phasher, idProvider, passRegex, true)
csvc := users.NewService(crepo, auth, emailer, true, nil)
gsvc := groups.NewService(grepo, idProvider, auth)
logger := mglog.NewMock()
mux := chi.NewRouter()
provider := new(oauth2mocks.Provider)
provider.On("Name").Return("test")
api.MakeHandler(csvc, gsvc, mux, logger, "", provider)
api.MakeHandler(csvc, gsvc, mux, logger, "", passRegex, provider)
return httptest.NewServer(mux), grepo, auth
}
+38 -5
View File
@@ -7,6 +7,8 @@ import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"strconv"
"strings"
"github.com/absmach/magistrala/internal/apiutil"
@@ -23,14 +25,14 @@ func (sdk mgSDK) SendMessage(chanName, msg, key string) errors.SDKError {
subtopicPart = fmt.Sprintf("/%s", strings.ReplaceAll(chanNameParts[1], ".", "/"))
}
url := fmt.Sprintf("%s/channels/%s/messages%s", sdk.httpAdapterURL, chanID, subtopicPart)
reqURL := fmt.Sprintf("%s/channels/%s/messages%s", sdk.httpAdapterURL, chanID, subtopicPart)
_, _, err := sdk.processRequest(http.MethodPost, url, ThingPrefix+key, []byte(msg), nil, http.StatusAccepted)
_, _, err := sdk.processRequest(http.MethodPost, reqURL, ThingPrefix+key, []byte(msg), nil, http.StatusAccepted)
return err
}
func (sdk mgSDK) ReadMessages(pm PageMetadata, chanName, token string) (MessagesPage, errors.SDKError) {
func (sdk mgSDK) ReadMessages(pm MessagePageMetadata, chanName, token string) (MessagesPage, errors.SDKError) {
chanNameParts := strings.SplitN(chanName, ".", channelParts)
chanID := chanNameParts[0]
subtopicPart := ""
@@ -39,7 +41,7 @@ func (sdk mgSDK) ReadMessages(pm PageMetadata, chanName, token string) (Messages
}
readMessagesEndpoint := fmt.Sprintf("channels/%s/messages%s", chanID, subtopicPart)
url, err := sdk.withQueryParams(sdk.readerURL, readMessagesEndpoint, pm)
msgURL, err := sdk.withMessageQueryParams(sdk.readerURL, readMessagesEndpoint, pm)
if err != nil {
return MessagesPage{}, errors.NewSDKError(err)
}
@@ -47,7 +49,7 @@ func (sdk mgSDK) ReadMessages(pm PageMetadata, chanName, token string) (Messages
header := make(map[string]string)
header["Content-Type"] = string(sdk.msgContentType)
_, body, sdkerr := sdk.processRequest(http.MethodGet, url, token, nil, header, http.StatusOK)
_, body, sdkerr := sdk.processRequest(http.MethodGet, msgURL, token, nil, header, http.StatusOK)
if sdkerr != nil {
return MessagesPage{}, sdkerr
}
@@ -69,3 +71,34 @@ func (sdk *mgSDK) SetContentType(ct ContentType) errors.SDKError {
return nil
}
func (sdk mgSDK) withMessageQueryParams(baseURL, endpoint string, mpm MessagePageMetadata) (string, error) {
b, err := json.Marshal(mpm)
if err != nil {
return "", err
}
q := map[string]interface{}{}
if err := json.Unmarshal(b, &q); err != nil {
return "", err
}
ret := url.Values{}
for k, v := range q {
switch t := v.(type) {
case string:
ret.Add(k, t)
case float64:
ret.Add(k, strconv.FormatFloat(t, 'f', -1, 64))
case uint64:
ret.Add(k, strconv.FormatUint(t, 10))
case int64:
ret.Add(k, strconv.FormatInt(t, 10))
case json.Number:
ret.Add(k, t.String())
case bool:
ret.Add(k, strconv.FormatBool(t))
}
}
qs := ret.Encode()
return fmt.Sprintf("%s/%s?%s", baseURL, endpoint, qs), nil
}
+18 -2
View File
@@ -69,6 +69,22 @@ var (
ErrInvalidJWT = errors.New("invalid JWT")
)
type MessagePageMetadata struct {
PageMetadata
Subtopic string `json:"subtopic,omitempty"`
Publisher string `json:"publisher,omitempty"`
Comparator string `json:"comparator,omitempty"`
BoolValue *bool `json:"vb,omitempty"`
StringValue string `json:"vs,omitempty"`
DataValue string `json:"vd,omitempty"`
From float64 `json:"from,omitempty"`
To float64 `json:"to,omitempty"`
Aggregation string `json:"aggregation,omitempty"`
Interval string `json:"interval,omitempty"`
Value float64 `json:"value,omitempty"`
Protocol string `json:"protocol,omitempty"`
}
type PageMetadata struct {
Total uint64 `json:"total"`
Offset uint64 `json:"offset"`
@@ -828,13 +844,13 @@ type SDK interface {
// ReadMessages read messages of specified channel.
//
// example:
// pm := sdk.PageMetadata{
// pm := sdk.MessagePageMetadata{
// Offset: 0,
// Limit: 10,
// }
// msgs, _ := sdk.ReadMessages(pm,"channelID", "token")
// fmt.Println(msgs)
ReadMessages(pm PageMetadata, chanID, token string) (MessagesPage, errors.SDKError)
ReadMessages(pm MessagePageMetadata, chanID, token string) (MessagesPage, errors.SDKError)
// SetContentType sets message content type.
//
+2 -2
View File
@@ -892,8 +892,8 @@ func TestUpdateThingSecret(t *testing.T) {
newSecret: "newSecret",
token: validToken,
response: sdk.Thing{},
repoErr: apiutil.ErrInvalidSecret,
err: errors.NewSDKErrorWithStatus(errors.Wrap(svcerr.ErrUpdateEntity, apiutil.ErrInvalidSecret), http.StatusBadRequest),
repoErr: apiutil.ErrMissingSecret,
err: errors.NewSDKErrorWithStatus(errors.Wrap(svcerr.ErrUpdateEntity, apiutil.ErrMissingSecret), http.StatusBadRequest),
},
}
for _, tc := range cases {
+1 -1
View File
@@ -62,7 +62,7 @@ func TestIssueToken(t *testing.T) {
desc: "issue token for an empty user",
login: sdk.Login{},
token: &magistrala.Token{},
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrMissingIdentity), http.StatusInternalServerError),
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrMissingIdentity), http.StatusBadRequest),
},
{
desc: "issue token for invalid identity",
+7 -14
View File
@@ -43,14 +43,14 @@ func setupUsers() (*httptest.Server, *umocks.Repository, *gmocks.Repository, *au
gRepo := new(gmocks.Repository)
auth := new(authmocks.AuthClient)
csvc := users.NewService(crepo, auth, emailer, phasher, idProvider, passRegex, true)
csvc := users.NewService(crepo, auth, emailer, true, nil)
gsvc := groups.NewService(gRepo, idProvider, auth)
logger := mglog.NewMock()
mux := chi.NewRouter()
provider := new(oauth2mocks.Provider)
provider.On("Name").Return("test")
api.MakeHandler(csvc, gsvc, mux, logger, "", provider)
api.MakeHandler(csvc, gsvc, mux, logger, "", passRegex, provider)
return httptest.NewServer(mux), crepo, gRepo, auth
}
@@ -62,7 +62,7 @@ func TestCreateClient(t *testing.T) {
user := sdk.User{
Name: "clientname",
Tags: []string{"tag1", "tag2"},
Credentials: sdk.Credentials{Identity: "admin@example.com", Secret: "secret"},
Credentials: sdk.Credentials{Identity: "admin@example.com", Secret: "12345678"},
Status: mgclients.EnabledStatus.String(),
}
conf := sdk.Config{
@@ -96,7 +96,7 @@ func TestCreateClient(t *testing.T) {
client: sdk.User{},
response: sdk.User{},
token: token,
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, errors.ErrMalformedEntity), http.StatusBadRequest),
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrMissingIdentity), http.StatusBadRequest),
},
{
desc: "register a user that can't be marshalled",
@@ -135,7 +135,7 @@ func TestCreateClient(t *testing.T) {
},
response: sdk.User{},
token: token,
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, errors.ErrMalformedEntity), http.StatusBadRequest),
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrMissingIdentity), http.StatusBadRequest),
},
{
desc: "register user with empty identity",
@@ -147,14 +147,7 @@ func TestCreateClient(t *testing.T) {
},
response: sdk.User{},
token: token,
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, errors.ErrMalformedEntity), http.StatusBadRequest),
},
{
desc: "register empty user",
client: sdk.User{},
response: sdk.User{},
token: token,
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, errors.ErrMalformedEntity), http.StatusBadRequest),
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrMissingIdentity), http.StatusBadRequest),
},
{
desc: "register user with every field defined",
@@ -828,7 +821,7 @@ func TestUpdateClientSecret(t *testing.T) {
newSecret: "newSecret",
token: validToken,
response: sdk.User{},
repoErr: apiutil.ErrInvalidSecret,
repoErr: apiutil.ErrMissingSecret,
err: errors.NewSDKErrorWithStatus(errors.Wrap(svcerr.ErrNotFound, repoerr.ErrMissingSecret), http.StatusBadRequest),
},
}
+4 -4
View File
@@ -1805,7 +1805,7 @@ func (_m *SDK) Parents(id string, pm sdk.PageMetadata, token string) (sdk.Groups
}
// ReadMessages provides a mock function with given fields: pm, chanID, token
func (_m *SDK) ReadMessages(pm sdk.PageMetadata, chanID string, token string) (sdk.MessagesPage, errors.SDKError) {
func (_m *SDK) ReadMessages(pm sdk.MessagePageMetadata, chanID string, token string) (sdk.MessagesPage, errors.SDKError) {
ret := _m.Called(pm, chanID, token)
if len(ret) == 0 {
@@ -1814,16 +1814,16 @@ func (_m *SDK) ReadMessages(pm sdk.PageMetadata, chanID string, token string) (s
var r0 sdk.MessagesPage
var r1 errors.SDKError
if rf, ok := ret.Get(0).(func(sdk.PageMetadata, string, string) (sdk.MessagesPage, errors.SDKError)); ok {
if rf, ok := ret.Get(0).(func(sdk.MessagePageMetadata, string, string) (sdk.MessagesPage, errors.SDKError)); ok {
return rf(pm, chanID, token)
}
if rf, ok := ret.Get(0).(func(sdk.PageMetadata, string, string) sdk.MessagesPage); ok {
if rf, ok := ret.Get(0).(func(sdk.MessagePageMetadata, string, string) sdk.MessagesPage); ok {
r0 = rf(pm, chanID, token)
} else {
r0 = ret.Get(0).(sdk.MessagesPage)
}
if rf, ok := ret.Get(1).(func(sdk.PageMetadata, string, string) errors.SDKError); ok {
if rf, ok := ret.Get(1).(func(sdk.MessagePageMetadata, string, string) errors.SDKError); ok {
r1 = rf(pm, chanID, token)
} else {
if ret.Get(1) != nil {
+1 -1
View File
@@ -187,7 +187,7 @@ func (ts *transformerService) transformTimeField(payload map[string]interface{})
return 0, err
}
return t.UnixNano(), nil
return transformers.ToUnixNano(t.UnixNano()), nil
}
}
+12 -2
View File
@@ -15,6 +15,8 @@ const (
JSON = "application/senml+json"
// CBOR represents SenML in CBOR format content type.
CBOR = "application/senml+cbor"
maxRelativeTime = 1 << 28
)
var (
@@ -59,8 +61,16 @@ func (t transformer) Transform(msg *messaging.Message) (interface{}, error) {
// Use reception timestamp if SenML messsage Time is missing
t := v.Time
if t == 0 {
// Convert the Unix timestamp in nanoseconds to float64
t = float64(msg.GetCreated()) / float64(1e9)
t = float64(msg.GetCreated())
}
// If time is below 2**28 it is relative to the current time
// https://datatracker.ietf.org/doc/html/rfc8428#section-4.5.3
if t >= maxRelativeTime {
t = transformers.ToUnixNano(t)
}
if v.UpdateTime >= maxRelativeTime {
v.UpdateTime = transformers.ToUnixNano(v.UpdateTime)
}
msgs[i] = Message{
+1 -1
View File
@@ -17,7 +17,7 @@ import (
func TestTransformJSON(t *testing.T) {
// Following hex-encoded bytes correspond to the content of:
// [{-2: "base-name", -3: 100.0, -4: "base-unit", -1: 10, -5: 10.0, -6: 100.0, 0: "name", 1: "unit", 6: 300.0, 7: 150.0, 2: 42.0, 5: 10.0}]
// [{"bn":"base-name","bt":100,"bu":"base-unit","bver":10,"bv":10,"bs":100,"n":"name","u":"unit","t":300,"ut":150,"v":42,"s":10}]
// For more details for mapping SenML labels to integers, please take a look here: https://tools.ietf.org/html/rfc8428#page-19.
jsonBytes, err := hex.DecodeString("5b7b22626e223a22626173652d6e616d65222c226274223a3130302c226275223a22626173652d756e6974222c2262766572223a31302c226276223a31302c226273223a3130302c226e223a226e616d65222c2275223a22756e6974222c2274223a3330302c227574223a3135302c2276223a34322c2273223a31307d5d")
assert.Nil(t, err, "Decoding JSON expected to succeed")
+20
View File
@@ -10,3 +10,23 @@ type Transformer interface {
// Transform Magistrala message to any other format.
Transform(msg *messaging.Message) (interface{}, error)
}
type number interface {
uint64 | int64 | float64
}
// ToUnixNano converts time to UnixNano time format.
func ToUnixNano[N number](t N) N {
switch {
case t == 0:
return 0
case t >= 1e18: // Check if the value is in nanoseconds
return t
case t >= 1e15 && t < 1e18: // Check if the value is in milliseconds
return t * 1e3
case t >= 1e12 && t < 1e15: // Check if the value is in microseconds
return t * 1e6
default: // Assume it's in seconds (Unix time)
return t * 1e9
}
}
+140
View File
@@ -0,0 +1,140 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package transformers_test
import (
"testing"
"time"
"github.com/absmach/magistrala/pkg/transformers"
)
var now = time.Now()
func TestInt64ToUnixNano(t *testing.T) {
cases := []struct {
desc string
time int64
want int64
}{
{
desc: "empty",
time: 0,
want: 0,
},
{
desc: "unix",
time: now.Unix(),
want: now.Unix() * int64(time.Second),
},
{
desc: "unix milli",
time: now.UnixMilli(),
want: now.UnixMilli() * int64(time.Millisecond),
},
{
desc: "unix micro",
time: now.UnixMicro(),
want: now.UnixMicro() * int64(time.Microsecond),
},
{
desc: "unix nano",
time: now.UnixNano(),
want: now.UnixNano(),
},
{
desc: "1e9 nano",
time: time.Unix(1e9, 0).Unix(),
want: time.Unix(1e9, 0).UnixNano(),
},
{
desc: "1e10 nano",
time: time.Unix(1e10, 0).Unix(),
want: time.Unix(1e10, 0).UnixNano(),
},
{
desc: "1e12 nano",
time: time.UnixMilli(1e12).Unix(),
want: time.UnixMilli(1e12).UnixNano(),
},
{
desc: "1e13 nano",
time: time.UnixMilli(1e13).Unix(),
want: time.UnixMilli(1e13).UnixNano(),
},
{
desc: "1e15 nano",
time: time.UnixMicro(1e15).Unix(),
want: time.UnixMicro(1e15).UnixNano(),
},
{
desc: "1e16 nano",
time: time.UnixMicro(1e16).Unix(),
want: time.UnixMicro(1e16).UnixNano(),
},
}
for _, c := range cases {
t.Run(c.desc, func(t *testing.T) {
got := transformers.ToUnixNano(c.time)
if got != c.want {
t.Errorf("ToUnixNano(%d) = %d; want %d", c.time, got, c.want)
}
t.Logf("ToUnixNano(%d) = %d; want %d", c.time, got, c.want)
})
}
}
func TestFloat64ToUnixNano(t *testing.T) {
cases := []struct {
desc string
time float64
want float64
}{
{
desc: "empty",
time: 0,
want: 0,
},
{
desc: "unix",
time: float64(now.Unix()),
want: float64(now.Unix() * int64(time.Second)),
},
{
desc: "unix milli",
time: float64(now.UnixMilli()),
want: float64(now.UnixMilli() * int64(time.Millisecond)),
},
{
desc: "unix micro",
time: float64(now.UnixMicro()),
want: float64(now.UnixMicro() * int64(time.Microsecond)),
},
{
desc: "unix nano",
time: float64(now.UnixNano()),
want: float64(now.UnixNano()),
},
}
for _, c := range cases {
t.Run(c.desc, func(t *testing.T) {
got := transformers.ToUnixNano(c.time)
if got != c.want {
t.Errorf("ToUnixNano(%f) = %f; want %f", c.time, got, c.want)
}
t.Logf("ToUnixNano(%f) = %f; want %f", c.time, got, c.want)
})
}
}
func BenchmarkToUnixNano(b *testing.B) {
for i := 0; i < b.N; i++ {
transformers.ToUnixNano(now.Unix())
transformers.ToUnixNano(now.UnixMilli())
transformers.ToUnixNano(now.UnixMicro())
transformers.ToUnixNano(now.UnixNano())
}
}
+124 -1
View File
@@ -414,7 +414,6 @@ func TestReadAll(t *testing.T) {
key: thingToken,
status: http.StatusBadRequest,
},
{
desc: "read page with non-float to as thing",
url: fmt.Sprintf("%s/channels/%s/messages?to=ABCD", ts.URL, chanID),
@@ -431,6 +430,68 @@ func TestReadAll(t *testing.T) {
Messages: messages[5:15],
},
},
{
desc: "read page with aggregation as thing",
url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX", ts.URL, chanID),
key: thingToken,
status: http.StatusBadRequest,
},
{
desc: "read page with interval as thing",
url: fmt.Sprintf("%s/channels/%s/messages?interval=10h", ts.URL, chanID),
key: thingToken,
status: http.StatusOK,
res: pageRes{
Total: uint64(len(messages)),
Messages: messages[0:10],
},
},
{
desc: "read page with aggregation and interval as thing",
url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h", ts.URL, chanID),
key: thingToken,
status: http.StatusBadRequest,
},
{
desc: "read page with aggregation, interval, to and from as thing",
url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time),
key: thingToken,
status: http.StatusOK,
res: pageRes{
Total: uint64(len(messages[5:20])),
Messages: messages[5:15],
},
},
{
desc: "read page with invalid aggregation and valid interval, to and from as thing",
url: fmt.Sprintf("%s/channels/%s/messages?aggregation=invalid&interval=10h&from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time),
key: thingToken,
status: http.StatusBadRequest,
},
{
desc: "read page with invalid interval and valid aggregation, to and from as thing",
url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10hrs&from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time),
key: thingToken,
status: http.StatusBadRequest,
},
{
desc: "read page with aggregation, interval and to with missing from as thing",
url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&to=%f", ts.URL, chanID, messages[4].Time),
key: thingToken,
status: http.StatusBadRequest,
},
{
desc: "read page with aggregation, interval and to with invalid from as thing",
url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&to=ABCD&from=%f", ts.URL, chanID, messages[4].Time),
key: thingToken,
status: http.StatusBadRequest,
},
{
desc: "read page with aggregation, interval and to with invalid to as thing",
url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&from=%f&to=ABCD", ts.URL, chanID, messages[4].Time),
key: thingToken,
status: http.StatusBadRequest,
},
{
desc: "read page with valid offset and limit as user",
url: fmt.Sprintf("%s/channels/%s/messages?offset=0&limit=10", ts.URL, chanID),
@@ -711,6 +772,68 @@ func TestReadAll(t *testing.T) {
Messages: messages[5:15],
},
},
{
desc: "read page with aggregation as user",
url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX", ts.URL, chanID),
key: userToken,
status: http.StatusBadRequest,
},
{
desc: "read page with interval as user",
url: fmt.Sprintf("%s/channels/%s/messages?interval=10h", ts.URL, chanID),
key: userToken,
status: http.StatusOK,
res: pageRes{
Total: uint64(len(messages)),
Messages: messages[0:10],
},
},
{
desc: "read page with aggregation and interval as user",
url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h", ts.URL, chanID),
key: userToken,
status: http.StatusBadRequest,
},
{
desc: "read page with aggregation, interval, to and from as user",
url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time),
key: userToken,
status: http.StatusOK,
res: pageRes{
Total: uint64(len(messages[5:20])),
Messages: messages[5:15],
},
},
{
desc: "read page with invalid aggregation and valid interval, to and from as user",
url: fmt.Sprintf("%s/channels/%s/messages?aggregation=invalid&interval=10h&from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time),
key: userToken,
status: http.StatusBadRequest,
},
{
desc: "read page with invalid interval and valid aggregation, to and from as user",
url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10hrs&from=%f&to=%f", ts.URL, chanID, messages[19].Time, messages[4].Time),
key: userToken,
status: http.StatusBadRequest,
},
{
desc: "read page with aggregation, interval and to with missing from as user",
url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&to=%f", ts.URL, chanID, messages[4].Time),
key: userToken,
status: http.StatusBadRequest,
},
{
desc: "read page with aggregation, interval and to with invalid from as user",
url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&to=ABCD&from=%f", ts.URL, chanID, messages[4].Time),
key: userToken,
status: http.StatusBadRequest,
},
{
desc: "read page with aggregation, interval and to with invalid to as user",
url: fmt.Sprintf("%s/channels/%s/messages?aggregation=MAX&interval=10h&from=%f&to=ABCD", ts.URL, chanID, messages[4].Time),
key: userToken,
status: http.StatusBadRequest,
},
}
for _, tc := range cases {
+24
View File
@@ -4,12 +4,18 @@
package api
import (
"slices"
"strings"
"time"
"github.com/absmach/magistrala/internal/apiutil"
"github.com/absmach/magistrala/readers"
)
const maxLimitSize = 1000
var validAggregations = []string{"MAX", "MIN", "AVG", "SUM", "COUNT"}
type listMessagesReq struct {
chanID string
token string
@@ -39,5 +45,23 @@ func (req listMessagesReq) validate() error {
return apiutil.ErrInvalidComparator
}
if req.pageMeta.Aggregation != "" {
if req.pageMeta.From == 0 {
return apiutil.ErrMissingFrom
}
if req.pageMeta.To == 0 {
return apiutil.ErrMissingTo
}
if !slices.Contains(validAggregations, strings.ToUpper(req.pageMeta.Aggregation)) {
return apiutil.ErrInvalidAggregation
}
if _, err := time.ParseDuration(req.pageMeta.Interval); err != nil {
return apiutil.ErrInvalidInterval
}
}
return nil
}
+23 -1
View File
@@ -36,6 +36,9 @@ const (
comparatorKey = "comparator"
fromKey = "from"
toKey = "to"
aggregationKey = "aggregation"
intervalKey = "interval"
defInterval = "1s"
defLimit = 10
defOffset = 0
defFormat = "messages"
@@ -141,6 +144,19 @@ func decodeList(_ context.Context, r *http.Request) (interface{}, error) {
return nil, errors.Wrap(apiutil.ErrValidation, err)
}
aggregation, err := apiutil.ReadStringQuery(r, aggregationKey, "")
if err != nil {
return nil, errors.Wrap(apiutil.ErrValidation, err)
}
var interval string
if aggregation != "" {
interval, err = apiutil.ReadStringQuery(r, intervalKey, defInterval)
if err != nil {
return nil, errors.Wrap(apiutil.ErrValidation, err)
}
}
req := listMessagesReq{
chanID: chi.URLParam(r, "chanID"),
token: apiutil.ExtractBearerToken(r),
@@ -160,6 +176,8 @@ func decodeList(_ context.Context, r *http.Request) (interface{}, error) {
BoolValue: vb,
From: from,
To: to,
Aggregation: aggregation,
Interval: interval,
},
}
return req, nil
@@ -196,7 +214,11 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
errors.Contains(err, apiutil.ErrMissingID),
errors.Contains(err, apiutil.ErrLimitSize),
errors.Contains(err, apiutil.ErrOffsetSize),
errors.Contains(err, apiutil.ErrInvalidComparator):
errors.Contains(err, apiutil.ErrInvalidComparator),
errors.Contains(err, apiutil.ErrInvalidAggregation),
errors.Contains(err, apiutil.ErrInvalidInterval),
errors.Contains(err, apiutil.ErrMissingFrom),
errors.Contains(err, apiutil.ErrMissingTo):
w.WriteHeader(http.StatusBadRequest)
case errors.Contains(err, svcerr.ErrAuthentication),
errors.Contains(err, svcerr.ErrAuthorization),
+2
View File
@@ -55,6 +55,8 @@ type PageMetadata struct {
From float64 `json:"from,omitempty"`
To float64 `json:"to,omitempty"`
Format string `json:"format,omitempty"`
Aggregation string `json:"aggregation,omitempty"`
Interval string `json:"interval,omitempty"`
}
// ParseValueComparator convert comparison operator keys into mathematic anotation.
+10 -4
View File
@@ -37,7 +37,14 @@ func (tr timescaleRepository) ReadAll(chanID string, rpm readers.PageMetadata) (
format = rpm.Format
}
q := fmt.Sprintf(`SELECT * FROM %s WHERE %s ORDER BY %s DESC LIMIT :limit OFFSET :offset;`, format, fmtCondition(chanID, rpm), order)
q := fmt.Sprintf(`SELECT * FROM %s WHERE %s ORDER BY %s DESC LIMIT :limit OFFSET :offset;`, format, fmtCondition(rpm), order)
totalQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s WHERE %s;`, format, fmtCondition(rpm))
// If aggregation is provided, add time_bucket and aggregation to the query
if rpm.Aggregation != "" {
q = fmt.Sprintf(`SELECT EXTRACT(epoch FROM time_bucket('%s', to_timestamp(time/1000))) *1000 AS time, %s(value) AS value FROM %s WHERE %s GROUP BY 1 ORDER BY time DESC LIMIT :limit OFFSET :offset;`, rpm.Interval, rpm.Aggregation, format, fmtCondition(rpm))
totalQuery = fmt.Sprintf(`SELECT COUNT(*) FROM (SELECT EXTRACT(epoch FROM time_bucket('%s', to_timestamp(time/1000))) AS time, %s(value) AS value FROM %s WHERE %s GROUP BY 1) AS subquery;`, rpm.Interval, rpm.Aggregation, format, fmtCondition(rpm))
}
params := map[string]interface{}{
"channel": chanID,
@@ -94,8 +101,7 @@ func (tr timescaleRepository) ReadAll(chanID string, rpm readers.PageMetadata) (
}
}
q = fmt.Sprintf(`SELECT COUNT(*) FROM %s WHERE %s;`, format, fmtCondition(chanID, rpm))
rows, err = tr.db.NamedQuery(q, params)
rows, err = tr.db.NamedQuery(totalQuery, params)
if err != nil {
return readers.MessagesPage{}, errors.Wrap(readers.ErrReadMessages, err)
}
@@ -112,7 +118,7 @@ func (tr timescaleRepository) ReadAll(chanID string, rpm readers.PageMetadata) (
return page, nil
}
func fmtCondition(chanID string, rpm readers.PageMetadata) string {
func fmtCondition(rpm readers.PageMetadata) string {
condition := `channel = :channel`
var query map[string]interface{}
+4 -4
View File
@@ -383,7 +383,7 @@ func update(s sdk.SDK, token string, users []sdk.User, groups []sdk.Group, thing
return fmt.Errorf("failed to update user metadata before %s after %s", user.Metadata["Update"], rUser.Metadata["Update"])
}
user = rUser
user.Credentials.Identity = namesgenerator.Generate()
user.Credentials.Identity = namesgenerator.Generate() + "@example.com"
rUser, err = s.UpdateUserIdentity(user, token)
if err != nil {
return fmt.Errorf("failed to update user identity %w", err)
@@ -397,9 +397,9 @@ func update(s sdk.SDK, token string, users []sdk.User, groups []sdk.Group, thing
if err != nil {
return fmt.Errorf("failed to update user tags %w", err)
}
if rUser.Tags[0] != user.Tags[0] {
return fmt.Errorf("failed to update user tags before %s after %s", user.Tags[0], rUser.Tags[0])
}
// if rUser.Tags[0] != user.Tags[0] {
// return fmt.Errorf("failed to update user tags before %s after %s", user.Tags[0], rUser.Tags[0])
// }
user = rUser
rUser, err = s.DisableUser(user.ID, token)
if err != nil {
+57 -39
View File
@@ -12,45 +12,54 @@ For in-depth explanation of the aforementioned scenarios, as well as thorough un
The service is configured using the environment variables presented in the following table. Note that any unset variables will be replaced with their default values.
| Variable | Description | Default |
| ----------------------------- | ----------------------------------------------------------------------- | ----------------------------------- |
| MG_USERS_LOG_LEVEL | Log level for users service (debug, info, warn, error) | info |
| MG_USERS_ADMIN_EMAIL | Default user, created on startup | <admin@example.com> |
| MG_USERS_ADMIN_PASSWORD | Default user password, created on startup | 12345678 |
| MG_USERS_PASS_REGEX | Password regex | ^.{8,}$ |
| MG_TOKEN_RESET_ENDPOINT | Password request reset endpoint, for constructing link | /reset-request |
| MG_USERS_HTTP_HOST | Users service HTTP host | localhost |
| MG_USERS_HTTP_PORT | Users service HTTP port | 9002 |
| MG_USERS_HTTP_SERVER_CERT | Path to the PEM encoded server certificate file | "" |
| MG_USERS_HTTP_SERVER_KEY | Path to the PEM encoded server key file | "" |
| MG_USERS_HTTP_SERVER_CA_CERTS | Path to the PEM encoded server CA certificate file | "" |
| MG_USERS_HTTP_CLIENT_CA_CERTS | Path to the PEM encoded client CA certificate file | "" |
| MG_AUTH_GRPC_URL | Auth service GRPC URL | localhost:8181 |
| MG_AUTH_GRPC_TIMEOUT | Auth service GRPC timeout | 1s |
| MG_AUTH_GRPC_CLIENT_CERT | Path to the PEM encoded client certificate file | "" |
| MG_AUTH_GRPC_CLIENT_KEY | Path to the PEM encoded client key file | "" |
| MG_AUTH_GRPC_SERVER_CA_CERTS | Path to the PEM encoded server CA certificate file | "" |
| MG_USERS_DB_HOST | Database host address | localhost |
| MG_USERS_DB_PORT | Database host port | 5432 |
| MG_USERS_DB_USER | Database user | magistrala |
| MG_USERS_DB_PASS | Database password | magistrala |
| MG_USERS_DB_NAME | Name of the database used by the service | users |
| MG_USERS_DB_SSL_MODE | Database connection SSL mode (disable, require, verify-ca, verify-full) | disable |
| MG_USERS_DB_SSL_CERT | Path to the PEM encoded certificate file | "" |
| MG_USERS_DB_SSL_KEY | Path to the PEM encoded key file | "" |
| MG_USERS_DB_SSL_ROOT_CERT | Path to the PEM encoded root certificate file | "" |
| MG_EMAIL_HOST | Mail server host | localhost |
| MG_EMAIL_PORT | Mail server port | 25 |
| MG_EMAIL_USERNAME | Mail server username | "" |
| MG_EMAIL_PASSWORD | Mail server password | "" |
| MG_EMAIL_FROM_ADDRESS | Email "from" address | "" |
| MG_EMAIL_FROM_NAME | Email "from" name | "" |
| MG_EMAIL_TEMPLATE | Email template for sending emails with password reset link | email.tmpl |
| MG_USERS_ES_URL | Event store URL | <nats://localhost:4222> |
| MG_JAEGER_URL | Jaeger server URL | <http://localhost:14268/api/traces> |
| MG_JAEGER_TRACE_RATIO | Jaeger sampling ratio | 1.0 |
| MG_SEND_TELEMETRY | Send telemetry to magistrala call home server. | true |
| MG_USERS_INSTANCE_ID | Magistrala instance ID | "" |
| Variable | Description | Default |
| ----------------------------- | ----------------------------------------------------------------------- | ---------------------------------------- |
| MG_USERS_LOG_LEVEL | Log level for users service (debug, info, warn, error) | info |
| MG_USERS_ADMIN_EMAIL | Default user, created on startup | <admin@example.com> |
| MG_USERS_ADMIN_PASSWORD | Default user password, created on startup | 12345678 |
| MG_USERS_PASS_REGEX | Password regex | ^.{8,}$ |
| MG_TOKEN_RESET_ENDPOINT | Password request reset endpoint, for constructing link | /reset-request |
| MG_USERS_HTTP_HOST | Users service HTTP host | localhost |
| MG_USERS_HTTP_PORT | Users service HTTP port | 9002 |
| MG_USERS_HTTP_SERVER_CERT | Path to the PEM encoded server certificate file | "" |
| MG_USERS_HTTP_SERVER_KEY | Path to the PEM encoded server key file | "" |
| MG_USERS_HTTP_SERVER_CA_CERTS | Path to the PEM encoded server CA certificate file | "" |
| MG_USERS_HTTP_CLIENT_CA_CERTS | Path to the PEM encoded client CA certificate file | "" |
| MG_AUTH_GRPC_URL | Auth service GRPC URL | localhost:8181 |
| MG_AUTH_GRPC_TIMEOUT | Auth service GRPC timeout | 1s |
| MG_AUTH_GRPC_CLIENT_CERT | Path to the PEM encoded client certificate file | "" |
| MG_AUTH_GRPC_CLIENT_KEY | Path to the PEM encoded client key file | "" |
| MG_AUTH_GRPC_SERVER_CA_CERTS | Path to the PEM encoded server CA certificate file | "" |
| MG_USERS_DB_HOST | Database host address | localhost |
| MG_USERS_DB_PORT | Database host port | 5432 |
| MG_USERS_DB_USER | Database user | magistrala |
| MG_USERS_DB_PASS | Database password | magistrala |
| MG_USERS_DB_NAME | Name of the database used by the service | users |
| MG_USERS_DB_SSL_MODE | Database connection SSL mode (disable, require, verify-ca, verify-full) | disable |
| MG_USERS_DB_SSL_CERT | Path to the PEM encoded certificate file | "" |
| MG_USERS_DB_SSL_KEY | Path to the PEM encoded key file | "" |
| MG_USERS_DB_SSL_ROOT_CERT | Path to the PEM encoded root certificate file | "" |
| MG_EMAIL_HOST | Mail server host | localhost |
| MG_EMAIL_PORT | Mail server port | 25 |
| MG_EMAIL_USERNAME | Mail server username | "" |
| MG_EMAIL_PASSWORD | Mail server password | "" |
| MG_EMAIL_FROM_ADDRESS | Email "from" address | "" |
| MG_EMAIL_FROM_NAME | Email "from" name | "" |
| MG_EMAIL_TEMPLATE | Email template for sending emails with password reset link | email.tmpl |
| MG_USERS_ES_URL | Event store URL | <nats://localhost:4222> |
| MG_JAEGER_URL | Jaeger server URL | <http://localhost:14268/api/traces> |
| MG_JAEGER_TRACE_RATIO | Jaeger sampling ratio | 1.0 |
| MG_SEND_TELEMETRY | Send telemetry to magistrala call home server. | true |
| MG_USERS_INSTANCE_ID | Magistrala instance ID | "" |
| MG_KRATOS_CLIENT_ID | Kratos client ID | "" |
| MG_KRATOS_CLIENT_SECRET | Kratos client secret | "" |
| MG_KRATOS_REDIRECT_URL | Kratos redirect URL | <http://localhost/oauth/callback/kratos> |
| MG_KRATOS_STATE | Kratos state | "" |
| MG_OAUTH_UI_REDIRECT_URL | OAuth UI redirect URL | <http://localhost:9095/domains> |
| MG_OAUTH_UI_ERROR_URL | OAuth UI error URL | <http://localhost:9095/error> |
| MG_KRATOS_URL | Kratos URL | <http://localhost:4433> |
| MG_KRATOS_API_KEY | Kratos API key | "" |
| MG_KRATOS_SCHEMA_ID | Kratos schema ID | "" |
## Deployment
@@ -108,6 +117,15 @@ MG_JAEGER_URL=http://localhost:14268/api/traces \
MG_JAEGER_TRACE_RATIO=1.0 \
MG_SEND_TELEMETRY=true \
MG_USERS_INSTANCE_ID="" \
MG_KRATOS_CLIENT_ID="" \
MG_KRATOS_CLIENT_SECRET="" \
MG_KRATOS_REDIRECT_URL=http://localhost/oauth/callback/kratos \
MG_KRATOS_STATE="" \
MG_OAUTH_UI_REDIRECT_URL=http://localhost:9095/domains \
MG_OAUTH_UI_ERROR_URL=http://localhost:9095/error \
MG_KRATOS_URL=http://localhost:4433 \
MG_KRATOS_API_KEY="" \
MG_KRATOS_SCHEMA_ID="" \
$GOBIN/magistrala-users
```
+14 -3
View File
@@ -8,6 +8,7 @@ import (
"encoding/json"
"log/slog"
"net/http"
"regexp"
"strings"
"github.com/absmach/magistrala/auth"
@@ -22,8 +23,12 @@ import (
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)
var passRegex = regexp.MustCompile("^.{8,}$")
// MakeHandler returns a HTTP handler for API endpoints.
func clientsHandler(svc users.Service, r *chi.Mux, logger *slog.Logger, providers ...oauth2.Provider) http.Handler {
func clientsHandler(svc users.Service, r *chi.Mux, logger *slog.Logger, pr *regexp.Regexp, providers ...oauth2.Provider) http.Handler {
passRegex = pr
opts := []kithttp.ServerOption{
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, api.EncodeError)),
}
@@ -548,13 +553,19 @@ func oauth2CallbackHandler(oauth oauth2.Provider, svc users.Service) http.Handle
}
if code := r.FormValue("code"); code != "" {
client, token, err := oauth.UserDetails(r.Context(), code)
token, err := oauth.Exchange(r.Context(), code)
if err != nil {
http.Redirect(w, r, oauth.ErrorURL()+"?error="+err.Error(), http.StatusSeeOther)
return
}
jwt, err := svc.OAuthCallback(r.Context(), oauth.Name(), flow, token, client)
client, err := oauth.UserInfo(token.AccessToken)
if err != nil {
http.Redirect(w, r, oauth.ErrorURL()+"?error="+err.Error(), http.StatusSeeOther)
return
}
jwt, err := svc.OAuthCallback(r.Context(), flow, client)
if err != nil {
http.Redirect(w, r, oauth.ErrorURL()+"?error="+err.Error(), http.StatusSeeOther)
return
+17 -16
View File
@@ -9,6 +9,7 @@ import (
"io"
"net/http"
"net/http/httptest"
"regexp"
"strings"
"testing"
@@ -44,11 +45,11 @@ var (
Metadata: validCMetadata,
Status: mgclients.EnabledStatus,
}
validToken = "valid"
inValidToken = "invalid"
inValid = "invalid"
validID = "d4ebb847-5d0e-4e46-bdd9-b6aceaaa3a22"
ErrPasswordFormat = errors.New("password does not meet the requirements")
validToken = "valid"
inValidToken = "invalid"
inValid = "invalid"
validID = "d4ebb847-5d0e-4e46-bdd9-b6aceaaa3a22"
passRegex = regexp.MustCompile("^.{8,}$")
)
const contentType = "application/json"
@@ -92,7 +93,7 @@ func newUsersServer() (*httptest.Server, *mocks.Service) {
mux := chi.NewRouter()
provider := new(oauth2mocks.Provider)
provider.On("Name").Return("test")
httpapi.MakeHandler(svc, gsvc, mux, logger, "", provider)
httpapi.MakeHandler(svc, gsvc, mux, logger, "", passRegex, provider)
return httptest.NewServer(mux), svc
}
@@ -1166,8 +1167,8 @@ func TestPasswordReset(t *testing.T) {
data: fmt.Sprintf(`{"token": "%s", "password": "%s", "confirm_password": "%s"}`, validToken, "weak", "weak"),
token: validToken,
contentType: contentType,
status: http.StatusInternalServerError,
err: ErrPasswordFormat,
status: http.StatusBadRequest,
err: apiutil.ErrPasswordFormat,
},
{
desc: "password reset with empty token",
@@ -1182,7 +1183,7 @@ func TestPasswordReset(t *testing.T) {
data: fmt.Sprintf(`{"token": "%s", "password": "%s", "confirm_password": "%s"}`, validToken, "", ""),
token: validToken,
contentType: contentType,
status: http.StatusInternalServerError,
status: http.StatusBadRequest,
err: apiutil.ErrValidation,
},
{
@@ -1338,7 +1339,7 @@ func TestUpdateClientSecret(t *testing.T) {
}{
{
desc: "update user secret with valid token",
data: fmt.Sprintf(`{"secret": "%s"}`, "strongersecret"),
data: `{"old_secret": "strongersecret", "new_secret": "strongersecret"}`,
client: mgclients.Client{
ID: client.ID,
Credentials: mgclients.Credentials{
@@ -1353,7 +1354,7 @@ func TestUpdateClientSecret(t *testing.T) {
},
{
desc: "update user secret with empty token",
data: fmt.Sprintf(`{"secret": "%s"}`, "strongersecret"),
data: `{"old_secret": "strongersecret", "new_secret": "strongersecret"}`,
client: mgclients.Client{
ID: client.ID,
Credentials: mgclients.Credentials{
@@ -1368,7 +1369,7 @@ func TestUpdateClientSecret(t *testing.T) {
},
{
desc: "update user secret with invalid token",
data: fmt.Sprintf(`{"secret": "%s"}`, "strongersecret"),
data: `{"old_secret": "strongersecret", "new_secret": "strongersecret"}`,
client: mgclients.Client{
ID: client.ID,
Credentials: mgclients.Credentials{
@@ -1384,7 +1385,7 @@ func TestUpdateClientSecret(t *testing.T) {
{
desc: "update user secret with empty secret",
data: fmt.Sprintf(`{"secret": "%s"}`, ""),
data: `{"old_secret": "", "new_secret": "strongersecret"}`,
client: mgclients.Client{
ID: client.ID,
Credentials: mgclients.Credentials{
@@ -1395,11 +1396,11 @@ func TestUpdateClientSecret(t *testing.T) {
contentType: contentType,
token: validToken,
status: http.StatusBadRequest,
err: apiutil.ErrBearerKey,
err: apiutil.ErrMissingPass,
},
{
desc: "update user secret with invalid contentype",
data: fmt.Sprintf(`{"secret": "%s"}`, ""),
data: `{"old_secret": "strongersecret", "new_secret": "strongersecret"}`,
client: mgclients.Client{
ID: client.ID,
Credentials: mgclients.Credentials{
@@ -1479,7 +1480,7 @@ func TestIssueToken(t *testing.T) {
desc: "issue token with empty identity",
data: fmt.Sprintf(`{"identity": "%s", "secret": "%s", "domainID": "%s"}`, "", secret, validID),
contentType: contentType,
status: http.StatusInternalServerError,
status: http.StatusBadRequest,
err: apiutil.ErrValidation,
},
{
+2 -4
View File
@@ -12,7 +12,6 @@ import (
mgclients "github.com/absmach/magistrala/pkg/clients"
mgoauth2 "github.com/absmach/magistrala/pkg/oauth2"
"github.com/absmach/magistrala/users"
"golang.org/x/oauth2"
)
var _ users.Service = (*loggingMiddleware)(nil)
@@ -400,11 +399,10 @@ func (lm *loggingMiddleware) Identify(ctx context.Context, token string) (id str
return lm.svc.Identify(ctx, token)
}
func (lm *loggingMiddleware) OAuthCallback(ctx context.Context, provider string, state mgoauth2.State, oauthToken oauth2.Token, client mgclients.Client) (token *magistrala.Token, err error) {
func (lm *loggingMiddleware) OAuthCallback(ctx context.Context, state mgoauth2.State, client mgclients.Client) (token *magistrala.Token, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("provider", provider),
slog.String("state", state.String()),
slog.String("user_id", client.ID),
}
@@ -415,5 +413,5 @@ func (lm *loggingMiddleware) OAuthCallback(ctx context.Context, provider string,
}
lm.logger.Info("OAuth callback completed successfully", args...)
}(time.Now())
return lm.svc.OAuthCallback(ctx, provider, state, oauthToken, client)
return lm.svc.OAuthCallback(ctx, state, client)
}
+3 -4
View File
@@ -12,7 +12,6 @@ import (
mgoauth2 "github.com/absmach/magistrala/pkg/oauth2"
"github.com/absmach/magistrala/users"
"github.com/go-kit/kit/metrics"
"golang.org/x/oauth2"
)
var _ users.Service = (*metricsMiddleware)(nil)
@@ -194,11 +193,11 @@ func (ms *metricsMiddleware) Identify(ctx context.Context, token string) (string
return ms.svc.Identify(ctx, token)
}
func (ms *metricsMiddleware) OAuthCallback(ctx context.Context, provider string, state mgoauth2.State, token oauth2.Token, client mgclients.Client) (*magistrala.Token, error) {
method := provider + "_oauth_callback_" + state.String()
func (ms *metricsMiddleware) OAuthCallback(ctx context.Context, state mgoauth2.State, client mgclients.Client) (*magistrala.Token, error) {
method := "oauth_callback_" + state.String()
defer func(begin time.Time) {
ms.counter.With("method", method).Add(1)
ms.latency.With("method", method).Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.OAuthCallback(ctx, provider, state, token, client)
return ms.svc.OAuthCallback(ctx, state, client)
}
+19 -1
View File
@@ -20,6 +20,15 @@ func (req createClientReq) validate() error {
if len(req.client.Name) > api.MaxNameSize {
return apiutil.ErrNameSize
}
if req.client.Credentials.Identity == "" {
return apiutil.ErrMissingIdentity
}
if req.client.Credentials.Secret == "" {
return apiutil.ErrMissingPass
}
if !passRegex.MatchString(req.client.Credentials.Secret) {
return apiutil.ErrPasswordFormat
}
return req.client.Validate()
}
@@ -180,6 +189,12 @@ func (req updateClientSecretReq) validate() error {
if req.token == "" {
return apiutil.ErrBearerToken
}
if req.OldSecret == "" || req.NewSecret == "" {
return apiutil.ErrMissingPass
}
if !passRegex.MatchString(req.NewSecret) {
return apiutil.ErrPasswordFormat
}
return nil
}
@@ -211,7 +226,7 @@ func (req loginClientReq) validate() error {
return apiutil.ErrMissingIdentity
}
if req.Secret == "" {
return apiutil.ErrMissingSecret
return apiutil.ErrMissingPass
}
return nil
@@ -265,6 +280,9 @@ func (req resetTokenReq) validate() error {
if req.Password != req.ConfPass {
return apiutil.ErrInvalidResetPass
}
if !passRegex.MatchString(req.ConfPass) {
return apiutil.ErrPasswordFormat
}
return nil
}
+88 -17
View File
@@ -17,6 +17,7 @@ import (
const (
valid = "valid"
invalid = "invalid"
secret = "QJg58*aMan7j"
)
var validID = testsutil.GenerateUUID(&testing.T{})
@@ -36,7 +37,7 @@ func TestCreateClientReqValidate(t *testing.T) {
Name: valid,
Credentials: mgclients.Credentials{
Identity: "example@example.com",
Secret: valid,
Secret: secret,
},
},
},
@@ -51,7 +52,7 @@ func TestCreateClientReqValidate(t *testing.T) {
Name: valid,
Credentials: mgclients.Credentials{
Identity: "example@example.com",
Secret: valid,
Secret: secret,
},
},
},
@@ -67,6 +68,49 @@ func TestCreateClientReqValidate(t *testing.T) {
},
err: apiutil.ErrNameSize,
},
{
desc: "missing identity in request",
req: createClientReq{
token: valid,
client: mgclients.Client{
ID: validID,
Name: valid,
Credentials: mgclients.Credentials{
Secret: valid,
},
},
},
err: apiutil.ErrMissingIdentity,
},
{
desc: "missing secret in request",
req: createClientReq{
token: valid,
client: mgclients.Client{
ID: validID,
Name: valid,
Credentials: mgclients.Credentials{
Identity: "example@example.com",
},
},
},
err: apiutil.ErrMissingPass,
},
{
desc: "invalid secret in request",
req: createClientReq{
token: valid,
client: mgclients.Client{
ID: validID,
Name: valid,
Credentials: mgclients.Credentials{
Identity: "example@example.com",
Secret: "invalid",
},
},
},
err: apiutil.ErrPasswordFormat,
},
}
for _, tc := range cases {
err := tc.req.validate()
@@ -411,8 +455,8 @@ func TestUpdateClientSecretReqValidate(t *testing.T) {
desc: "valid request",
req: updateClientSecretReq{
token: valid,
OldSecret: valid,
NewSecret: valid,
OldSecret: secret,
NewSecret: secret,
},
err: nil,
},
@@ -420,11 +464,38 @@ func TestUpdateClientSecretReqValidate(t *testing.T) {
desc: "empty token",
req: updateClientSecretReq{
token: "",
OldSecret: valid,
NewSecret: valid,
OldSecret: secret,
NewSecret: secret,
},
err: apiutil.ErrBearerToken,
},
{
desc: "missing old secret",
req: updateClientSecretReq{
token: valid,
OldSecret: "",
NewSecret: secret,
},
err: apiutil.ErrMissingPass,
},
{
desc: "missing new secret",
req: updateClientSecretReq{
token: valid,
OldSecret: secret,
NewSecret: "",
},
err: apiutil.ErrMissingPass,
},
{
desc: "invalid new secret",
req: updateClientSecretReq{
token: valid,
OldSecret: secret,
NewSecret: "invalid",
},
err: apiutil.ErrPasswordFormat,
},
}
for _, c := range cases {
err := c.req.validate()
@@ -479,7 +550,7 @@ func TestLoginClientReqValidate(t *testing.T) {
desc: "valid request",
req: loginClientReq{
Identity: "eaxmple,example.com",
Secret: valid,
Secret: secret,
},
err: nil,
},
@@ -487,7 +558,7 @@ func TestLoginClientReqValidate(t *testing.T) {
desc: "empty identity",
req: loginClientReq{
Identity: "",
Secret: valid,
Secret: secret,
},
err: apiutil.ErrMissingIdentity,
},
@@ -497,7 +568,7 @@ func TestLoginClientReqValidate(t *testing.T) {
Identity: "eaxmple,example.com",
Secret: "",
},
err: apiutil.ErrMissingSecret,
err: apiutil.ErrMissingPass,
},
}
for _, c := range cases {
@@ -580,8 +651,8 @@ func TestResetTokenReqValidate(t *testing.T) {
desc: "valid request",
req: resetTokenReq{
Token: valid,
Password: valid,
ConfPass: valid,
Password: secret,
ConfPass: secret,
},
err: nil,
},
@@ -589,8 +660,8 @@ func TestResetTokenReqValidate(t *testing.T) {
desc: "empty token",
req: resetTokenReq{
Token: "",
Password: valid,
ConfPass: valid,
Password: secret,
ConfPass: secret,
},
err: apiutil.ErrBearerToken,
},
@@ -599,7 +670,7 @@ func TestResetTokenReqValidate(t *testing.T) {
req: resetTokenReq{
Token: valid,
Password: "",
ConfPass: valid,
ConfPass: secret,
},
err: apiutil.ErrMissingPass,
},
@@ -607,7 +678,7 @@ func TestResetTokenReqValidate(t *testing.T) {
desc: "empty confpass",
req: resetTokenReq{
Token: valid,
Password: valid,
Password: secret,
ConfPass: "",
},
err: apiutil.ErrMissingConfPass,
@@ -616,8 +687,8 @@ func TestResetTokenReqValidate(t *testing.T) {
desc: "mismatching password and confpass",
req: resetTokenReq{
Token: valid,
Password: "valid2",
ConfPass: valid,
Password: "secret",
ConfPass: secret,
},
err: apiutil.ErrInvalidResetPass,
},
+3 -2
View File
@@ -6,6 +6,7 @@ package api
import (
"log/slog"
"net/http"
"regexp"
"github.com/absmach/magistrala"
"github.com/absmach/magistrala/pkg/groups"
@@ -16,8 +17,8 @@ import (
)
// MakeHandler returns a HTTP handler for Users and Groups API endpoints.
func MakeHandler(cls users.Service, grps groups.Service, mux *chi.Mux, logger *slog.Logger, instanceID string, providers ...oauth2.Provider) http.Handler {
clientsHandler(cls, mux, logger, providers...)
func MakeHandler(cls users.Service, grps groups.Service, mux *chi.Mux, logger *slog.Logger, instanceID string, pr *regexp.Regexp, providers ...oauth2.Provider) http.Handler {
clientsHandler(cls, mux, logger, pr, providers...)
groupsHandler(grps, mux, logger)
mux.Get("/health", magistrala.Health("users", instanceID))
+18 -2
View File
@@ -9,7 +9,6 @@ import (
"github.com/absmach/magistrala"
"github.com/absmach/magistrala/pkg/clients"
mgoauth2 "github.com/absmach/magistrala/pkg/oauth2"
"golang.org/x/oauth2"
)
// Service specifies an API that must be fullfiled by the domain service
@@ -78,5 +77,22 @@ type Service interface {
// OAuthCallback handles the callback from any supported OAuth provider.
// It processes the OAuth tokens and either signs in or signs up the user based on the provided state.
OAuthCallback(ctx context.Context, provider string, state mgoauth2.State, token oauth2.Token, client clients.Client) (*magistrala.Token, error)
OAuthCallback(ctx context.Context, state mgoauth2.State, client clients.Client) (*magistrala.Token, error)
}
// Repository defines the required dependencies for Client repository.
//
//go:generate mockery --name Repository --output=./mocks --filename repository.go --quiet --note "Copyright (c) Abstract Machines"
type Repository interface {
clients.Repository
// Save persists the client account. A non-nil error is returned to indicate
// operation failure.
Save(ctx context.Context, client clients.Client) (clients.Client, error)
RetrieveByID(ctx context.Context, id string) (clients.Client, error)
UpdateRole(ctx context.Context, client clients.Client) (clients.Client, error)
CheckSuperAdmin(ctx context.Context, adminID string) error
}
-2
View File
@@ -415,7 +415,6 @@ func (spre sendPasswordResetEvent) Encode() (map[string]interface{}, error) {
type oauthCallbackEvent struct {
state string
provider string
clientID string
}
@@ -423,7 +422,6 @@ func (oce oauthCallbackEvent) Encode() (map[string]interface{}, error) {
return map[string]interface{}{
"operation": oauthCallback,
"state": oce.state,
"provider": oce.provider,
"client_id": oce.clientID,
}, nil
}

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