mirror of
https://github.com/absmach/magistrala.git
synced 2026-08-07 15:25:48 +00:00
Compare commits
18 Commits
hooks
...
v0.14.1-dave
| Author | SHA1 | Date | |
|---|---|---|---|
| d7075502cc | |||
| d9195d0f6e | |||
| e00b630e79 | |||
| fc279d7d78 | |||
| b4c60b21cc | |||
| f5c0e2c906 | |||
| e2b021ab60 | |||
| 959dbd7c50 | |||
| 7a61872648 | |||
| 8e45a8c5d7 | |||
| 8ffc710b6a | |||
| f762b91669 | |||
| 6e8ca15f56 | |||
| d3fe7d1063 | |||
| ad6619f0ac | |||
| 4bee424289 | |||
| f55d7640eb | |||
| 221c1212bb |
+1
-1
@@ -2,7 +2,7 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
.git
|
||||
.github
|
||||
.gitlab
|
||||
build
|
||||
docker
|
||||
metrics
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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:
|
||||
@@ -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"
|
||||
@@ -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?
|
||||
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
# Magistrala
|
||||
|
||||
[](https://github.com/absmach/magistrala/actions/workflows/check-license.yaml)
|
||||
[](https://github.com/absmach/magistrala/actions/workflows/check-generated-files.yml)
|
||||
[](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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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")
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
//
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
},
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user