Compare commits

...

172 Commits

Author SHA1 Message Date
dusan ae28821707 Add edge PRD
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-08-07 18:31:25 +02:00
dusan e8cf13c7f3 NOISSUE - Update FMQ version
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-08-05 17:59:48 +02:00
Dušan Borovčanin 10791c1e28 NOISSUE - Preserve message origin (#3565) 2026-08-05 16:53:52 +02:00
Filip Bugarski d63bbe1f93 NOISSUE - Mark Rules Engine, Alarms, and Audit Logs as Enterprise Edition in README (#3562)
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 10:26:54 +02:00
dependabot[bot] f8fab301de NOISSUE - Bump the go-dependency group across 1 directory with 2 updates (#3560)
Continuous Delivery / lint-and-build (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-04 19:27:35 +02:00
Dušan Borovčanin 135490f680 NOISSUE - Use internal principals for services communication (#3564)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-08-04 19:20:44 +02:00
dusan dcd6e85afd Update compose and deployments
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-08-03 15:40:26 +02:00
dusan 0ba7994db9 Update FMQ version
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-08-01 14:00:45 +02:00
Dušan Borovčanin 880634e009 MG-3486 - RE Loop Prevention (#3559)
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-08-01 02:33:52 +02:00
Dušan Borovčanin 168e8b90cb NOISSUE - Move rules engine, alarms, reports, journal and notifications to EE (#3552)
Property Based Tests / api-test (push) Has been cancelled
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-07-30 17:55:57 +02:00
dependabot[bot] 6429f16233 Bump the go-dependency group with 3 updates (#3558)
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-27 09:03:43 +02:00
b1ackd0t d40757f36f NOISSUE - Reject empty username/password in gRPC early (#3554)
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: Rodney Osodo <socials@rodneyosodo.com>
2026-07-22 09:55:49 +02:00
dependabot[bot] c09020a29c Bump actions/setup-go from 6 to 7 in /.github/workflows in the gh-dependency group (#3553)
Property Based Tests / api-test (push) Has been cancelled
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: dusan <borovcanindusan1@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: dusan <borovcanindusan1@gmail.com>
2026-07-20 12:07:22 +02:00
dependabot[bot] 2320ec96c0 NOISSUE - Bump the go-dependency group across 1 directory with 5 updates (#3551)
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-18 18:54:18 +02:00
Filip Bugarski 14d6db9684 NOISSUE - Add multi-publisher filter to readers PageMetadata (#3550)
Property Based Tests / api-test (push) Has been cancelled
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: fbugarski <filipbugarski@gmail.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-16 11:04:56 +02:00
Arvindh 513a84361b NOISSUE - Remove unwanted alarms operations (#3548)
Property Based Tests / api-test (push) Has been cancelled
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: Arvindh <arvindh91@gmail.com>
2026-07-08 12:27:47 +02:00
Dušan Borovčanin 6ed7ca6a42 NOISSUE - Limit pdf-generator memory (#3547)
Continuous Delivery / lint-and-build (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-07-07 18:59:26 +02:00
Arvindh 52645e2c39 NOISSUE - Fix Alarms roles (#3546)
Property Based Tests / api-test (push) Has been cancelled
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: Arvindh <arvindh91@gmail.com>
2026-07-06 17:26:39 +02:00
dependabot[bot] e078e00f73 NOISSUE - Bump the go-dependency group across 1 directory with 4 updates (#3545)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-06 16:44:19 +02:00
dependabot[bot] c3b9c20cc0 NOISSUE - Bump golangci/golangci-lint-action from 9.2.1 to 9.3.0 in /.github/workflows in the gh-dependency group (#3542)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-06 16:37:53 +02:00
Arvindh 36fb079563 NOISSUE - Fix Alarms roles (#3544)
Signed-off-by: Arvindh <arvindh91@gmail.com>
2026-07-06 16:36:55 +02:00
Arvindh 4d20126e75 NOISSUE - Add messaging hooks endpoints (#3541)
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: Arvindh <arvindh91@gmail.com>
2026-07-04 19:33:46 +02:00
Dušan Borovčanin 09a56575c1 NOISSUE - Use Atom access tokens (#3540)
Property Based Tests / api-test (push) Has been cancelled
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-07-01 19:41:01 +02:00
Arvindh 3b5f646719 NOISSUE - Fix client keys (#3539)
Property Based Tests / api-test (push) Has been cancelled
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: Arvindh <arvindh91@gmail.com>
2026-06-30 20:10:33 +02:00
dusan ededf5308c Fix migrations
Continuous Delivery / lint-and-build (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-06-30 15:38:42 +02:00
dusan bc7c9096f9 NOISSUE - Improve migration scripts
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-06-30 13:50:43 +02:00
dusan c405028fc5 NOISSUE - Revert alarms approach
Continuous Delivery / lint-and-build (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Property Based Tests / api-test (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-06-29 19:16:16 +02:00
dusan cdc065a7b2 NOISSUE - Revert alarms Atom migration
This reverts commits afd2665c9c and 45c426c8bf.
2026-06-29 17:51:51 +02:00
dependabot[bot] 3cf6b2f0f4 NOISSUE - Bump the go-dependency group with 3 updates (#3538)
Property Based Tests / api-test (push) Has been cancelled
Continuous Delivery / lint-and-build (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-29 11:55:22 +02:00
dusan afd2665c9c NOISSUE - Simplify alarms
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-06-29 10:16:27 +02:00
dusan 45c426c8bf NOISSUE - Remove alarms
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-06-29 08:36:37 +02:00
Arvindh 16ba29cf4a MG-3537 - Migrate Magistrala to ATOM for identity & authorization (#3532)
Property Based Tests / api-test (push) Has been cancelled
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: Arvindh <arvindh91@gmail.com>
Signed-off-by: dusan <borovcanindusan1@gmail.com>
Signed-off-by: Rodney Osodo <socials@rodneyosodo.com>
Co-authored-by: Dušan Borovčanin <dusan.borovcanin@absmach.eu>
Co-authored-by: Rodney Osodo <socials@rodneyosodo.com>
Co-authored-by: dusan <borovcanindusan1@gmail.com>
2026-06-26 22:06:57 +02:00
dependabot[bot] 19ed0de788 NOISSUE - Bump github.com/opencontainers/runc from 1.2.8 to 1.3.6 (#3535)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-26 19:33:22 +02:00
dependabot[bot] 7efeb875de NOISSUE - Bump the go-dependency group across 1 directory with 4 updates (#3534)
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-23 10:03:31 +02:00
dusan 935a0950f9 NOISSUE - Fix Bootstrap rendering test
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-06-23 10:00:15 +02:00
dependabot[bot] d4f0d8fdef NOISSUE - Bump the go-dependency group across 1 directory with 3 updates (#3531)
Property Based Tests / api-test (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
Continuous Delivery / lint-and-build (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-19 17:13:43 +02:00
dependabot[bot] aaa718bdf6 Bump actions/checkout from 6 to 7 in /.github/workflows in the gh-dependency group across 1 directory (#3530)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-19 17:08:11 +02:00
dusan 91e010128d NOISSUE - Fix proto
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-06-19 16:52:13 +02:00
dependabot[bot] 5d7d3d412b NOISSUE - Bump github.com/slack-go/slack from 0.25.0 to 0.26.0 in the go-dependency group (#3529)
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-16 16:23:06 +02:00
dusan cb364d0426 NOISSUE - Update FluxMQ dependency
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-06-12 13:43:21 +02:00
dependabot[bot] b68c9fe79e NOISSUE - Bump the go-dependency group with 4 updates (#3528)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-12 13:22:02 +02:00
dusan 0d5048941e NOISSUE - Update FMQ version
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-06-09 16:04:42 +02:00
dependabot[bot] 24edbe6ad8 NOISSUE - Bump golang from 1.26.3-alpine3.22 to 1.26.4-alpine3.22 in /docker in the docker-dependency group (#3527)
Continuous Delivery / lint-and-build (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-09 16:04:04 +02:00
dependabot[bot] 610da72779 NOISSUE - Bump codecov/codecov-action from 6 to 7 in /.github/workflows in the gh-dependency group across 1 directory (#3525)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-09 15:57:55 +02:00
dependabot[bot] 90672e5fc7 NOISSUE - Bump the go-dependency group across 1 directory with 12 updates (#3526)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-09 15:39:54 +02:00
b1ackd0t 5821d2a513 NOISSUE - Sign server certificate with SANs for container hostnames (#3524)
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
Signed-off-by: Rodney Osodo <socials@rodneyosodo.com>
2026-06-03 13:40:34 +02:00
Dušan Borovčanin 49488738df NOISSUE - Fix queue subscriptions (#3522)
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-05-27 00:50:36 +02:00
dusan 493073ae49 NOISSUE - Update dependencies
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-05-25 11:17:47 +02:00
dependabot[bot] 5a528dd138 NOISSUE - Bump golangci/golangci-lint-action from 9.2.0 to 9.2.1 in /.github/workflows in the gh-dependency group (#3520)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Dušan Borovčanin <dusan.borovcanin@absmach.eu>
2026-05-25 10:40:30 +02:00
Steve Munene 377b8dfc08 MG-3509 - Add FluxMQ m stream queue to fix messages not appearing in web UI (#3518)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2026-05-25 10:28:40 +02:00
dependabot[bot] 03b33fee9e NOISSUE - Bump the go-dependency group with 5 updates (#3521)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-25 10:25:58 +02:00
dusan af75ac730c NOISSUE - Update FluxMQ version
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-05-22 12:51:20 +02:00
dusan 70d879275a NOISSUE - Improve certbot script
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-05-20 23:09:35 +02:00
Dušan Borovčanin 353e050a39 NOISSUE - Add a fast Certbot startup (#3517)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-05-20 19:23:19 +02:00
Steve Munene 683809dc6b NOISSUE - Update bootstrap content format, update profile method and add profile search (#3515)
Property Based Tests / api-test (push) Has been cancelled
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2026-05-19 09:02:45 +02:00
dependabot[bot] f380c8d360 NOISSUE - Bump the go-dependency group across 1 directory with 7 updates (#3516)
Continuous Delivery / lint-and-build (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 16:52:02 +02:00
Steve Munene 78804278d4 MG-3512 - Add rendered context field to update endpoint (#3513)
Property Based Tests / api-test (push) Has been cancelled
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2026-05-14 21:51:35 +02:00
dependabot[bot] 426532099a Bump golang from 1.26.2-alpine3.22 to 1.26.3-alpine3.22 in /docker in the docker-dependency group (#3511)
Continuous Delivery / lint-and-build (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-14 13:56:23 +02:00
Steve Munene 7f03134d8e NOISSUE - Update bootstrap and provision service (#3476)
Property Based Tests / api-test (push) Has been cancelled
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
Signed-off-by: JeffMboya <jangina.mboya@gmail.com>
Co-authored-by: JeffMboya <jangina.mboya@gmail.com>
2026-05-08 10:35:00 +02:00
dependabot[bot] f736bca7c1 Bump the go-dependency group with 7 updates (#3508)
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-05 12:39:13 +02:00
Arvindh d840aeb1b9 NOISSUE - Add migration scripts for Rules, Alarms and Reports (#3482)
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: Arvindh <arvindh91@gmail.com>
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
Co-authored-by: nyagamunene <stevenyaga2014@gmail.com>
2026-04-30 08:46:50 +02:00
Ian Ngethe Muchiri a0bc7c2108 NOISSUE - Update ui env variables and remove unused and repeated variables (#3507)
Continuous Delivery / lint-and-build (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
Signed-off-by: ianmuchyri <ianmuchiri8@gmail.com>
2026-04-29 12:46:39 +02:00
dependabot[bot] df242f6179 NOISSUE - Bump the go-dependency group with 3 updates (#3506)
Continuous Delivery / lint-and-build (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-28 12:34:32 +02:00
dependabot[bot] 3f256ddcf6 NOISSUE - Bump github.com/jackc/pgx/v5 from 5.9.1 to 5.9.2 in the go-dependency group (#3479)
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-20 09:51:44 +02:00
dependabot[bot] e294963450 NOISSUE - Bump the go-dependency group across 1 directory with 7 updates (#3477)
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-17 13:51:36 +02:00
JeffMboya 12180707d2 NOISSUE - Configure RE and reports billing callout (#3478)
Continuous Delivery / lint-and-build (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: JeffMboya <jangina.mboya@gmail.com>
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
Co-authored-by: nyagamunene <stevenyaga2014@gmail.com>
2026-04-17 13:34:44 +02:00
dependabot[bot] 68befa023c NOISSUE - Bump golang from 1.26.1-alpine3.22 to 1.26.2-alpine3.22 in /docker in the docker-dependency group (#3471)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-17 11:51:03 +02:00
Steve Munene dc72811048 NOISSUE - Update superadmin check (#3394)
Continuous Delivery / lint-and-build (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2026-04-16 18:08:14 +02:00
dependabot[bot] 92b2993366 NOISSUE - Bump github.com/authzed/spicedb from 1.51.0 to 1.51.1 (#3475)
Continuous Delivery / lint-and-build (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-16 10:53:31 +02:00
Steve Munene f3a7230cc0 NOISSUE - Add PAT support for rules and reports (#3466)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2026-04-16 10:01:03 +02:00
Steve Munene ac8dadefc6 NOISSUE - Fix refreshKey method (#3472)
Continuous Delivery / lint-and-build (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Property Based Tests / api-test (push) Has been cancelled
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2026-04-15 13:30:00 +02:00
dusan 3541ea8678 NOISSUE - Fix Docker publish error
Property Based Tests / api-test (push) Has been cancelled
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-04-08 22:41:41 +02:00
dusan 125e311eda NOISSUE - Fix token revoked erro on refresh
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-04-08 18:48:42 +02:00
Steve Munene c9bf5beba2 NOISSUE - Add missing role fields to re and reports (#3435)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2026-04-08 10:40:27 +02:00
dusan c5fc0b64d4 NOISSUE - Remove Make and UPX dependencies in build
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-04-07 13:29:05 +02:00
Arvindh 6c7e5d893d SMQ-3415 - Return correct error in auth gRPC response (#3416)
Signed-off-by: Arvindh <arvindh91@gmail.com>
2026-04-07 10:37:55 +02:00
dependabot[bot] 69d02ed58e NOISSUE - Bump the go-dependency group with 9 updates (#3434)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-07 10:37:22 +02:00
Dušan Borovčanin 3f329eb3c2 NOISSUE - Update CI scripts (#3433)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-04-07 10:33:04 +02:00
dusan b753294101 NOISSUE - Update README
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-04-07 09:36:17 +02:00
dusan 6dd470a41e NOISSUE - Update Docker CI
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-04-06 18:51:03 +02:00
Dušan Borovčanin 61d0427898 NOISSUE - Rename to Magistrala (#3427)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-04-06 15:23:42 +02:00
Dušan Borovčanin fc679e9982 NOISSUE - Use Github for Docker images (#3419)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-04-06 10:19:30 +02:00
Dušan Borovčanin 791e084de6 NOISSUE - Switch to / delimiter (#3424)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-04-03 18:37:00 +02:00
dependabot[bot] 6a3319828e NOISSUE - Bump github.com/go-jose/go-jose/v4 from 4.1.3 to 4.1.4 (#3425)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-03 14:47:47 +02:00
Steve Munene 5f230f9446 NOISSUE - Fix listing members for rule and reports methods (#3423)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2026-04-02 22:56:31 +02:00
dependabot[bot] 03893cf9e5 NOISSUE - Bump github.com/yuin/gopher-lua from 1.1.1 to 1.1.2 (#3422)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-02 14:10:04 +02:00
dependabot[bot] 560e90aa96 NOISSUE - Bump google.golang.org/grpc from 1.79.3 to 1.80.0 (#3421)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-02 12:41:06 +02:00
dependabot[bot] 2687a31ac2 NOISSUE - Bump the gh-dependency group with 3 updates (#3414)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-02 12:36:20 +02:00
dusan b70004500e NOISSUE - Update FMQ
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-04-02 12:14:22 +02:00
dependabot[bot] c336bf2bb6 NOISSUE - Bump github.com/nats-io/nats.go from 1.49.0 to 1.50.0 (#3407)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-02 12:14:18 +02:00
dependabot[bot] 74832cc081 NOISSUE - Bump github.com/plgd-dev/go-coap/v3 from 3.4.2 to 3.5.0 (#3408)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-02 12:12:19 +02:00
dependabot[bot] 468457c303 NOISSUE - Bump github.com/authzed/spicedb from 1.50.0 to 1.51.0 (#3409)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-02 12:11:56 +02:00
dependabot[bot] b062fb22ee NOISSUE - Bump github.com/slack-go/slack from 0.19.0 to 0.20.0 (#3413)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-02 12:11:42 +02:00
dependabot[bot] fad25c9092 NOISSUE - Bump github.com/lib/pq from 1.12.0 to 1.12.1 (#3412)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-02 12:11:26 +02:00
Arvindh 8e774b3398 NOISSUE - Add access control listing in alarms, rules engine and reports (#3417)
Signed-off-by: Arvindh <arvindh91@gmail.com>
2026-04-02 11:51:26 +02:00
dusan cc84466e7d NOISSUE - Fix refresh token
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-04-01 18:06:21 +02:00
dusan 351b25cd85 Add writers and alarms to the config
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-04-01 15:53:05 +02:00
Dušan Borovčanin ef5c253c51 SMQ-3399 - Unify Magistrala and SuperMQ (#3400)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
Signed-off-by: dusan <borovcanindusan1@gmail.com>
Co-authored-by: Steve Munene <stevenyaga2014@gmail.com>
2026-04-01 09:55:11 +02:00
dependabot[bot] 08249c045b NOISSUE - Bump github.com/authzed/spicedb from 1.49.2 to 1.50.0 (#3402)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-24 09:38:45 +01:00
dependabot[bot] e3be8d5f91 NOISSUE - Bump github.com/lib/pq from 1.11.2 to 1.12.0 (#3403)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-24 09:38:13 +01:00
dependabot[bot] cf7cd15a14 NOISSUE - Bump github.com/fatih/color from 1.18.0 to 1.19.0 (#3404)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-24 09:37:56 +01:00
dependabot[bot] 8f1ae9fd03 NOISSUE - Bump github.com/jackc/pgx/v5 from 5.8.0 to 5.9.1 (#3405)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-24 09:24:03 +01:00
dependabot[bot] 0f7ad10534 NOISSUE - Bump google.golang.org/grpc from 1.79.2 to 1.79.3 (#3398)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-20 13:13:32 +01:00
dusan fade98b84e NOISSUE - Update Certs
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-03-17 19:56:10 +01:00
dependabot[bot] 492965d379 NOISSUE - Bump golang.org/x/crypto from 0.48.0 to 0.49.0 (#3396)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-17 17:58:22 +01:00
dusan 6969fd2ce8 NOISSUE - Update Certs version
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-03-17 17:23:21 +01:00
dusan 9c6ad9744e NOISSUE - Fix fetching connected clients
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-03-11 17:25:47 +01:00
dusan df2446c2cc NOISSUE - Rename Admin to SuperAdmin role
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-03-11 16:52:34 +01:00
Ian Ngethe Muchiri 28ae84286e SMQ-416 - Return roles and actions in channel list for non-superadmin users (#3388)
Signed-off-by: ianmuchyri <ianmuchiri8@gmail.com>
2026-03-11 10:59:11 +01:00
Dušan Borovčanin 487dbbb44c NOISSUE - Fix refresh token bug (#3392)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-03-10 10:30:55 +01:00
dependabot[bot] ea3925e3e2 NOISSUE - Bump golang.org/x/oauth2 from 0.35.0 to 0.36.0 (#3389)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-09 18:06:06 +01:00
dependabot[bot] 3fc2dabf8a NOISSUE - Bump go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp from 0.66.0 to 0.67.0 (#3390)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-09 17:58:09 +01:00
dependabot[bot] e3902256ef NOISSUE - Bump golang.org/x/sync from 0.19.0 to 0.20.0 (#3391)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-09 17:57:48 +01:00
dependabot[bot] 215218495d NOISSUE - Bump go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc from 0.65.0 to 0.67.0 (#3383)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-09 17:38:35 +01:00
dependabot[bot] ff581b8736 NOISSUE - Bump golang from 1.26.0-alpine3.22 to 1.26.1-alpine3.22 in /docker in the docker-dependency group (#3381)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-09 17:33:55 +01:00
dependabot[bot] 4bd1694cd5 NOISSUE - Bump the gh-dependency group in /.github/workflows with 2 updates (#3387)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-09 17:33:35 +01:00
dependabot[bot] efba921328 NOISSUE - Bump go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp from 1.40.0 to 1.42.0 (#3385)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-09 17:31:34 +01:00
dependabot[bot] 373aab73ae NOISSUE - Bump go.opentelemetry.io/otel/sdk from 1.41.0 to 1.42.0 (#3386)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-09 11:37:16 +01:00
Dušan Borovčanin abd669c610 NOISSUE - Improve SQL queries performance and safety (#3378)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-03-06 11:09:40 +01:00
dependabot[bot] cef4b1d14d NOISSUE - Bump github.com/docker/cli from 27.4.1+incompatible to 29.2.0+incompatible (#3377)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-06 08:59:21 +01:00
Felix Gateru f8410b8940 SMQ-3338 - Add created at period filter to entities (#3339)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2026-03-04 12:37:35 +01:00
dependabot[bot] 2260293dfc NOISSUE - Bump go.opentelemetry.io/otel/exporters/otlp/otlptrace from 1.40.0 to 1.41.0 (#3374)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-03 15:32:32 +01:00
dependabot[bot] c9f34e3759 NOISSUE - Bump github.com/authzed/spicedb from 1.49.1 to 1.49.2 (#3372)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-03 15:31:41 +01:00
dependabot[bot] aeb1d9d0a1 NOISSUE - Bump go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp from 0.65.0 to 0.66.0 (#3371)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-03 15:29:25 +01:00
dependabot[bot] 03a8feb679 NOISSUE - Bump go.opentelemetry.io/otel/sdk from 1.40.0 to 1.41.0 (#3375)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-03 15:26:08 +01:00
Felix Gateru 9c2608659f SMQ-1672 - Revoke refresh token (#3241)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
Co-authored-by: nyagamunene <stevenyaga2014@gmail.com>
2026-03-03 15:22:28 +01:00
Steve Munene 2c476c17ee NOISSUE - Update tags filtering (#3376)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2026-03-03 15:14:02 +01:00
Dušan Borovčanin 3b2dd09ab4 NOISSUE - Update script dependencies (#3370)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-03-02 18:32:06 +01:00
dependabot[bot] 5255d887ef NOISSUE - Bump github.com/nats-io/nats.go from 1.48.0 to 1.49.0 (#3369)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-02 15:39:42 +01:00
dependabot[bot] bb8917cc34 NOISSUE - Bump golang from 1.25.7-alpine3.22 to 1.26.0-alpine3.22 in /docker in the docker-dependency group (#3367)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-02 11:23:24 +01:00
dependabot[bot] 4792a99c9a NOISSUE - Bump the gh-dependency group in /.github/workflows with 2 updates (#3368)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-02 11:19:44 +01:00
dusan fe49305238 Update dependencies version
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-03-02 11:17:34 +01:00
Steve Munene 03143d4142 NOISSUE - Add migrations for UI metadata (#3366)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2026-02-27 17:00:04 +01:00
Steve Munene 15a6c026e9 NOISSUE - Seperate PAT from policy (#3330)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
Signed-off-by: Arvindh <arvindh91@gmail.com>
Co-authored-by: Arvindh <arvindh91@gmail.com>
2026-02-26 16:35:47 +01:00
dependabot[bot] 175f0e08ab NOISSUE - Bump google.golang.org/grpc from 1.78.0 to 1.79.1 (#3355)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-26 10:10:57 +01:00
dependabot[bot] 41526634f8 NOISSUE - Bump github.com/redis/go-redis/v9 from 9.17.3 to 9.18.0 (#3356)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-26 10:09:57 +01:00
dependabot[bot] 73a640e646 NOISSUE - Bump github.com/lib/pq from 1.11.1 to 1.11.2 (#3358)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-26 10:07:51 +01:00
dependabot[bot] 6ca535155a NOISSUE - Bump github.com/caarlos0/env/v11 from 11.3.1 to 11.4.0 (#3363)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-25 14:19:03 +01:00
dependabot[bot] 4a449629b3 NOISUE - Bump github.com/authzed/authzed-go from 1.7.0 to 1.8.0 (#3362)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-24 09:02:40 +01:00
dependabot[bot] 1cd00fbd83 NOISSUE - Bump github.com/pion/dtls/v3 from 3.1.1 to 3.1.2 (#3357)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-23 16:29:10 +01:00
Felix Gateru a871fa926e SMQ-3361 - Enable TLS and mTLS termination on MQTT adapter (#3360)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2026-02-23 16:14:31 +01:00
dependabot[bot] c7fad0d2ca Bump github.com/pion/dtls/v3 from 3.1.0 to 3.1.1 (#3351)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-16 19:47:31 +01:00
dependabot[bot] 51e782693d NOISSUE - Bump github.com/pion/dtls/v3 from 3.0.10 to 3.1.0 (#3350)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-12 14:53:31 +01:00
Dušan Borovčanin e3a3e052d2 NOISSUE - Use the latest stable Go version instead of RC (#3349)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-02-10 13:12:46 +01:00
dependabot[bot] 1e8437cfc2 NOISSUE - Bump github.com/authzed/spicedb from 1.48.0 to 1.49.1 (#3347)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-10 12:51:10 +01:00
dependabot[bot] f8f4ccac79 NOISSUE - Bump golang.org/x/crypto from 0.47.0 to 0.48.0 (#3348)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-10 12:29:04 +01:00
dependabot[bot] 56bb07273d NOISSUE - Bump github.com/go-chi/chi/v5 from 5.2.4 to 5.2.5 (#3344)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Dušan Borovčanin <borovcanindusan1@gmail.com>
2026-02-09 17:48:37 +01:00
dependabot[bot] aba4d6a0b7 NOISSUE - Bump go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp from 0.64.0 to 0.65.0 (#3345)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-09 17:47:29 +01:00
dependabot[bot] b948edc573 Bump golang.org/x/oauth2 from 0.34.0 to 0.35.0 (#3346)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-09 12:26:38 +01:00
Arvindh 20bafe0077 NOISSUE - Fix Invitations and remove Domain check in AuthZ (#3340)
Signed-off-by: Arvindh <arvindh91@gmail.com>
2026-02-04 20:56:41 +01:00
Felix Gateru 4e77ae65e2 SMQ-2875 - Add listing entities by multiple tag values with support for AND/OR conditions (#3154)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2026-02-04 17:13:48 +01:00
Steve Munene 61c120f947 SMQ-2627 - Align PATs with new architecture (#3295)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2026-02-03 14:06:30 +01:00
dependabot[bot] 0d4f4c9266 NOISSUE - Bump go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc from 0.64.0 to 0.65.0 (#3334)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-03 11:42:55 +01:00
dependabot[bot] 668338dfa2 NOISSUE - Bump go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp from 1.39.0 to 1.40.0 (#3335)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-03 11:41:17 +01:00
dependabot[bot] 38ea004e30 NOISSUE - Bump go.opentelemetry.io/otel/sdk from 1.39.0 to 1.40.0 (#3337)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-03 11:30:51 +01:00
dependabot[bot] 7b99baeb02 NOISSUE - Bump github.com/lib/pq from 1.10.9 to 1.11.1 (#3331)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-02 15:06:31 +01:00
Steve Munene cd31b1c6bd NOISSUE - Refactor makefile (#3318)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
Signed-off-by: dorcaslitunya <anonolitunya@gmail.com>
Co-authored-by: dorcaslitunya <anonolitunya@gmail.com>
2026-01-29 09:50:15 +01:00
dependabot[bot] 1a348b11dd NOISSUE - Bump github.com/dgraph-io/ristretto/v2 from 2.3.0 to 2.4.0 (#3324)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-27 13:57:19 +01:00
dependabot[bot] f552e08661 NOISSUE - Bump github.com/redis/go-redis/v9 from 9.17.2 to 9.17.3 (#3325)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-27 12:17:45 +01:00
dependabot[bot] 5606cdbe47 NOISSUE - Bump github.com/plgd-dev/go-coap/v3 from 3.4.1 to 3.4.2 (#3326)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-27 12:00:39 +01:00
Felix Gateru 59d9f91813 NOISSUE - Remove public metadata, introduce private metadata (#3322)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2026-01-23 14:42:54 +01:00
Felix Gateru 5b913dd46b SMQ-3108 - Add support for public and private metadata for users and clients (#3155)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2026-01-22 08:55:25 +01:00
Steve Munene 9293de7636 NOISSUE - Fix certs network (#3321)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2026-01-21 14:06:55 +01:00
Steve Munene 2dd8c44aa3 NOISSUE - Fix certs override file (#3317)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2026-01-21 09:40:54 +01:00
Felix Gateru 28fc9738df SMQ-3303 - Update API schema request bodies (#3309)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2026-01-19 12:10:46 +01:00
Steve Munene ad1d67a678 NOISSUE - Fetch certs (#3316)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2026-01-19 11:38:20 +01:00
dependabot[bot] 1086f3e208 NOISSUE - Bump golang.org/x/crypto from 0.46.0 to 0.47.0 (#3308)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-19 09:59:59 +01:00
dependabot[bot] b896c03f5f NOISSUE - Bump golang from 1.25.5-alpine3.22 to 1.26rc2-alpine3.22 in /docker in the docker-dependency group (#3314)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-19 09:38:40 +01:00
dependabot[bot] d78c1e8d20 NOISSUE - Bump github.com/go-chi/chi/v5 from 5.2.3 to 5.2.4 (#3315)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-19 09:38:11 +01:00
Felix Gateru 551d44d58e NOISSUE - Fix publisher id on message published by user (#3312)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2026-01-15 17:34:11 +01:00
Felix Gateru 927230dbb4 NOISSUE - Allow superadmin to send messages over channel (#3310)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2026-01-14 18:38:44 +01:00
dependabot[bot] c7996ce6cf NOISSUE - Bump github.com/pion/dtls/v3 from 3.0.9 to 3.0.10 (#3307)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-12 08:52:20 +01:00
1061 changed files with 62355 additions and 170845 deletions
+1 -1
View File
@@ -1 +1 @@
* @absmach/supermq
* @absmach/magistrala
+2 -2
View File
@@ -5,7 +5,7 @@ blank_issues_enabled: false
contact_links:
- name: Google group
url: https://groups.google.com/forum/#!forum/mainflux
about: Join the SuperMQ community on Google group.
about: Join the Magistrala community on Google group.
- name: Gitter
url: https://gitter.im/mainflux/mainflux
about: Join the SuperMQ community on Gitter.
about: Join the Magistrala community on Gitter.
+2 -2
View File
@@ -3,8 +3,8 @@ SPDX-License-Identifier: Apache-2.0 -->
<!--
Pull request title should be `SMQ-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/supermq/blob/main/CONTRIBUTING.md) file for detailed contributing guidelines.
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/main/CONTRIBUTING.md) 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.
@@ -5,9 +5,11 @@ version: 2
updates:
- package-ecosystem: "github-actions"
directory: "./.github/workflows"
target-branch: "main"
schedule:
interval: "monthly"
interval: "weekly"
day: "monday"
time: "06:00"
timezone: "Europe/Paris"
groups:
gh-dependency:
@@ -16,16 +18,24 @@ updates:
- package-ecosystem: "gomod"
directory: "/"
target-branch: "main"
schedule:
interval: "weekly"
day: "monday"
time: "06:15"
timezone: "Europe/Paris"
groups:
go-dependency:
patterns:
- "*"
- package-ecosystem: "docker"
directory: "./docker"
directory: "/docker"
target-branch: "main"
schedule:
interval: "monthly"
interval: "weekly"
day: "monday"
time: "06:30"
timezone: "Europe/Paris"
groups:
docker-dependency:
+2 -2
View File
@@ -7,7 +7,7 @@ SPDX-License-Identifier: Apache-2.0
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SuperMQ API Documentation</title>
<title>Magistrala API Documentation</title>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.30.3/swagger-ui.css">
<style>
body {
@@ -101,7 +101,7 @@ SPDX-License-Identifier: Apache-2.0
</head>
<body>
<div class="service-selector">
<h1>SuperMQ API Documentation</h1>
<h1>Magistrala API Documentation</h1>
<div class="service-dropdown-container">
<label for="serviceDropdown">Select Service:</label>
<select id="serviceDropdown" class="service-dropdown"></select>
+104 -79
View File
@@ -10,14 +10,15 @@ on:
paths:
- ".github/workflows/api-tests.yaml"
- "api/**"
- "auth/api/http/**"
- "internal/atom/**"
- "channels/api/http/**"
- "clients/api/http/**"
- "domains/api/http/**"
- "groups/api/http/**"
- "http/api/**"
- "journal/api/**"
- "users/api/**"
- "bootstrap/api/**"
- "certs/api/http/**"
- "readers/api/http/**"
- "apidocs/openapi/**"
pull_request:
branches:
@@ -25,14 +26,15 @@ on:
paths:
- ".github/workflows/api-tests.yaml"
- "api/**"
- "auth/api/http/**"
- "internal/atom/**"
- "channels/api/http/**"
- "clients/api/http/**"
- "domains/api/http/**"
- "groups/api/http/**"
- "http/api/**"
- "journal/api/**"
- "users/api/**"
- "bootstrap/api/**"
- "certs/api/http/**"
- "readers/api/http/**"
- "apidocs/openapi/**"
concurrency:
@@ -40,84 +42,87 @@ concurrency:
cancel-in-progress: true
env:
TOKENS_URL: http://localhost:9002/users/tokens/issue
CREATE_DOMAINS_URL: http://localhost:9003/domains
USER_IDENTITY: admin@example.com
ATOM_LOGIN_URL: http://localhost/auth/login
USER_IDENTITY: admin
USER_SECRET: 12345678
DOMAIN_NAME: demo-test
USERS_URL: http://localhost:9002
DOMAIN_URL: http://localhost:9003
CLIENTS_URL: http://localhost:9006
CHANNELS_URL: http://localhost:9005
GROUPS_URL: http://localhost:9004
HTTP_ADAPTER_URL: http://localhost:8008
AUTH_URL: http://localhost:9001
JOURNAL_URL: http://localhost:9021
USERS_URL: http://localhost
DOMAIN_URL: http://localhost
CLIENTS_URL: http://localhost
CHANNELS_URL: http://localhost
GROUPS_URL: http://localhost
BOOTSTRAP_URL: http://localhost:9013
CERTS_URL: http://localhost:9019
READERS_URL: http://localhost:9011
jobs:
api-test:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Get Go version from go.mod
id: go-version
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
- name: Install Go
uses: actions/setup-go@v6
uses: actions/setup-go@v7
with:
go-version: ${{ steps.go-version.outputs.version }}
go-version-file: go.mod
cache-dependency-path: "go.sum"
- name: Check for changes in specific paths
uses: dorny/paths-filter@v3
uses: dorny/paths-filter@v4
id: changes
with:
filters: |
workflow:
- ".github/workflows/api-tests.yaml"
journal:
- "apidocs/openapi/journal.yaml"
- "journal/api/**"
auth:
- "apidocs/openapi/auth.yaml"
- "auth/api/http/**"
domains:
- "apidocs/openapi/domains.yaml"
- "internal/atom/**"
- "domains/api/http/**"
http:
- "apidocs/openapi/http.yaml"
- "http/api/**"
clients:
- "apidocs/openapi/clients.yaml"
- "internal/atom/**"
- "clients/api/http/**"
channels:
- "apidocs/openapi/channels.yaml"
- "internal/atom/**"
- "channels/api/http/**"
groups:
- "apidocs/openapi/groups.yaml"
- "internal/atom/**"
- "groups/api/http/**"
users:
- "apidocs/openapi/users.yaml"
- "internal/atom/**"
- "users/api/**"
bootstrap:
- "apidocs/openapi/bootstrap.yaml"
- "bootstrap/api/**"
certs:
- "apidocs/openapi/certs.yaml"
- "certs/api/http/**"
readers:
- "apidocs/openapi/readers.yaml"
- "readers/api/http/**"
- name: Build images
run: make all -j $(nproc) && make dockers_dev -j $(nproc)
- name: Provision Atom service tokens
run: make provision_atom_tokens
- name: Start containers
run: make run_latest up args="-d" && make run_addons up args="-d"
run: make run_latest_ci up args="-d" && make run_addons up args="-d"
- name: Wait for services to be ready
run: |
@@ -126,94 +131,114 @@ jobs:
# Check if services are responding
for i in {1..30}; do
if curl -f -s http://localhost:9002/health > /dev/null 2>&1; then
if curl -f -s http://localhost/health > /dev/null 2>&1; then
echo "Services are ready!"
break
exit 0
fi
echo "Waiting for services... ($i/30)"
sleep 2
done
echo "Services failed to become ready" >&2
docker compose -f docker/docker-compose.yaml -f docker/docker-compose-ci.yaml --env-file docker/.env --env-file docker/.env.tokens -p "${USER_REPO:-absmach_magistrala}" ps || true
docker logs --tail 100 magistrala-nginx || true
docker logs --tail 100 magistrala-atom || true
docker logs --tail 100 magistrala-atom-bootstrap || true
exit 1
- name: Set access token
run: |
export USER_TOKEN=$(curl -sSX POST $TOKENS_URL -H "Content-Type: application/json" -d "{\"identity\": \"$USER_IDENTITY\",\"secret\": \"$USER_SECRET\"}" | jq -r .access_token)
export DOMAIN_ID=$(curl -sSX POST $CREATE_DOMAINS_URL -H "Content-Type: application/json" -H "Authorization: Bearer $USER_TOKEN" -d "{\"name\":\"$DOMAIN_NAME\",\"route\":\"$DOMAIN_NAME\"}" | jq -r .id)
export USER_TOKEN=$(curl -fsS -X POST "$ATOM_LOGIN_URL" -H "Content-Type: application/json" -d "{\"identifier\":\"$USER_IDENTITY\",\"secret\":\"$USER_SECRET\",\"kind\":\"password\"}" | jq -er .token)
echo "USER_TOKEN=$USER_TOKEN" >> $GITHUB_ENV
export CLIENT_SECRET=$(supermq-cli provision test | /usr/bin/grep -Eo '"secret": "[^"]+"' | awk 'NR % 2 == 0' | sed 's/"secret": "\(.*\)"/\1/')
echo "CLIENT_SECRET=$CLIENT_SECRET" >> $GITHUB_ENV
- name: Run Users API tests
if: steps.changes.outputs.users == 'true' || steps.changes.outputs.workflow == 'true'
uses: schemathesis/action@v2.1.0
if: (steps.changes.outputs.users == 'true' || steps.changes.outputs.workflow == 'true') && hashFiles('users/api/**') != ''
uses: schemathesis/action@v3.0.0
with:
schema: apidocs/openapi/users.yaml
base-url: ${{ env.USERS_URL }}
checks: all
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --exclude-operation-id=requestPasswordReset --phases=examples,stateful'
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --exclude-operation-id=requestPasswordReset --phases=examples'
coverage-artifact-name: schema-coverage-users
coverage-pr-comment: false
- name: Run Groups API tests
if: steps.changes.outputs.groups == 'true' || steps.changes.outputs.workflow == 'true'
uses: schemathesis/action@v2.1.0
if: (steps.changes.outputs.groups == 'true' || steps.changes.outputs.workflow == 'true') && hashFiles('groups/api/http/**') != ''
uses: schemathesis/action@v3.0.0
with:
schema: apidocs/openapi/groups.yaml
base-url: ${{ env.GROUPS_URL }}
checks: all
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --phases=examples'
coverage-artifact-name: schema-coverage-groups
coverage-pr-comment: false
- name: Run Clients API tests
if: steps.changes.outputs.clients == 'true' || steps.changes.outputs.workflow == 'true'
uses: schemathesis/action@v2.1.0
if: (steps.changes.outputs.clients == 'true' || steps.changes.outputs.workflow == 'true') && hashFiles('clients/api/http/**') != ''
uses: schemathesis/action@v3.0.0
with:
schema: apidocs/openapi/clients.yaml
base-url: ${{ env.CLIENTS_URL }}
checks: all
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --phases=examples'
coverage-artifact-name: schema-coverage-clients
coverage-pr-comment: false
- name: Run Channels API tests
if: steps.changes.outputs.channels == 'true' || steps.changes.outputs.workflow == 'true'
uses: schemathesis/action@v2.1.0
if: (steps.changes.outputs.channels == 'true' || steps.changes.outputs.workflow == 'true') && hashFiles('channels/api/http/**') != ''
uses: schemathesis/action@v3.0.0
with:
schema: apidocs/openapi/channels.yaml
base-url: ${{ env.CHANNELS_URL }}
checks: all
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --phases=examples'
- name: Run HTTP Adapter API tests
if: steps.changes.outputs.http == 'true' || steps.changes.outputs.workflow == 'true'
uses: schemathesis/action@v2.1.0
with:
schema: apidocs/openapi/http.yaml
base-url: ${{ env.HTTP_ADAPTER_URL }}
checks: all
args: '--header "Authorization: Client ${{ env.CLIENT_SECRET }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --phases=examples'
- name: Run Auth API tests
if: steps.changes.outputs.auth == 'true' || steps.changes.outputs.workflow == 'true'
uses: schemathesis/action@v2.1.0
with:
schema: apidocs/openapi/auth.yaml
base-url: ${{ env.AUTH_URL }}
checks: all
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --phases=examples'
coverage-artifact-name: schema-coverage-channels
coverage-pr-comment: false
- name: Run Domains API tests
if: steps.changes.outputs.domains == 'true' || steps.changes.outputs.workflow == 'true'
uses: schemathesis/action@v2.1.0
if: (steps.changes.outputs.domains == 'true' || steps.changes.outputs.workflow == 'true') && hashFiles('domains/api/http/**') != ''
uses: schemathesis/action@v3.0.0
with:
schema: apidocs/openapi/domains.yaml
base-url: ${{ env.DOMAIN_URL }}
checks: all
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --phases=examples'
coverage-artifact-name: schema-coverage-domains
coverage-pr-comment: false
- name: Run Journal API tests
if: steps.changes.outputs.journal == 'true' || steps.changes.outputs.workflow == 'true'
uses: schemathesis/action@v2.1.0
- name: Run Bootstrap API tests
if: (steps.changes.outputs.bootstrap == 'true' || steps.changes.outputs.workflow == 'true') && hashFiles('bootstrap/api/**') != ''
uses: schemathesis/action@v3.0.0
with:
schema: apidocs/openapi/journal.yaml
base-url: ${{ env.JOURNAL_URL }}
schema: apidocs/openapi/bootstrap.yaml
base-url: ${{ env.BOOTSTRAP_URL }}
checks: all
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --phases=examples'
coverage-artifact-name: schema-coverage-bootstrap
coverage-pr-comment: false
- name: Run Certs API tests
if: (steps.changes.outputs.certs == 'true' || steps.changes.outputs.workflow == 'true') && hashFiles('docker/addons/certs/docker-compose.yaml') != ''
uses: schemathesis/action@v3.0.0
with:
schema: apidocs/openapi/certs.yaml
base-url: ${{ env.CERTS_URL }}
checks: all
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --phases=examples'
coverage-artifact-name: schema-coverage-certs
coverage-pr-comment: false
- name: Run Readers API tests
if: steps.changes.outputs.readers == 'true' || steps.changes.outputs.workflow == 'true'
uses: schemathesis/action@v3.0.0
with:
schema: apidocs/openapi/readers.yaml
base-url: ${{ env.READERS_URL }}
checks: all
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --phases=examples'
coverage-artifact-name: schema-coverage-readers
coverage-pr-comment: false
- name: Stop containers
if: always()
run: make run_latest down args="-v" && make run_addons down args="-v"
run: make run_latest_ci down args="-v" && make run_addons down args="-v"
+16 -20
View File
@@ -8,12 +8,12 @@ on:
branches:
- main
paths-ignore:
- '**.md'
- 'docs/**'
- '.github/workflows/**'
- 'LICENSE'
- 'MAINTAINERS'
- 'CODEOWNERS'
- "**/*.md"
- "docs/**"
- ".github/workflows/**"
- "LICENSE"
- "MAINTAINERS"
- "CODEOWNERS"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -29,35 +29,31 @@ jobs:
needs: [lint-and-build]
permissions:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
fetch-tags: true
- name: Get Go version from go.mod
id: go-version
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
- name: Setup Go
uses: actions/setup-go@v6
uses: actions/setup-go@v7
with:
go-version: ${{ steps.go-version.outputs.version }}
go-version-file: go.mod
cache-dependency-path: "go.sum"
- name: Set up Docker Build
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
- name: Login to DockerHub
uses: docker/login-action@v3
- name: Login to GHCR
uses: docker/login-action@v4
with:
registry: docker.io
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Docker images
run: |
make latest -j $(nproc)
+8 -12
View File
@@ -12,21 +12,17 @@ jobs:
check-generated-files:
runs-on: ubuntu-latest
env:
PROTOC_VERSION: "33.0"
PROTOC_GEN_GO_VERSION: "v1.36.10"
PROTOC_GEN_GO_GRPC_VERSION: "v1.5.1"
PROTOC_VERSION: "35.1"
PROTOC_GEN_GO_VERSION: "v1.36.11"
PROTOC_GEN_GO_GRPC_VERSION: "v1.6.2"
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Get Go version from go.mod
id: go-version
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
uses: actions/checkout@v7
- name: Install Go
uses: actions/setup-go@v6
uses: actions/setup-go@v7
with:
go-version: ${{ steps.go-version.outputs.version }}
go-version-file: go.mod
cache-dependency-path: "go.sum"
- name: Set GOBIN
@@ -41,7 +37,7 @@ jobs:
git diff --exit-code
- name: Check for changes in specific paths
uses: dorny/paths-filter@v3
uses: dorny/paths-filter@v4
id: changes
with:
base: main
@@ -54,6 +50,7 @@ jobs:
- "pkg/messaging/*.pb.go"
mocks:
- "tools/config/.mockery.yaml"
- ".github/workflows/check-generated-files.yaml"
- "pkg/sdk/sdk.go"
- "users/postgres/clients.go"
@@ -71,7 +68,6 @@ jobs:
- "pkg/groups/groups.go"
- "users/emailer.go"
- "users/hasher.go"
- "journal/journal.go"
- "consumers/notifier.go"
- name: Install Protoc
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Check License Header
run: |
+14 -37
View File
@@ -12,22 +12,18 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Get Go version from go.mod
id: go-version
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
uses: actions/checkout@v7
- name: Setup Go
uses: actions/setup-go@v6
uses: actions/setup-go@v7
with:
go-version: ${{ steps.go-version.outputs.version }}
go-version-file: go.mod
cache-dependency-path: "go.sum"
- name: Run linters
uses: golangci/golangci-lint-action@v9
uses: golangci/golangci-lint-action@v9.3.0
with:
version: v2.7.2
version: v2.10.1
args: --config ./tools/config/.golangci.yaml
build:
@@ -36,16 +32,12 @@ jobs:
needs: lint
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Get Go version from go.mod
id: go-version
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
uses: actions/checkout@v7
- name: Setup Go
uses: actions/setup-go@v6
uses: actions/setup-go@v7
with:
go-version: ${{ steps.go-version.outputs.version }}
go-version-file: go.mod
cache-dependency-path: "go.sum"
- name: Build all binaries
@@ -53,34 +45,19 @@ jobs:
make all -j $(nproc)
compile-check:
name: Compile Check ${{ matrix.variant.name }}
name: Compile Check Redis Event Store
runs-on: ubuntu-latest
needs: lint
strategy:
fail-fast: true
matrix:
variant:
- name: rabbitmq
env: SMQ_MESSAGE_BROKER_TYPE=msg_rabbitmq
target: mqtt
- name: redis
env: SMQ_ES_TYPE=es_redis
target: mqtt
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Get Go version from go.mod
id: go-version
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
uses: actions/checkout@v7
- name: Setup Go
uses: actions/setup-go@v6
uses: actions/setup-go@v7
with:
go-version: ${{ steps.go-version.outputs.version }}
go-version-file: go.mod
cache-dependency-path: "go.sum"
- name: Compile check for ${{ matrix.variant.name }}
- name: Compile check
run: |
${{ matrix.variant.env }} make ${{ matrix.variant.target }}
MG_ES_TYPE=es_redis make all -j $(nproc)
+2 -2
View File
@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Build Swagger UI
run: |
@@ -42,4 +42,4 @@ jobs:
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./swagger-ui
cname: docs.api.supermq.absmach.eu
cname: docs.api.magistrala.absmach.eu
+52 -125
View File
@@ -8,7 +8,7 @@ on:
branches:
- main
paths-ignore:
- '**.md'
- '**/*.md'
- 'docs/**'
- 'LICENSE'
- 'MAINTAINERS'
@@ -22,39 +22,17 @@ concurrency:
cancel-in-progress: true
jobs:
check-certs:
name: Check Certs
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v6
- name: Fetch Certs
run: |
make fetch_certs
if [[ -n $(git status --porcelain docker/addons/certs) ]]; then
echo "Certs docker file is not up to date. Please update it"
git diff docker/addons/certs
exit 1
else
exit 0
fi
lint-proto:
name: Lint Proto
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v6
- name: Get Go version from go.mod
id: go-version
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
uses: actions/checkout@v7
- name: Setup Go
uses: actions/setup-go@v6
uses: actions/setup-go@v7
with:
go-version: ${{ steps.go-version.outputs.version }}
go-version-file: go.mod
cache-dependency-path: "go.sum"
- name: Install protolint
@@ -66,46 +44,30 @@ jobs:
protolint .
lint-and-build:
needs: [check-certs, lint-proto]
needs: [lint-proto]
uses: ./.github/workflows/lint-and-build.yaml
detect-changes:
name: Detect Changes
runs-on: ubuntu-latest
outputs:
modules: ${{ steps.set-matrix.outputs.modules }}
workflow_changed: ${{ steps.changes.outputs.workflow }}
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Check for changes in specific paths
uses: dorny/paths-filter@v3
uses: dorny/paths-filter@v4
id: changes
with:
filters: |
workflow:
- ".github/workflows/tests.yaml"
auth:
- "auth/**"
- "cmd/auth/**"
- "auth.proto"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "pkg/ulid/**"
- "pkg/uuid/**"
channels:
- "channels/**"
- "cmd/channels/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "auth/**"
- "pkg/sdk/**"
- "clients/api/grpc/**"
- "groups/api/grpc/**"
@@ -119,10 +81,6 @@ jobs:
clients:
- "clients/**"
- "cmd/clients/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "auth/**"
- "pkg/ulid/**"
- "pkg/uuid/**"
- "pkg/events/**"
@@ -131,28 +89,12 @@ jobs:
- "domains/api/grpc/**"
- "internal/grpc/**"
coap:
- "coap/**"
- "cmd/coap/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "clients/**"
- "pkg/messaging/**"
domains:
- "domains/**"
- "cmd/domains/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "auth/**"
- "internal/grpc/**"
groups:
- "groups/**"
- "cmd/groups/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "auth/**"
- "pkg/ulid/**"
- "pkg/uuid/**"
- "clients/api/grpc/**"
@@ -160,38 +102,24 @@ jobs:
- "domains/api/grpc/**"
- "internal/grpc/**"
http:
- "http/**"
- "cmd/http/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "clients/**"
- "pkg/messaging/**"
- "logger/**"
internal:
- "internal/**"
journal:
- "journal/**"
- "cmd/journal/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "auth/**"
- "pkg/events/**"
logger:
- "logger/**"
mqtt:
- "mqtt/**"
- "cmd/mqtt/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "clients/**"
- "pkg/messaging/**"
- "logger/**"
- "pkg/events/**"
pkg-atom:
- "pkg/atom/**"
pkg-email:
- "pkg/email/**"
- "pkg/emailer/**"
pkg-readersclient:
- "pkg/readersclient/**"
pkg-testsutil:
- "pkg/testsutil/**"
pkg-errors:
- "pkg/errors/**"
@@ -210,15 +138,12 @@ jobs:
- "pkg/sdk/**"
- "pkg/errors/**"
- "pkg/groups/**"
- "auth/**"
- "http/**"
- "internal/*"
- "clients/**"
- "users/**"
- "channels/**"
- "domains/**"
- "groups/**"
- "journal/**"
- "api/http/**"
pkg-transformers:
@@ -232,63 +157,55 @@ jobs:
users:
- "users/**"
- "cmd/users/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "auth/**"
- "pkg/ulid/**"
- "pkg/uuid/**"
- "pkg/events/**"
notifications:
- "notifications/**"
- "cmd/notifications/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "consumers/notifier.go"
- "pkg/events/**"
api:
- "api/**"
consumers:
- "consumers/**"
- "cmd/postgres-writer/**"
- "cmd/timescale-writer/**"
- "cmd/smpp-notifier/**"
- "cmd/smtp-notifier/**"
readers:
- "readers/**"
- "cmd/postgres-reader/**"
- "cmd/timescale-reader/**"
- name: Set matrix for changed modules
id: set-matrix
run: |
modules=()
if [[ "${{ steps.changes.outputs.workflow }}" == "true" || "${{ steps.changes.outputs.pkg-errors }}" == "true" ]]; then
# If workflow or pkg/errors changed, test everything
modules=("auth" "channels" "cli" "clients" "coap" "domains" "groups" "http" "internal" "journal" "logger" "mqtt" "pkg-errors" "pkg-events" "pkg-grpcclient" "pkg-messaging" "pkg-sdk" "pkg-transformers" "pkg-ulid" "pkg-uuid" "users" "notifications" "api" "consumers" "readers")
if [[ "${{ steps.changes.outputs.workflow }}" == "true" || "${{ steps.changes.outputs.pkg-errors }}" == "true" || "${{ steps.changes.outputs.pkg-testsutil }}" == "true" ]]; then
# If workflow, shared errors, or test utilities changed, test everything
modules=("auth" "channels" "cli" "clients" "domains" "groups" "internal" "logger" "pkg-atom" "pkg-email" "pkg-errors" "pkg-events" "pkg-grpcclient" "pkg-messaging" "pkg-readersclient" "pkg-sdk" "pkg-testsutil" "pkg-transformers" "pkg-ulid" "pkg-uuid" "users" "api" "consumers" "readers")
else
# Add only changed modules
[[ "${{ steps.changes.outputs.auth }}" == "true" ]] && modules+=("auth")
[[ "${{ steps.changes.outputs.channels }}" == "true" ]] && modules+=("channels")
[[ "${{ steps.changes.outputs.cli }}" == "true" ]] && modules+=("cli")
[[ "${{ steps.changes.outputs.clients }}" == "true" ]] && modules+=("clients")
[[ "${{ steps.changes.outputs.coap }}" == "true" ]] && modules+=("coap")
[[ "${{ steps.changes.outputs.domains }}" == "true" ]] && modules+=("domains")
[[ "${{ steps.changes.outputs.groups }}" == "true" ]] && modules+=("groups")
[[ "${{ steps.changes.outputs.http }}" == "true" ]] && modules+=("http")
[[ "${{ steps.changes.outputs.internal }}" == "true" ]] && modules+=("internal")
[[ "${{ steps.changes.outputs.journal }}" == "true" ]] && modules+=("journal")
[[ "${{ steps.changes.outputs.logger }}" == "true" ]] && modules+=("logger")
[[ "${{ steps.changes.outputs.mqtt }}" == "true" ]] && modules+=("mqtt")
[[ "${{ steps.changes.outputs.pkg-atom }}" == "true" ]] && modules+=("pkg-atom")
[[ "${{ steps.changes.outputs.pkg-email }}" == "true" ]] && modules+=("pkg-email")
[[ "${{ steps.changes.outputs.pkg-errors }}" == "true" ]] && modules+=("pkg-errors")
[[ "${{ steps.changes.outputs.pkg-events }}" == "true" ]] && modules+=("pkg-events")
[[ "${{ steps.changes.outputs.pkg-grpcclient }}" == "true" ]] && modules+=("pkg-grpcclient")
[[ "${{ steps.changes.outputs.pkg-messaging }}" == "true" ]] && modules+=("pkg-messaging")
[[ "${{ steps.changes.outputs.pkg-readersclient }}" == "true" ]] && modules+=("pkg-readersclient")
[[ "${{ steps.changes.outputs.pkg-sdk }}" == "true" ]] && modules+=("pkg-sdk")
[[ "${{ steps.changes.outputs.pkg-transformers }}" == "true" ]] && modules+=("pkg-transformers")
[[ "${{ steps.changes.outputs.pkg-ulid }}" == "true" ]] && modules+=("pkg-ulid")
[[ "${{ steps.changes.outputs.pkg-uuid }}" == "true" ]] && modules+=("pkg-uuid")
[[ "${{ steps.changes.outputs.users }}" == "true" ]] && modules+=("users")
[[ "${{ steps.changes.outputs.notifications }}" == "true" ]] && modules+=("notifications")
[[ "${{ steps.changes.outputs.api }}" == "true" ]] && modules+=("api")
[[ "${{ steps.changes.outputs.consumers }}" == "true" ]] && modules+=("consumers")
[[ "${{ steps.changes.outputs.readers }}" == "true" ]] && modules+=("readers")
@@ -312,16 +229,12 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Get Go version from go.mod
id: go-version
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
uses: actions/checkout@v7
- name: Setup Go
uses: actions/setup-go@v6
uses: actions/setup-go@v7
with:
go-version: ${{ steps.go-version.outputs.version }}
go-version-file: go.mod
cache-dependency-path: "go.sum"
- name: Verify dependencies
@@ -333,21 +246,35 @@ jobs:
run: |
# Map module names to directories
case "${{ matrix.module }}" in
pkg-atom) dir="pkg/atom" ;;
pkg-email) dir="pkg/email" ;;
pkg-errors) dir="pkg/errors" ;;
pkg-events) dir="pkg/events" ;;
pkg-grpcclient) dir="pkg/grpcclient" ;;
pkg-messaging) dir="pkg/messaging" ;;
pkg-readersclient) dir="pkg/readersclient" ;;
pkg-sdk) dir="pkg/sdk" ;;
pkg-testsutil) dir="pkg/testsutil" ;;
pkg-transformers) dir="pkg/transformers" ;;
pkg-ulid) dir="pkg/ulid" ;;
pkg-uuid) dir="pkg/uuid" ;;
channels) dir="pkg/channels" ;;
clients) dir="pkg/clients" ;;
domains) dir="pkg/domains" ;;
groups) dir="pkg/groups" ;;
*) dir="${{ matrix.module }}" ;;
esac
if [[ ! -d "$dir" ]]; then
echo "Skipping ${{ matrix.module }}; ./$dir is not present in this branch"
echo "mode: atomic" > coverage-${{ matrix.module }}.out
exit 0
fi
go test -mod=readonly --race -v -count=1 -failfast -coverprofile=coverage-${{ matrix.module }}.out ./$dir/...
- name: Upload coverage
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v7
with:
name: coverage-${{ matrix.module }}
path: coverage-${{ matrix.module }}.out
@@ -360,17 +287,17 @@ jobs:
if: always() && needs.run-tests.result != 'cancelled'
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Download all coverage artifacts
uses: actions/download-artifact@v7
uses: actions/download-artifact@v8
with:
pattern: coverage-*
path: coverage
merge-multiple: true
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@v7
with:
token: ${{ secrets.CODECOV }}
directory: ./coverage
+9
View File
@@ -18,3 +18,12 @@ coverage
# Ignore Openbao data directory as it contains runtime-generated data
docker/addons/certs/openbao/
# Ignore generated local Atom service tokens.
docker/.env.tokens
# Ignore SeaweedFS data directory as it contains runtime-generated data
docker/data/*
demo-ui
node_modules
+6 -6
View File
@@ -1,12 +1,12 @@
# Adopters
As SuperMQ Community grows, we'd like to keep track of SuperMQ adopters to grow the community, contact other users, share experiences and best practices.
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 SuperMQ adopters and that **publicly/officially** shared information and/or details of their adoption journey(optional).
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 SuperMQ, 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 SuperMQ technology.
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**
@@ -25,12 +25,12 @@ Pull request commit must be [signed](https://docs.github.com/en/github/authentic
* 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 SuperMQ:**
**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 SuperMQ Community members.
**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/supermq/blob/main/MAINTAINERS) and you will be permanently removed from the list.
**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/main/MAINTAINERS) and you will be permanently removed from the list.
+9 -9
View File
@@ -1,6 +1,6 @@
# Contributing to SuperMQ
# Contributing to Magistrala
The following is a set of guidelines to contribute to SuperMQ and its libraries, which are
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.
This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0).
@@ -13,7 +13,7 @@ Reporting issues are a great way to contribute to the project. We are perpetuall
thorough bug report.
Before raising a new issue, check [our issue
list](https://github.com/absmach/supermq/issues) to determine if it already contains the
list](https://github.com/absmach/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
@@ -41,9 +41,9 @@ To contribute to the project, [fork](https://help.github.com/articles/fork-a-rep
clone your fork repository, and configure the remotes:
```
git clone https://github.com/<your-username>/supermq.git
cd supermq
git remote add upstream https://github.com/absmach/supermq.git
git clone https://github.com/<your-username>/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:
@@ -53,11 +53,11 @@ git checkout main
git pull --rebase upstream main
```
Create a new topic branch from `main` using the naming convention `SMQ-[issue-number]`
Create a new topic branch from `main` using the naming convention `MG-[issue-number]`
to help us keep track of your contribution scope:
```
git checkout -b SMQ-[issue-number]
git checkout -b MG-[issue-number]
```
Commit your changes in logical chunks. When you are ready to commit, make sure
@@ -80,7 +80,7 @@ git pull --rebase upstream main
Push your topic branch up to your fork:
```
git push origin SMQ-[issue-number]
git push origin MG-[issue-number]
```
[Open a Pull Request](https://help.github.com/articles/using-pull-requests/) with a clear title
+1 -1
View File
@@ -176,7 +176,7 @@
END OF TERMS AND CONDITIONS
Copyright 2015-2026 SuperMQ
Copyright 2015-2026 Magistrala
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
+2 -2
View File
@@ -1,6 +1,6 @@
# SuperMQ Maintainers
# Magistrala Maintainers
SuperMQ follows a BDFL model for dead-lock situations; day-to-day decisions happen through discussion and pull requests.
Magistrala follows a BDFL model for dead-lock situations; day-to-day decisions happen through discussion and pull requests.
## BDFL
+229 -83
View File
@@ -1,16 +1,18 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
SMQ_DOCKER_IMAGE_NAME_PREFIX ?= supermq
override MG_DOCKER_IMAGE_NAME_PREFIX := ghcr.io/absmach/magistrala
MG_DOCKER_VOLUME_NAME_PREFIX ?= magistrala
BUILD_DIR ?= build
SERVICES = auth users clients groups channels domains http coap cli mqtt journal notifications
TEST_API_SERVICES = journal auth certs http clients users channels groups domains
SERVICES = atom-bootstrap certs postgres-writer postgres-reader timescale-writer timescale-reader fluxmq
TEST_API_SERVICES = certs clients users channels groups domains
TEST_API = $(addprefix test_api_,$(TEST_API_SERVICES))
DOCKERS = $(addprefix docker_,$(SERVICES))
DOCKERS_DEV = $(addprefix docker_dev_,$(SERVICES))
CGO_ENABLED ?= 0
GOARCH ?= amd64
GOOS ?= linux
DETECTED_ARCH := $(shell uname -m)
VERSION ?= $(shell git describe --abbrev=0 --tags 2>/dev/null || echo 'unknown')
COMMIT ?= $(shell git rev-parse HEAD)
TIME ?= $(shell date +%F_%T)
@@ -21,31 +23,42 @@ space:= $(empty) $(empty)
DOCKER_PROJECT ?= $(shell echo $(subst $(space),,$(USER_REPO)) | sed -E 's/[^a-zA-Z0-9]/_/g' | tr '[:upper:]' '[:lower:]')
DOCKER_COMPOSE_COMMANDS_SUPPORTED := up down config restart
DEFAULT_DOCKER_COMPOSE_COMMAND := up
ATOM_TOKENS_ENV ?= docker/.env.tokens
REQUIRED_ATOM_TOKEN_ENVS := MG_ATOM_TOKEN_FLUXMQ_AUTH MG_ATOM_TOKEN_FLUXMQ_NODE1 MG_ATOM_TOKEN_FLUXMQ_NODE2 MG_ATOM_TOKEN_FLUXMQ_NODE3 MG_ATOM_TOKEN_TIMESCALE_READER MG_ATOM_TOKEN_RE MG_ATOM_TOKEN_ALARMS MG_ATOM_TOKEN_REPORTS MG_ATOM_TOKEN_POSTGRES_READER
PROVISION_ATOM_TOKENS ?= false
PROVISION_ATOM_TOKEN_GOALS := provision-atom-tokens
DOCKER_BASE_ENV_FILES := --env-file docker/.env
DOCKER_ENV_FILES = $(if $(filter down,$(DOCKER_COMPOSE_COMMAND)),$(DOCKER_BASE_ENV_FILES),$(DOCKER_BASE_ENV_FILES) --env-file $(ATOM_TOKENS_ENV))
DOCKER_PROVISION_ENV_FILES = $(DOCKER_BASE_ENV_FILES) $(if $(wildcard $(ATOM_TOKENS_ENV)),--env-file $(ATOM_TOKENS_ENV))
HOST_UID := $(shell id -u)
HOST_GID := $(shell id -g)
GRPC_MTLS_CERT_FILES_EXISTS = 0
MOCKERY = $(GOBIN)/mockery
MOCKERY_VERSION=3.5.5
MOCKERY_VERSION=3.6.4
PKG_PROTO_GEN_OUT_DIR=api/grpc
INTERNAL_PROTO_DIR=internal/proto
INTERNAL_PROTO_FILES := $(shell find $(INTERNAL_PROTO_DIR) -name "*.proto" | sed 's|$(INTERNAL_PROTO_DIR)/||')
ifneq ($(SMQ_MESSAGE_BROKER_TYPE),)
SMQ_MESSAGE_BROKER_TYPE := $(SMQ_MESSAGE_BROKER_TYPE)
ifneq ($(MG_MESSAGE_BROKER_TYPE),)
MG_MESSAGE_BROKER_TYPE := $(MG_MESSAGE_BROKER_TYPE)
else
SMQ_MESSAGE_BROKER_TYPE=msg_nats
MG_MESSAGE_BROKER_TYPE=msg_fluxmq
endif
ifneq ($(SMQ_ES_TYPE),)
SMQ_ES_TYPE := $(SMQ_ES_TYPE)
ifneq ($(MG_ES_TYPE),)
MG_ES_TYPE := $(MG_ES_TYPE)
else
SMQ_ES_TYPE=es_nats
MG_ES_TYPE=es_fluxmq
endif
BUILD_TAGS := $(strip $(MG_MESSAGE_BROKER_TYPE) $(MG_ES_TYPE))
define compile_service
CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) GOARCH=$(GOARCH) GOARM=$(GOARM) \
go build -tags $(SMQ_MESSAGE_BROKER_TYPE) -tags $(SMQ_ES_TYPE) -ldflags "-s -w \
-X 'github.com/absmach/supermq.BuildTime=$(TIME)' \
-X 'github.com/absmach/supermq.Version=$(VERSION)' \
-X 'github.com/absmach/supermq.Commit=$(COMMIT)'" \
go build -tags "$(BUILD_TAGS)" -ldflags "-s -w \
-X 'github.com/absmach/magistrala.BuildTime=$(TIME)' \
-X 'github.com/absmach/magistrala.Version=$(VERSION)' \
-X 'github.com/absmach/magistrala.Commit=$(COMMIT)'" \
-o ${BUILD_DIR}/$(1) cmd/$(1)/main.go
endef
@@ -60,7 +73,8 @@ define make_docker
--build-arg VERSION=$(VERSION) \
--build-arg COMMIT=$(COMMIT) \
--build-arg TIME=$(TIME) \
--tag=$(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$(svc) \
--build-arg BUILD_TAGS="$(BUILD_TAGS)" \
--tag=$(MG_DOCKER_IMAGE_NAME_PREFIX)/$(svc) \
-f docker/Dockerfile .
endef
@@ -70,17 +84,100 @@ define make_docker_dev
docker build \
--no-cache \
--build-arg SVC=$(svc) \
--tag=$(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$(svc) \
--tag=$(MG_DOCKER_IMAGE_NAME_PREFIX)/$(svc) \
-f docker/Dockerfile.dev ./build
endef
ADDON_SERVICES = journal certs
define require_atom_tokens_env
@if [ -z "$(filter down,$(DOCKER_COMPOSE_COMMAND))" ]; then \
if [ ! -f "$(ATOM_TOKENS_ENV)" ]; then \
echo "Missing $(ATOM_TOKENS_ENV). Run 'make provision_atom_tokens' before starting the Docker Compose stack."; \
exit 2; \
fi; \
missing=""; \
for env_name in $(REQUIRED_ATOM_TOKEN_ENVS); do \
if ! grep -q "^$${env_name}=" "$(ATOM_TOKENS_ENV)"; then \
missing="$${missing} $${env_name}"; \
fi; \
done; \
if [ -n "$${missing}" ]; then \
echo "Missing Atom service token(s) in $(ATOM_TOKENS_ENV):$${missing}. Run 'make provision_atom_tokens' before starting the Docker Compose stack."; \
exit 2; \
fi; \
fi
endef
define ensure_atom_tokens_env
@if [ "$(PROVISION_ATOM_TOKENS)" = "true" ] && [ -z "$(filter down,$(DOCKER_COMPOSE_COMMAND))" ]; then \
$(MAKE) provision_atom_tokens; \
elif [ -z "$(filter down,$(DOCKER_COMPOSE_COMMAND))" ]; then \
if [ ! -f "$(ATOM_TOKENS_ENV)" ]; then \
echo "Missing $(ATOM_TOKENS_ENV). Run 'make provision_atom_tokens' before starting the Docker Compose stack."; \
exit 2; \
fi; \
missing=""; \
for env_name in $(REQUIRED_ATOM_TOKEN_ENVS); do \
if ! grep -q "^$${env_name}=" "$(ATOM_TOKENS_ENV)"; then \
missing="$${missing} $${env_name}"; \
fi; \
done; \
if [ -n "$${missing}" ]; then \
echo "Missing Atom service token(s) in $(ATOM_TOKENS_ENV):$${missing}. Run 'make provision_atom_tokens' before starting the Docker Compose stack."; \
exit 2; \
fi; \
fi
endef
define run_with_arch_detection
$(call require_atom_tokens_env)
@echo "Detecting architecture..."
@if [ "$(DETECTED_ARCH)" = "arm64" ] || [ "$(DETECTED_ARCH)" = "aarch64" ]; then \
echo "ARM64 architecture detected."; \
git checkout $(1); \
GOARCH=arm64 $(MAKE) dockers; \
for svc in $(SERVICES); do \
docker tag $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc:latest; \
done; \
sed -i.bak 's/^MG_RELEASE_TAG=.*/MG_RELEASE_TAG=latest/' docker/.env && rm -f docker/.env.bak; \
docker compose -f docker/docker-compose.yaml $(DOCKER_ENV_FILES) -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args); \
else \
echo "x86_64 architecture detected."; \
git checkout $(1); \
sed -i.bak 's/^MG_RELEASE_TAG=.*/MG_RELEASE_TAG=$(2)/' docker/.env && rm -f docker/.env.bak; \
docker compose -f docker/docker-compose.yaml $(DOCKER_ENV_FILES) -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args); \
fi
endef
ADDON_SERVICES = bootstrap provision postgres-writer postgres-reader
EXTERNAL_SERVICES = prometheus
# Detect OS and architecture for cross-platform compatibility
UNAME_S := $(shell uname -s)
UNAME_M := $(shell uname -m)
# macOS BSD sed vs GNU sed compatibility
ifeq ($(UNAME_S),Darwin)
SED_INPLACE := sed -i ''
else
SED_INPLACE := sed -i
endif
# Apple Silicon (arm64) Docker platform compatibility
# Pre-built images are amd64 only, so we need to use emulation on Apple Silicon
ifeq ($(UNAME_S),Darwin)
ifeq ($(UNAME_M),arm64)
DOCKER_PLATFORM := DOCKER_DEFAULT_PLATFORM=linux/amd64
endif
endif
DOCKER_PLATFORM ?=
ifneq ($(filter run%,$(firstword $(MAKECMDGOALS))),)
temp_args := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
DOCKER_COMPOSE_COMMAND := $(if $(filter $(DOCKER_COMPOSE_COMMANDS_SUPPORTED),$(temp_args)), $(filter $(DOCKER_COMPOSE_COMMANDS_SUPPORTED),$(temp_args)), $(DEFAULT_DOCKER_COMPOSE_COMMAND))
ifneq ($(filter $(PROVISION_ATOM_TOKEN_GOALS),$(temp_args)),)
override PROVISION_ATOM_TOKENS := true
endif
$(eval $(DOCKER_COMPOSE_COMMAND):;@)
endif
@@ -100,7 +197,14 @@ FILTERED_SERVICES = $(filter-out $(RUN_ADDON_ARGS), $(SERVICES))
all: $(SERVICES)
.PHONY: all $(SERVICES) dockers dockers_dev latest release run_latest run_stable run_addons grpc_mtls_certs check_mtls check_certs test_api mocks
.PHONY: all help $(SERVICES) dockers dockers_dev latest release provision_atom_tokens provision-atom-tokens migrate_atom run_latest run_latest_ci run_tls run_stable run_addons grpc_mtls_certs check_mtls check_certs check_fluxmq_service_certs check_re_trace_key test_api mocks
help:
@printf 'Usage:\n make <target> [VARIABLE=value ...]\n\nAvailable targets:\n'
@$(MAKE) -qpRr : 2>/dev/null | \
awk -F: '/^[[:alnum:]_][^$$#\/\t=]*:([^=]|$$)/ { split($$1, targets, /[[:space:]]+/); for (i in targets) if (targets[i] != "") print targets[i] }' | \
LC_ALL=C sort -u | \
awk '$$0 != "Makefile" { printf " make %s\n", $$0 }'
clean:
rm -rf ${BUILD_DIR}
@@ -111,12 +215,12 @@ cleandocker:
ifdef pv
# Remove unused volumes
docker volume ls -f name=$(SMQ_DOCKER_IMAGE_NAME_PREFIX) -f dangling=true -q | xargs -r docker volume rm
docker volume ls -f name=$(MG_DOCKER_VOLUME_NAME_PREFIX) -f dangling=true -q | xargs -r docker volume rm
endif
install:
for file in $(BUILD_DIR)/*; do \
cp $$file $(GOBIN)/supermq-`basename $$file`; \
cp $$file $(GOBIN)/magistrala-`basename $$file`; \
done
mocks: $(MOCKERY)
@@ -124,11 +228,8 @@ mocks: $(MOCKERY)
$(MOCKERY):
@mkdir -p $(GOBIN)
@mkdir -p mockery
@echo ">> downloading mockery $(MOCKERY_VERSION)..."
@curl -sL https://github.com/vektra/mockery/releases/download/v$(MOCKERY_VERSION)/mockery_$(MOCKERY_VERSION)_Linux_x86_64.tar.gz | tar -xz -C mockery
@mv mockery/mockery $(GOBIN)
@rm -r mockery
@echo ">> installing mockery $(MOCKERY_VERSION)..."
@go install github.com/vektra/mockery/v3@v$(MOCKERY_VERSION)
DIRS = consumers readers postgres internal
test: mocks
@@ -144,45 +245,26 @@ define test_api_service
@if [ -z "$(USER_TOKEN)" ]; then \
echo "USER_TOKEN is not set"; \
echo "Please set it to a valid token"; \
exit 1; \
echo "Please set it to a valid token"; \
exit 1; \
fi
@if [ "$(svc)" = "http" ] && [ -z "$(CLIENT_SECRET)" ]; then \
echo "CLIENT_SECRET is not set"; \
echo "Please set it to a valid secret"; \
exit 1; \
fi
@if [ "$(svc)" = "http" ]; then \
uvx schemathesis run apidocs/openapi/$(svc).yaml \
--checks all \
--url $(2) \
--header "Authorization: Client $(CLIENT_SECRET)" \
--suppress-health-check=filter_too_much \
--exclude-checks=positive_data_acceptance \
--phases=examples,stateful; \
else \
uvx schemathesis run apidocs/openapi/$(svc).yaml \
--checks all \
--url $(2) \
--header "Authorization: Bearer $(USER_TOKEN)" \
--suppress-health-check=filter_too_much \
--exclude-checks=positive_data_acceptance \
--exclude-operation-id=requestPasswordReset \
--phases=examples,stateful; \
fi
@uvx schemathesis run apidocs/openapi/$(svc).yaml \
--checks all \
--url $(2) \
--header "Authorization: Bearer $(USER_TOKEN)" \
--suppress-health-check=filter_too_much \
--exclude-checks=positive_data_acceptance \
--exclude-operation-id=requestPasswordReset \
--phases=examples,stateful
endef
test_api_users: TEST_API_URL := http://localhost:9002
test_api_clients: TEST_API_URL := http://localhost:9006
test_api_domains: TEST_API_URL := http://localhost:9003
test_api_channels: TEST_API_URL := http://localhost:9005
test_api_groups: TEST_API_URL := http://localhost:9004
test_api_http: TEST_API_URL := http://localhost:8008
test_api_auth: TEST_API_URL := http://localhost:9001
test_api_users: TEST_API_URL := http://localhost:9000
test_api_clients: TEST_API_URL := http://localhost:9000
test_api_domains: TEST_API_URL := http://localhost:9000
test_api_channels: TEST_API_URL := http://localhost:9000
test_api_groups: TEST_API_URL := http://localhost:9000
test_api_certs: TEST_API_URL := http://localhost:9019
test_api_journal: TEST_API_URL := http://localhost:9021
$(TEST_API):
$(call test_api_service,$(@),$(TEST_API_URL))
@@ -206,7 +288,7 @@ dockers_dev: $(DOCKERS_DEV)
define docker_push
for svc in $(SERVICES); do \
docker push $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(1); \
docker push $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(1); \
done
endef
@@ -219,10 +301,10 @@ latest: dockers
publish_arch:
$(MAKE) dockers GOOS=$(GOOS) GOARCH=$(GOARCH) GOARM=$(GOARM)
for svc in $(SERVICES); do \
docker tag $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(VERSION)-$(GOARCH); \
docker tag $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc:latest-$(GOARCH); \
docker push $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(VERSION)-$(GOARCH); \
docker push $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc:latest-$(GOARCH); \
docker tag $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(VERSION)-$(GOARCH); \
docker tag $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc:latest-$(GOARCH); \
docker push $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(VERSION)-$(GOARCH); \
docker push $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc:latest-$(GOARCH); \
done
release:
@@ -230,7 +312,7 @@ release:
git checkout $(version)
$(MAKE) dockers
for svc in $(SERVICES); do \
docker tag $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(version); \
docker tag $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(version); \
done
$(call docker_push,$(version))
@@ -238,7 +320,25 @@ rundev:
cd scripts && ./run.sh
grpc_mtls_certs:
$(MAKE) -C docker/ssl auth_grpc_certs clients_grpc_certs
$(MAKE) -C docker/ssl clients_grpc_certs
provision_atom_tokens:
$(DOCKER_PLATFORM) docker compose -f docker/docker-compose.yaml $(DOCKER_PROVISION_ENV_FILES) -p $(DOCKER_PROJECT) up -d --wait --wait-timeout 120 atom
$(MAKE) docker_atom-bootstrap
$(DOCKER_PLATFORM) docker compose -f docker/docker-compose.yaml $(DOCKER_PROVISION_ENV_FILES) -p $(DOCKER_PROJECT) run --rm --no-deps --user "$(HOST_UID):$(HOST_GID)" -v "$(PWD)/docker:/host/docker" atom-bootstrap provision-tokens --output /host/docker/.env.tokens
provision-atom-tokens:
@:
# Migrate an old Magistrala (v0.30.0 / pre-Atom) deployment into Atom. Runs an
# isolated, collision-free stack, seeds the Atom schema into the run_latest Atom
# volume and loads the data. Default is a dry-run; pass args="--apply" to load,
# args="--verify" to reconcile afterwards.
# make migrate_atom # dry-run
# make migrate_atom args="--apply" # perform the migration
# make migrate_atom args="--apply --fresh-atom" # rebuild Atom schema first
migrate_atom:
DOCKER_PROJECT="$(DOCKER_PROJECT)" tools/atom-migration/migrate.sh $(args)
check_tls:
ifeq ($(GRPC_TLS),true)
@@ -256,39 +356,85 @@ else
$(eval GRPC_MTLS :=)
endif
check_certs: check_mtls check_tls
# Internal services reach FluxMQ on the mTLS local listener, and Compose mounts
# both sides of those connections. Certificates and principal secrets are
# generated rather than committed, so make them before anything binds them.
check_fluxmq_service_certs:
ifeq ("$(wildcard docker/ssl/certs/re-fluxmq-client.crt)","")
$(MAKE) -C docker/ssl fluxmq_service_certs
endif
ifeq ("$(wildcard docker/ssl/certs/timescale-writer-fluxmq-client.crt)","")
$(MAKE) -C docker/ssl timescale_writer_fluxmq_client_cert
endif
ifeq ("$(wildcard docker/ssl/certs/postgres-writer-fluxmq-client.crt)","")
$(MAKE) -C docker/ssl postgres_writer_fluxmq_client_cert
endif
ifeq ("$(wildcard docker/ssl/certs/fluxmq-auth-fluxmq-client.crt)","")
$(MAKE) -C docker/ssl fluxmq_auth_fluxmq_client_cert
endif
ifeq ("$(wildcard docker/fluxmq/secrets/re-current)","")
$(MAKE) -C docker/ssl fluxmq_service_secret
endif
ifeq ("$(wildcard docker/fluxmq/secrets/timescale-writer-current)","")
$(MAKE) -C docker/ssl timescale_writer_fluxmq_service_secret
endif
ifeq ("$(wildcard docker/fluxmq/secrets/postgres-writer-current)","")
$(MAKE) -C docker/ssl postgres_writer_fluxmq_service_secret
endif
ifeq ("$(wildcard docker/fluxmq/secrets/fluxmq-auth-current)","")
$(MAKE) -C docker/ssl fluxmq_auth_fluxmq_service_secret
endif
check_re_trace_key:
ifeq ("$(wildcard docker/re/secrets/trace.key)","")
$(MAKE) -C docker/ssl re_trace_key
endif
check_certs: check_mtls check_tls check_fluxmq_service_certs check_re_trace_key
ifeq ($(GRPC_MTLS_CERT_FILES_EXISTS),0)
ifeq ($(filter true,$(GRPC_MTLS) $(GRPC_TLS)),true)
ifeq ($(filter $(DEFAULT_DOCKER_COMPOSE_COMMAND),$(DOCKER_COMPOSE_COMMAND)),$(DEFAULT_DOCKER_COMPOSE_COMMAND))
$(MAKE) -C docker/ssl auth_grpc_certs clients_grpc_certs
$(MAKE) -C docker/ssl clients_grpc_certs
endif
endif
endif
fetch_certs:
@./scripts/certs.sh
run_latest: check_certs
git checkout main
sed -i 's/^SMQ_RELEASE_TAG=.*/SMQ_RELEASE_TAG=latest/' docker/.env
docker compose -f docker/docker-compose.yaml --env-file docker/.env -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args)
$(SED_INPLACE) 's/^MG_RELEASE_TAG=.*/MG_RELEASE_TAG=latest/' docker/.env
$(call ensure_atom_tokens_env)
$(DOCKER_PLATFORM) docker compose -f docker/docker-compose.yaml $(DOCKER_ENV_FILES) -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args)
run_latest_ci: check_certs
$(call require_atom_tokens_env)
$(SED_INPLACE) 's/^MG_RELEASE_TAG=.*/MG_RELEASE_TAG=latest/' docker/.env
$(DOCKER_PLATFORM) docker compose -f docker/docker-compose.yaml -f docker/docker-compose-ci.yaml $(DOCKER_ENV_FILES) -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args)
run_tls: check_certs
@test -n "$(host)" || (echo "Usage: make run_tls host=example.com [email=admin@example.com] [letsencrypt=false] [staging=true] [force=true]" && exit 2)
@if [ "$(or $(letsencrypt),true)" != "false" ] && [ -z "$(email)" ]; then echo "Usage: make run_tls host=example.com email=admin@example.com [letsencrypt=false] [staging=true] [force=true]"; exit 2; fi
MG_PUBLIC_HOST="$(host)" \
MG_LETSENCRYPT_ENABLED="$(or $(letsencrypt),true)" \
MG_LETSENCRYPT_EMAIL="$(email)" \
MG_LETSENCRYPT_STAGING="$(or $(staging),false)" \
MG_LETSENCRYPT_FORCE_RENEWAL="$(or $(force),false)" \
DOCKER_PROJECT="$(DOCKER_PROJECT)" \
./docker/setup-tls.sh
run_stable: check_certs
$(call require_atom_tokens_env)
$(eval version = $(shell git describe --abbrev=0 --tags))
git checkout $(version)
sed -i 's/^SMQ_RELEASE_TAG=.*/SMQ_RELEASE_TAG=$(version)/' docker/.env
docker compose -f docker/docker-compose.yaml --env-file docker/.env -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args)
$(SED_INPLACE) 's/^MG_RELEASE_TAG=.*/MG_RELEASE_TAG=$(version)/' docker/.env
$(DOCKER_PLATFORM) docker compose -f docker/docker-compose.yaml $(DOCKER_ENV_FILES) -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args)
run_addons: check_certs
$(call require_atom_tokens_env)
$(foreach SVC,$(RUN_ADDON_ARGS),$(if $(filter $(SVC),$(ADDON_SERVICES) $(EXTERNAL_SERVICES)),,$(error Invalid Service $(SVC))))
@docker compose -f docker/docker-compose.yaml --env-file ./docker/.env -p $(DOCKER_PROJECT) up -d auth domains jaeger
@$(DOCKER_PLATFORM) docker compose -f docker/docker-compose.yaml $(DOCKER_ENV_FILES) -p $(DOCKER_PROJECT) up -d atom jaeger
@for SVC in $(RUN_ADDON_ARGS); do \
if [ "$$SVC" = "certs" ]; then \
docker compose -f docker/addons/$$SVC/docker-compose.yaml -f docker/certs-docker-compose-override.yaml --env-file ./docker/.env --env-file ./docker/addons/$$SVC/.env -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args) & \
else \
SMQ_ADDONS_CERTS_PATH_PREFIX="../." docker compose -f docker/addons/$$SVC/docker-compose.yaml -p $(DOCKER_PROJECT) --env-file ./docker/.env $(DOCKER_COMPOSE_COMMAND) $(args) & \
fi; \
MG_ADDONS_CERTS_PATH_PREFIX="../" $(DOCKER_PLATFORM) docker compose -f docker/addons/$$SVC/docker-compose.yaml -p $(DOCKER_PROJECT) $(DOCKER_ENV_FILES) $(DOCKER_COMPOSE_COMMAND) $(args) & \
done
run_live: check_certs
GOPATH=$(go env GOPATH) docker compose -f docker/docker-compose.yaml -f docker/docker-compose-live.yaml --env-file docker/.env -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args)
$(call require_atom_tokens_env)
GOPATH=$(go env GOPATH) $(DOCKER_PLATFORM) docker compose -f docker/docker-compose.yaml -f docker/docker-compose-live.yaml $(DOCKER_ENV_FILES) -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args)
+369 -96
View File
@@ -1,139 +1,412 @@
<div align="center">
# SuperMQ
### Planetary event-driven infrastructure
**Made with ❤️ by [Abstract Machines](https://absmach.eu/)**
# Magistrala
[![Build Status](https://github.com/absmach/supermq/actions/workflows/build.yaml/badge.svg?branch=main)](https://github.com/absmach/supermq/actions/workflows/build.yaml)
[![Go Report Card](https://goreportcard.com/badge/github.com/absmach/supermq)](https://goreportcard.com/report/github.com/absmach/supermq)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/absmach/supermq)
[![Check License Header](https://github.com/absmach/supermq/actions/workflows/check-license.yaml/badge.svg?branch=main)](https://github.com/absmach/supermq/actions/workflows/check-license.yaml)
[![Check Generated Files](https://github.com/absmach/supermq/actions/workflows/check-generated-files.yaml/badge.svg?branch=main)](https://github.com/absmach/supermq/actions/workflows/check-generated-files.yaml)
[![Coverage](https://codecov.io/gh/absmach/supermq/graph/badge.svg?token=nPCEr5nW8S)](https://codecov.io/gh/absmach/supermq)
### A Modern IoT Platform Framework for Scalable IoT
**Made with ❤ by [Abstract Machines](https://absmach.eu/)**
[![Build Status](https://github.com/absmach/magistrala/actions/workflows/build.yaml/badge.svg?branch=main)](https://github.com/absmach/magistrala/actions/workflows/build.yaml)
[![Go Report Card](https://goreportcard.com/badge/github.com/absmach/magistrala)](https://goreportcard.com/report/github.com/absmach/magistrala)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/absmach/magistrala)
[![Check License Header](https://github.com/absmach/magistrala/actions/workflows/check-license.yaml/badge.svg?branch=main)](https://github.com/absmach/magistrala/actions/workflows/check-license.yaml)
[![Check Generated Files](https://github.com/absmach/magistrala/actions/workflows/check-generated-files.yaml/badge.svg?branch=main)](https://github.com/absmach/magistrala/actions/workflows/check-generated-files.yaml)
[![Coverage](https://codecov.io/gh/absmach/magistrala/graph/badge.svg?token=nPCEr5nW8S)](https://codecov.io/gh/absmach/magistrala)
[![License](https://img.shields.io/badge/license-Apache%20v2.0-blue.svg)](LICENSE)
[![Matrix](https://img.shields.io/matrix/supermq%3Amatrix.org?label=Chat&style=flat&logo=matrix&logoColor=white)](https://matrix.to/#/#supermq:matrix.org)
### [Guide](https://docs.supermq.absmach.eu) | [Contributing](CONTRIBUTING.md) | [Website](https://absmach.eu/) | [Chat](https://matrix.to/#/#supermq:matrix.org)
[Guide](https://magistrala.absmach.eu/docs/) | [Contributing](CONTRIBUTING.md) | [Website](https://absmach.eu/) | [Chat](https://matrix.to/#/#supermq:matrix.org)
</div>
## Introduction 📖
## Introduction 🌍
SuperMQ is a distributed, highly scalable, and secure open-source cloud platform for messaging and event-driven architecture (EDA). It is a planetarily distributed, highly scalable, and secure platform that serves as a robust foundation for building advanced real-time and reactive systems.
Magistrala is an open-source IoT platform built for engineers who need full control over their messaging, device management, and data pipelines.
## Why SuperMQ Stands Out 🚀
It is built on top of [FluxMQ](https://github.com/absmach/fluxmq), a modern message broker designed for both messaging and event streams. Magistrala provides everything around it: identity, access control, device provisioning, data processing, and observability.
SuperMQ bridges the gap between various network protocols (HTTP, MQTT, WebSocket, CoAP, and more) to provide a seamless messaging experience. Whether you're working on IoT solutions, real-time data pipelines, or event-driven systems, SuperMQ has you covered. 🌐✨
IoT systems usually involve brokers, databases, rule engines, and custom services. Magistrala does not pretend those pieces disappear. It provides a coherent framework for integrating them into a single system with a consistent model for identity, access control, messaging, and observability.
## Key Features 🌟
**What it is:**
- An event-driven IoT middleware platform
- A unified control plane for devices, users, and data
- A foundation for building scalable IoT systems
- **Multi-Protocol Connectivity**: HTTP, MQTT, WebSocket, CoAP, and more! 🌉
- **Secure by Design**: Mutual TLS (mTLS) with X.509 Certificates, JWT support, and multi-protocol authorization. 🔒
- **Fine-Grained Access Control**: Support for ABAC and RBAC policies. 📜
- **Multi-Tenant**: Manage multiple domains seamlessly. 🏢
- **Multi-User**: Unlimited organizational hierarchies for user management. 👥
- **Application Management**: Group and share messaging clients for streamlined operations. 📱
- **Ease of Use**: Simple and powerful communication channel management, grouping, and sharing. ✨
- **Personal Access Tokens (PATs)**: Scoped and revocable tokens for enhanced security. 🔑
- **Observability**: Integrated logging and instrumentation with Prometheus and OpenTelemetry. 📈
- **Event Sourcing**: Build robust and scalable architectures. ⚡
- **Edge and IoT Ready**: Supports MQTT and CoAP protocols for seamless IoT gateway and sensor communication and management. 🌍
- **Developer-Friendly**: SDKs, CLI tools, and comprehensive documentation to get you started. 👩‍💻👨‍💻
- **Production-Ready**: Container-based deployment using Docker and Kubernetes. 🐳☸️
**What it is not:**
- Not just an MQTT broker
- Not a black-box SaaS
- Not tied to a single cloud or vendor
## Installation 🛠️
---
There are multiple ways to run SuperMQ.
First, clone the repository and position to it:
## 🧩 IoT Platform Framework
```bash
git clone https://github.com/absmach/supermq.git
cd supermq
We call Magistrala a **framework**, not just a platform.
It is extremely flexible and lets you build systems the way you want — from simple prototypes to complex, large-scale deployments — without forcing you into rigid patterns.
At the same time, it avoids the typical complexity of many IoT platforms, where you need to learn an entirely new set of concepts before you can even get started.
Magistrala is built around a small number of main concepts:
- users
- clients (devices)
- channels
- messages
- policies
Most engineers are already familiar with these ideas, so you can start building immediately.
You can keep things simple:
- connect devices
- send messages
- store data
Or you can go deeper:
- define complex access control policies
- build event-driven pipelines
- integrate custom processing and automation
Magistrala scales with your needs — simple when you want it, powerful when you need it.
---
## 🚀 Key Benefits
- **A Coherent System, Not a Mess of Integrations**
Build IoT systems from multiple components without ending up with fragmented security, messaging, and operations.
- **Event-Driven at the Core**
Everything is built around events — enabling real-time processing, streaming, and scalable data flows.
- **Protocol-Native, Not Forced Abstractions**
MQTT, HTTP, WebSocket, and CoAP are treated as first-class citizens, each with their own semantics.
- **Security Built Into the Model**
Identity, authentication, and authorization are part of the system design — not bolted on later.
- **Flexible by Design**
Start simple or build complex systems — without changing platforms or rewriting your architecture.
- **Runs Where You Need It**
Cloud, edge, or hybrid — no vendor lock-in, no hidden dependencies.
---
## ✨ Features
Magistrala provides a complete set of building blocks for IoT systems — from device connectivity to data processing and observability — without forcing a rigid architecture.
### 🔐 Identity & Access
- Multi-tenant domains for isolating environments
- Users, roles, and organizational hierarchies
- Fine-grained access control (ABAC + RBAC)
- Mutual TLS (X.509) and JWT-based authentication
- Personal Access Tokens (PATs) with scoping and revocation
### 🔌 Connectivity
- Native support for MQTT, HTTP, WebSocket, and CoAP
- Consistent authentication and authorization across protocols
- Designed for both cloud services and constrained devices
### 📦 Device & Application Model
- Device (client) provisioning and lifecycle management
- Channels for grouping and controlling message flow
- Application-level grouping and sharing of clients
- Simple but flexible communication model
### ⚙️ Processing & Automation
- Rules engine for message processing and routing (Enterprise Edition)
- Alarms and triggers for reacting to events (Enterprise Edition)
- Scheduled actions for time-based workflows
- Event-driven architecture as the foundation
### 📊 Observability
- Audit logs for tracking system activity (Enterprise Edition)
- Metrics and tracing via Prometheus and OpenTelemetry
- Built-in visibility into system behavior and data flows
### 🚀 Deployment & Operations
- Container-native (Docker, Kubernetes)
- Designed for cloud, edge, and hybrid deployments
- Works with external storage and processing systems
- Scales from small setups to production environments
### 🧑‍💻 Developer Experience
- CLI and SDKs for fast integration
- Straightforward APIs and concepts
- Documentation focused on getting you running quickly
---
## Atom Integration Model
Magistrala uses **Atom** as the backend for identity, authorization, and the catalog.
Atom is the source of truth for:
- domains
- users
- clients
- channels
- groups
- roles
- access policies
Magistrala services such as rules, alarms, and reports remain Magistrala services, but they use Atom for identity and authorization.
Current Docker deployments use the Atom image configured by `ATOM_IMAGE` in `docker/.env`. For compatibility with the current Magistrala integration, the generated `MG_ATOM_TOKEN_*` service credentials are unscoped Atom access tokens. Scoped Atom access tokens should not be used for these service env vars until Magistrala stops using owner-wide Atom listing APIs such as `authorizedObjectIds` in service policy paths.
### Core Entity Mapping
| Magistrala concept | Atom concept | Meaning |
| ------------------ | ---------------------------- | ------------------------------------------------------------------ |
| Domain | Tenant | Isolation boundary for one organization, project, or environment |
| User | Entity with kind `human` | A person who logs in and uses the UI/API |
| Client | Entity with kind `device` | A device or application that sends/receives data |
| Channel | Resource with kind `channel` | A messaging/data path that clients can publish or subscribe to |
| Group | Group | A collection of users, clients, channels, or other grouped objects |
In simple terms:
```text
MG Domain = Atom Tenant
MG User = Atom Human Entity
MG Client = Atom Device Entity
MG Channel = Atom Channel Resource
MG Group = Atom Group
```
To run the latest stable (tagged) version, use:
### Actions, Permission Blocks, Roles, and Assignments
```bash
# Run with latest stable tagged version
make run_stable
Atom access control has these basic parts:
| Atom word | Simple meaning | Example |
| ---------------- | ----------------------------- | --------------------------------------------------------- |
| Action | One permission verb | `read`, `write`, `delete`, `role.manage`, `policy.manage` |
| Permission Block | Where actions apply | all channels in domain `d1` can `read`, `publish` |
| Role | A bundle of permission blocks | `tenant-admin` bundles domain, role, and member access |
| Role Assignment | Who gets a role | give `user1` the `tenant-admin` role |
Read an assignment like this:
```text
Give <who> this <role>.
The role contains permission blocks that say where and what.
```
To run the latest version, use:
Example:
```text
Give user1 the tenant-admin role on domain d1.
```
That means:
```text
user1 can use the tenant-admin permissions inside domain d1.
```
### How MG Roles Work With Atom
MG UI shows actions such as:
- read
- update
- delete
- manage roles
- add/remove members
- publish
- subscribe
These are mapped to Atom actions:
| MG action | Atom action |
| ---------------------------- | --------------- |
| view/read | `read` |
| create/update/edit/connect | `write` |
| delete/remove | `delete` |
| manage roles | `role.manage` |
| add/remove members or access | `policy.manage` |
| channel publish | `publish` |
| channel subscribe | `subscribe` |
So when MG UI checks:
```text
Can user1 manage roles for client1?
```
Atom checks:
```text
Does user1 have role.manage on client1, or on the domain that contains client1?
```
When MG UI checks:
```text
Can user1 add a member to channel1?
```
Atom checks:
```text
Does user1 have policy.manage on channel1, or on the domain that contains channel1?
```
### Practical Rule
If a user is domain admin, they usually receive a tenant-scoped role in Atom.
That tenant-scoped role can allow them to manage objects inside the domain:
- clients
- channels
- groups
- rules
- alarms
- reports
For narrower access, create object-scoped roles. For example:
```text
Give user2 a reader role only on channel1.
```
Then user2 can read only that channel, not the whole domain.
## Installation
```bash
# Run with latest development version (from main branch)
git clone https://github.com/absmach/magistrala.git
cd magistrala
make provision_atom_tokens
make run_latest
```
The `make run_stable` command will:
- Checkout the repository to the latest git tag
- Update the version in the environment configuration
- Start the services with the stable release
A fresh clone carries no generated secrets. Two sets have to exist before the
stack can start — certificates and keys the internal services authenticate
with, and the Atom service tokens each service presents to Atom. `make
run_latest` produces the first set itself but expects the second to be there
already, which is why the token step comes first above.
**Note:** After running `make run_stable`, you'll be on a detached HEAD state. To return to your working branch:
### Certificates, broker secret and trace key
Generated by `make run_latest`, or on demand:
```bash
git checkout main
make check_certs
```
To manually run SuperMQ, clone the repository and start all core services:
This creates whatever is missing and leaves anything already present alone:
| Path | What it is |
| ----------------------------------------------------------- | ------------------------------------------------------------------------- |
| `docker/ssl/certs/fluxmq-service-server.{crt,key}` | Server certificate for FluxMQ's mTLS service listener |
| `docker/ssl/certs/re-fluxmq-client.{crt,key}` | Client certificate whose URI SAN identifies the Rules Engine |
| `docker/ssl/certs/timescale-writer-fluxmq-client.{crt,key}` | Client certificate whose URI SAN identifies the Timescale writer |
| `docker/ssl/certs/postgres-writer-fluxmq-client.{crt,key}` | Client certificate whose URI SAN identifies the Postgres writer |
| `docker/ssl/certs/fluxmq-auth-fluxmq-client.{crt,key}` | Client certificate whose URI SAN identifies the publish proxy |
| `docker/fluxmq/secrets/re-current` | Rules Engine principal secret, from `MG_RE_BROKER_SECRET` |
| `docker/fluxmq/secrets/timescale-writer-current` | Timescale writer secret, from `MG_TIMESCALE_WRITER_BROKER_SECRET` |
| `docker/fluxmq/secrets/postgres-writer-current` | Postgres writer secret, from `MG_POSTGRES_WRITER_BROKER_SECRET` |
| `docker/fluxmq/secrets/fluxmq-auth-current` | Publish proxy secret, from `MG_FLUXMQ_BROKER_SECRET` |
| `docker/re/secrets/trace.key` | HMAC key the Rules Engine signs its loop-detection traces with |
Internal services reach the broker as *local principals* rather than as ordinary
clients: each presents a client certificate whose URI SAN names it, plus a SASL
secret, and the broker grants it only what it needs — the Rules Engine consumes
`m`, republishes under it, and feeds the `writers` and `alarms` streams; the
writers only subscribe to `writers`; the publish proxy that serves the UI's
HTTP publish endpoint only publishes under `m.`. The principals are declared in
`docker/fluxmq/node{1,2,3}.yaml`, and adding a service means adding an entry
there alongside its certificate and secret.
Being a local principal is also what preserves a message's origin. The broker
stamps its own transport protocol and identity on anything published over a
connection it does not trust, so a message relayed to the writers over the plain
AMQP listener would be stored as `protocol: amqp` with the relaying service as
its publisher. A `service`-role principal on the mTLS listener may state the
origin instead, and the protocol the device actually published with survives to
the database.
The certificates are issued by the development CA committed at
`docker/ssl/certs/ca.crt`, so no extra setup is needed for a local run. The
generated material is gitignored.
The server certificate is issued for `fluxmq` and `fluxmq-node{1,2,3}`, which
covers both this Compose stack and a single-node deployment. Point any
`MG_*_BROKER_URL` at a host outside that set and the service fails its TLS
verification with `certificate is valid for ...`; add the name to
`FLUXMQ_SERVICE_SERVER_CERT_CONFIG` in `docker/ssl/Makefile` and reissue:
```bash
docker compose -f docker/docker-compose.yaml --env-file docker/.env up
rm -f docker/ssl/certs/fluxmq-service-server.* \
docker/ssl/certs/re-fluxmq-client.* \
docker/ssl/certs/timescale-writer-fluxmq-client.* \
docker/ssl/certs/postgres-writer-fluxmq-client.*
make -C docker/ssl fluxmq_service_certs
```
### Usage 📤📥
`make check_certs` skips certificates that already exist, so stale certificates
have to be removed rather than merely re-running the target.
**Using the CLI :**
Each local-principal secret must stay equal to the corresponding value in
`docker/.env`; a mismatch fails that service's broker authentication. After
changing one, re-run its target:
| Variable | Target |
| ----------------------------------- | ----------------------------------------- |
| `MG_RE_BROKER_SECRET` | `fluxmq_service_secret` |
| `MG_TIMESCALE_WRITER_BROKER_SECRET` | `timescale_writer_fluxmq_service_secret` |
| `MG_POSTGRES_WRITER_BROKER_SECRET` | `postgres_writer_fluxmq_service_secret` |
| `MG_FLUXMQ_BROKER_SECRET` | `fluxmq_auth_fluxmq_service_secret` |
`trace.key` is created once and preserved on later runs — replacing it while
messages are in flight would invalidate the rule traces they already carry, so
delete it only deliberately. Every Rules Engine replica must read the same key.
Start the stack through `make run_latest` rather than calling `docker compose
up` directly. Compose creates a missing bind-mount source as an empty
*directory*, so bringing up `re` or `fluxmq` before these files exist leaves the
containers failing against a directory where they expect a key.
### Atom service tokens
Not generated automatically, because provisioning them starts Atom and runs a
bootstrap job against it:
```bash
make provision_atom_tokens
```
This brings up Atom, runs `atom-bootstrap`, and writes the gitignored
`docker/.env.tokens` with one service token per consumer —
`MG_ATOM_TOKEN_FLUXMQ_AUTH`, `MG_ATOM_TOKEN_FLUXMQ_NODE{1,2,3}`,
`MG_ATOM_TOKEN_RE`, `MG_ATOM_TOKEN_ALARMS`, `MG_ATOM_TOKEN_REPORTS`,
`MG_ATOM_TOKEN_TIMESCALE_READER`, and `MG_ATOM_TOKEN_POSTGRES_READER`.
`make run_latest` refuses to start when that file is absent or short of any of
those variables, and names what is missing. To fold the step into the run:
```bash
make run_latest PROVISION_ATOM_TOKENS=true
```
Re-run `provision_atom_tokens` after anything that resets Atom's database; the
old tokens do not survive it.
---
## Usage
```bash
make cli
./build/supermq-cli status
./build/cli health <service>
```
This command retrieves the status of the SuperMQ server and outputs it to the console.
---
**Using HTTP with Curl :**
## License
```bash
curl -X GET http://localhost:8080/status
```
This request fetches the server status over HTTP and provides a JSON response.
See our [CLI documentation](https://docs.supermq.absmach.eu/cli) for more details.
## Documentation 📚
The official documentation is hosted at [SuperMQ docs page](https://docs.supermq.absmach.eu/).
Documentation is auto-generated, check out the instructions in the [docs repository](https://github.com/absmach/supermq-docs).
If you spot an error or a need for corrections, please let us know - or even better: send us a PR! 💌
## Community and Contributing 🤝
Thank you for your interest in SuperMQ and the desire to contribute!
1. Take a look at our [open issues](https://github.com/absmach/supermq/issues). The [good-first-issue](https://github.com/absmach/supermq/labels/good-first-issue) label is specifically for issues that are great for getting started.
2. Checkout the [contribution guide](CONTRIBUTING.md) to learn more about our style and conventions.
3. Make your changes compatible to our workflow.
Join our community:
- [Matrix Room](https://matrix.to/#/#supermq\:matrix.org)
## Professional Support 💼
Need help deploying SuperMQ or integrating it into your system? Reach out to **[Abstract Machines](https://absmach.eu/)** for professional support and guidance.
## License 📜
SuperMQ is open-source software licensed under the [Apache License 2.0](LICENSE). Contributions are welcome!
## Acknowledgments 🙌
Special thanks to the amazing contributors who make SuperMQ possible. Check out the [MAINTAINERS](MAINTAINERS) file to see the team behind the magic.
Ready to build the future of messaging and event-driven systems? Let's get started! 🚀
Apache-2.0
+1 -1
View File
@@ -1,7 +1,7 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package supermq
package magistrala
// Response contains HTTP response specific methods.
type Response interface {
+80 -122
View File
@@ -3,8 +3,8 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v6.33.0
// protoc-gen-go v1.36.11
// protoc v7.35.1
// source: auth/v1/auth.proto
package v1
@@ -70,11 +70,11 @@ func (x *AuthNReq) GetToken() string {
type AuthNRes struct {
state protoimpl.MessageState `protogen:"open.v1"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // token id
UserId string `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` // user id
UserRole uint32 `protobuf:"varint,3,opt,name=user_role,json=userRole,proto3" json:"user_role,omitempty"` // user role
Verified bool `protobuf:"varint,4,opt,name=verified,proto3" json:"verified,omitempty"` // verified user
TokenType uint32 `protobuf:"varint,5,opt,name=token_type,json=tokenType,proto3" json:"token_type,omitempty"` // token type
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
UserId string `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
UserRole uint32 `protobuf:"varint,3,opt,name=user_role,json=userRole,proto3" json:"user_role,omitempty"`
Verified bool `protobuf:"varint,4,opt,name=verified,proto3" json:"verified,omitempty"`
TokenType uint32 `protobuf:"varint,5,opt,name=token_type,json=tokenType,proto3" json:"token_type,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@@ -146,16 +146,15 @@ func (x *AuthNRes) GetTokenType() uint32 {
type PolicyReq struct {
state protoimpl.MessageState `protogen:"open.v1"`
TokenType uint32 `protobuf:"varint,1,opt,name=token_type,json=tokenType,proto3" json:"token_type,omitempty"` // Token type
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"` // Domain
SubjectType string `protobuf:"bytes,3,opt,name=subject_type,json=subjectType,proto3" json:"subject_type,omitempty"` // Client or User
SubjectKind string `protobuf:"bytes,4,opt,name=subject_kind,json=subjectKind,proto3" json:"subject_kind,omitempty"` // ID or Token
SubjectRelation string `protobuf:"bytes,5,opt,name=subject_relation,json=subjectRelation,proto3" json:"subject_relation,omitempty"` // Subject relation
Subject string `protobuf:"bytes,6,opt,name=subject,proto3" json:"subject,omitempty"` // Subject value
Relation string `protobuf:"bytes,7,opt,name=relation,proto3" json:"relation,omitempty"` // Relation to filter
Permission string `protobuf:"bytes,8,opt,name=permission,proto3" json:"permission,omitempty"` // Action
Object string `protobuf:"bytes,9,opt,name=object,proto3" json:"object,omitempty"` // Object ID
ObjectType string `protobuf:"bytes,10,opt,name=object_type,json=objectType,proto3" json:"object_type,omitempty"` // Client, User, Group
Domain string `protobuf:"bytes,1,opt,name=domain,proto3" json:"domain,omitempty"`
SubjectType string `protobuf:"bytes,2,opt,name=subject_type,json=subjectType,proto3" json:"subject_type,omitempty"`
SubjectKind string `protobuf:"bytes,3,opt,name=subject_kind,json=subjectKind,proto3" json:"subject_kind,omitempty"`
SubjectRelation string `protobuf:"bytes,4,opt,name=subject_relation,json=subjectRelation,proto3" json:"subject_relation,omitempty"`
Subject string `protobuf:"bytes,5,opt,name=subject,proto3" json:"subject,omitempty"`
Relation string `protobuf:"bytes,6,opt,name=relation,proto3" json:"relation,omitempty"`
Permission string `protobuf:"bytes,7,opt,name=permission,proto3" json:"permission,omitempty"`
Object string `protobuf:"bytes,8,opt,name=object,proto3" json:"object,omitempty"`
ObjectType string `protobuf:"bytes,9,opt,name=object_type,json=objectType,proto3" json:"object_type,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@@ -190,13 +189,6 @@ func (*PolicyReq) Descriptor() ([]byte, []int) {
return file_auth_v1_auth_proto_rawDescGZIP(), []int{2}
}
func (x *PolicyReq) GetTokenType() uint32 {
if x != nil {
return x.TokenType
}
return 0
}
func (x *PolicyReq) GetDomain() string {
if x != nil {
return x.Domain
@@ -261,15 +253,15 @@ func (x *PolicyReq) GetObjectType() string {
}
type PATReq struct {
state protoimpl.MessageState `protogen:"open.v1"`
UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` // User id (PAT)
PatId string `protobuf:"bytes,2,opt,name=pat_id,json=patId,proto3" json:"pat_id,omitempty"` // Pat id
EntityType uint32 `protobuf:"varint,3,opt,name=entity_type,json=entityType,proto3" json:"entity_type,omitempty"` // Entity type (PAT)
OptionalDomainId string `protobuf:"bytes,4,opt,name=optional_domain_id,json=optionalDomainId,proto3" json:"optional_domain_id,omitempty"` // Optional domain id (PAT)
Operation uint32 `protobuf:"varint,5,opt,name=operation,proto3" json:"operation,omitempty"` // Operation (PAT)
EntityId string `protobuf:"bytes,6,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"` // EntityID (PAT)
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
PatId string `protobuf:"bytes,1,opt,name=pat_id,json=patId,proto3" json:"pat_id,omitempty"`
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
Operation string `protobuf:"bytes,3,opt,name=operation,proto3" json:"operation,omitempty"`
UserId string `protobuf:"bytes,4,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
EntityId string `protobuf:"bytes,5,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"`
EntityType string `protobuf:"bytes,6,opt,name=entity_type,json=entityType,proto3" json:"entity_type,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PATReq) Reset() {
@@ -302,13 +294,6 @@ func (*PATReq) Descriptor() ([]byte, []int) {
return file_auth_v1_auth_proto_rawDescGZIP(), []int{3}
}
func (x *PATReq) GetUserId() string {
if x != nil {
return x.UserId
}
return ""
}
func (x *PATReq) GetPatId() string {
if x != nil {
return x.PatId
@@ -316,25 +301,25 @@ func (x *PATReq) GetPatId() string {
return ""
}
func (x *PATReq) GetEntityType() uint32 {
func (x *PATReq) GetDomain() string {
if x != nil {
return x.EntityType
}
return 0
}
func (x *PATReq) GetOptionalDomainId() string {
if x != nil {
return x.OptionalDomainId
return x.Domain
}
return ""
}
func (x *PATReq) GetOperation() uint32 {
func (x *PATReq) GetOperation() string {
if x != nil {
return x.Operation
}
return 0
return ""
}
func (x *PATReq) GetUserId() string {
if x != nil {
return x.UserId
}
return ""
}
func (x *PATReq) GetEntityId() string {
@@ -344,13 +329,17 @@ func (x *PATReq) GetEntityId() string {
return ""
}
func (x *PATReq) GetEntityType() string {
if x != nil {
return x.EntityType
}
return ""
}
type AuthZReq struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to AuthType:
//
// *AuthZReq_Policy
// *AuthZReq_Pat
AuthType isAuthZReq_AuthType `protobuf_oneof:"auth_type"`
state protoimpl.MessageState `protogen:"open.v1"`
PolicyReq *PolicyReq `protobuf:"bytes,1,opt,name=policy_req,json=policyReq,proto3" json:"policy_req,omitempty"`
PatReq *PATReq `protobuf:"bytes,2,opt,name=pat_req,json=patReq,proto3,oneof" json:"pat_req,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@@ -385,47 +374,20 @@ func (*AuthZReq) Descriptor() ([]byte, []int) {
return file_auth_v1_auth_proto_rawDescGZIP(), []int{4}
}
func (x *AuthZReq) GetAuthType() isAuthZReq_AuthType {
func (x *AuthZReq) GetPolicyReq() *PolicyReq {
if x != nil {
return x.AuthType
return x.PolicyReq
}
return nil
}
func (x *AuthZReq) GetPolicy() *PolicyReq {
func (x *AuthZReq) GetPatReq() *PATReq {
if x != nil {
if x, ok := x.AuthType.(*AuthZReq_Policy); ok {
return x.Policy
}
return x.PatReq
}
return nil
}
func (x *AuthZReq) GetPat() *PATReq {
if x != nil {
if x, ok := x.AuthType.(*AuthZReq_Pat); ok {
return x.Pat
}
}
return nil
}
type isAuthZReq_AuthType interface {
isAuthZReq_AuthType()
}
type AuthZReq_Policy struct {
Policy *PolicyReq `protobuf:"bytes,1,opt,name=policy,proto3,oneof"` // Policy-based authorization
}
type AuthZReq_Pat struct {
Pat *PATReq `protobuf:"bytes,2,opt,name=pat,proto3,oneof"` // PAT authorization
}
func (*AuthZReq_Policy) isAuthZReq_AuthType() {}
func (*AuthZReq_Pat) isAuthZReq_AuthType() {}
type AuthZRes struct {
state protoimpl.MessageState `protogen:"open.v1"`
Authorized bool `protobuf:"varint,1,opt,name=authorized,proto3" json:"authorized,omitempty"`
@@ -491,35 +453,34 @@ const file_auth_v1_auth_proto_rawDesc = "" +
"\tuser_role\x18\x03 \x01(\rR\buserRole\x12\x1a\n" +
"\bverified\x18\x04 \x01(\bR\bverified\x12\x1d\n" +
"\n" +
"token_type\x18\x05 \x01(\rR\ttokenType\"\xc2\x02\n" +
"\tPolicyReq\x12\x1d\n" +
"token_type\x18\x05 \x01(\rR\ttokenType\"\xa3\x02\n" +
"\tPolicyReq\x12\x16\n" +
"\x06domain\x18\x01 \x01(\tR\x06domain\x12!\n" +
"\fsubject_type\x18\x02 \x01(\tR\vsubjectType\x12!\n" +
"\fsubject_kind\x18\x03 \x01(\tR\vsubjectKind\x12)\n" +
"\x10subject_relation\x18\x04 \x01(\tR\x0fsubjectRelation\x12\x18\n" +
"\asubject\x18\x05 \x01(\tR\asubject\x12\x1a\n" +
"\brelation\x18\x06 \x01(\tR\brelation\x12\x1e\n" +
"\n" +
"token_type\x18\x01 \x01(\rR\ttokenType\x12\x16\n" +
"\x06domain\x18\x02 \x01(\tR\x06domain\x12!\n" +
"\fsubject_type\x18\x03 \x01(\tR\vsubjectType\x12!\n" +
"\fsubject_kind\x18\x04 \x01(\tR\vsubjectKind\x12)\n" +
"\x10subject_relation\x18\x05 \x01(\tR\x0fsubjectRelation\x12\x18\n" +
"\asubject\x18\x06 \x01(\tR\asubject\x12\x1a\n" +
"\brelation\x18\a \x01(\tR\brelation\x12\x1e\n" +
"\n" +
"permission\x18\b \x01(\tR\n" +
"permission\x18\a \x01(\tR\n" +
"permission\x12\x16\n" +
"\x06object\x18\t \x01(\tR\x06object\x12\x1f\n" +
"\vobject_type\x18\n" +
" \x01(\tR\n" +
"objectType\"\xc2\x01\n" +
"\x06PATReq\x12\x17\n" +
"\auser_id\x18\x01 \x01(\tR\x06userId\x12\x15\n" +
"\x06pat_id\x18\x02 \x01(\tR\x05patId\x12\x1f\n" +
"\ventity_type\x18\x03 \x01(\rR\n" +
"entityType\x12,\n" +
"\x12optional_domain_id\x18\x04 \x01(\tR\x10optionalDomainId\x12\x1c\n" +
"\toperation\x18\x05 \x01(\rR\toperation\x12\x1b\n" +
"\tentity_id\x18\x06 \x01(\tR\bentityId\"j\n" +
"\bAuthZReq\x12,\n" +
"\x06policy\x18\x01 \x01(\v2\x12.auth.v1.PolicyReqH\x00R\x06policy\x12#\n" +
"\x03pat\x18\x02 \x01(\v2\x0f.auth.v1.PATReqH\x00R\x03patB\v\n" +
"\tauth_type\":\n" +
"\x06object\x18\b \x01(\tR\x06object\x12\x1f\n" +
"\vobject_type\x18\t \x01(\tR\n" +
"objectType\"\xac\x01\n" +
"\x06PATReq\x12\x15\n" +
"\x06pat_id\x18\x01 \x01(\tR\x05patId\x12\x16\n" +
"\x06domain\x18\x02 \x01(\tR\x06domain\x12\x1c\n" +
"\toperation\x18\x03 \x01(\tR\toperation\x12\x17\n" +
"\auser_id\x18\x04 \x01(\tR\x06userId\x12\x1b\n" +
"\tentity_id\x18\x05 \x01(\tR\bentityId\x12\x1f\n" +
"\ventity_type\x18\x06 \x01(\tR\n" +
"entityType\"x\n" +
"\bAuthZReq\x121\n" +
"\n" +
"policy_req\x18\x01 \x01(\v2\x12.auth.v1.PolicyReqR\tpolicyReq\x12-\n" +
"\apat_req\x18\x02 \x01(\v2\x0f.auth.v1.PATReqH\x00R\x06patReq\x88\x01\x01B\n" +
"\n" +
"\b_pat_req\":\n" +
"\bAuthZRes\x12\x1e\n" +
"\n" +
"authorized\x18\x01 \x01(\bR\n" +
@@ -527,7 +488,7 @@ const file_auth_v1_auth_proto_rawDesc = "" +
"\x02id\x18\x02 \x01(\tR\x02id2z\n" +
"\vAuthService\x123\n" +
"\tAuthorize\x12\x11.auth.v1.AuthZReq\x1a\x11.auth.v1.AuthZRes\"\x00\x126\n" +
"\fAuthenticate\x12\x11.auth.v1.AuthNReq\x1a\x11.auth.v1.AuthNRes\"\x00B-Z+github.com/absmach/supermq/api/grpc/auth/v1b\x06proto3"
"\fAuthenticate\x12\x11.auth.v1.AuthNReq\x1a\x11.auth.v1.AuthNRes\"\x00B0Z.github.com/absmach/magistrala/api/grpc/auth/v1b\x06proto3"
var (
file_auth_v1_auth_proto_rawDescOnce sync.Once
@@ -551,8 +512,8 @@ var file_auth_v1_auth_proto_goTypes = []any{
(*AuthZRes)(nil), // 5: auth.v1.AuthZRes
}
var file_auth_v1_auth_proto_depIdxs = []int32{
2, // 0: auth.v1.AuthZReq.policy:type_name -> auth.v1.PolicyReq
3, // 1: auth.v1.AuthZReq.pat:type_name -> auth.v1.PATReq
2, // 0: auth.v1.AuthZReq.policy_req:type_name -> auth.v1.PolicyReq
3, // 1: auth.v1.AuthZReq.pat_req:type_name -> auth.v1.PATReq
4, // 2: auth.v1.AuthService.Authorize:input_type -> auth.v1.AuthZReq
0, // 3: auth.v1.AuthService.Authenticate:input_type -> auth.v1.AuthNReq
5, // 4: auth.v1.AuthService.Authorize:output_type -> auth.v1.AuthZRes
@@ -569,10 +530,7 @@ func file_auth_v1_auth_proto_init() {
if File_auth_v1_auth_proto != nil {
return
}
file_auth_v1_auth_proto_msgTypes[4].OneofWrappers = []any{
(*AuthZReq_Policy)(nil),
(*AuthZReq_Pat)(nil),
}
file_auth_v1_auth_proto_msgTypes[4].OneofWrappers = []any{}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
+7 -7
View File
@@ -3,8 +3,8 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc v6.33.0
// - protoc-gen-go-grpc v1.6.2
// - protoc v7.35.1
// source: auth/v1/auth.proto
package v1
@@ -31,7 +31,7 @@ const (
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// AuthService is a service that provides authentication
// and authorization functionalities for SuperMQ services.
// and authorization functionalities for Magistrala services.
type AuthServiceClient interface {
Authorize(ctx context.Context, in *AuthZReq, opts ...grpc.CallOption) (*AuthZRes, error)
Authenticate(ctx context.Context, in *AuthNReq, opts ...grpc.CallOption) (*AuthNRes, error)
@@ -70,7 +70,7 @@ func (c *authServiceClient) Authenticate(ctx context.Context, in *AuthNReq, opts
// for forward compatibility.
//
// AuthService is a service that provides authentication
// and authorization functionalities for SuperMQ services.
// and authorization functionalities for Magistrala services.
type AuthServiceServer interface {
Authorize(context.Context, *AuthZReq) (*AuthZRes, error)
Authenticate(context.Context, *AuthNReq) (*AuthNRes, error)
@@ -85,10 +85,10 @@ type AuthServiceServer interface {
type UnimplementedAuthServiceServer struct{}
func (UnimplementedAuthServiceServer) Authorize(context.Context, *AuthZReq) (*AuthZRes, error) {
return nil, status.Errorf(codes.Unimplemented, "method Authorize not implemented")
return nil, status.Error(codes.Unimplemented, "method Authorize not implemented")
}
func (UnimplementedAuthServiceServer) Authenticate(context.Context, *AuthNReq) (*AuthNRes, error) {
return nil, status.Errorf(codes.Unimplemented, "method Authenticate not implemented")
return nil, status.Error(codes.Unimplemented, "method Authenticate not implemented")
}
func (UnimplementedAuthServiceServer) mustEmbedUnimplementedAuthServiceServer() {}
func (UnimplementedAuthServiceServer) testEmbeddedByValue() {}
@@ -101,7 +101,7 @@ type UnsafeAuthServiceServer interface {
}
func RegisterAuthServiceServer(s grpc.ServiceRegistrar, srv AuthServiceServer) {
// If the following call pancis, it indicates UnimplementedAuthServiceServer was
// If the following call panics, it indicates UnimplementedAuthServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
+228
View File
@@ -0,0 +1,228 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.11
// protoc v7.35.1
// source: certs/v1/certs.proto
package v1
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
emptypb "google.golang.org/protobuf/types/known/emptypb"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type EntityReq struct {
state protoimpl.MessageState `protogen:"open.v1"`
SerialNumber string `protobuf:"bytes,1,opt,name=serial_number,json=serialNumber,proto3" json:"serial_number,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *EntityReq) Reset() {
*x = EntityReq{}
mi := &file_certs_v1_certs_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *EntityReq) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EntityReq) ProtoMessage() {}
func (x *EntityReq) ProtoReflect() protoreflect.Message {
mi := &file_certs_v1_certs_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EntityReq.ProtoReflect.Descriptor instead.
func (*EntityReq) Descriptor() ([]byte, []int) {
return file_certs_v1_certs_proto_rawDescGZIP(), []int{0}
}
func (x *EntityReq) GetSerialNumber() string {
if x != nil {
return x.SerialNumber
}
return ""
}
type EntityRes struct {
state protoimpl.MessageState `protogen:"open.v1"`
EntityId string `protobuf:"bytes,1,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *EntityRes) Reset() {
*x = EntityRes{}
mi := &file_certs_v1_certs_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *EntityRes) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EntityRes) ProtoMessage() {}
func (x *EntityRes) ProtoReflect() protoreflect.Message {
mi := &file_certs_v1_certs_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EntityRes.ProtoReflect.Descriptor instead.
func (*EntityRes) Descriptor() ([]byte, []int) {
return file_certs_v1_certs_proto_rawDescGZIP(), []int{1}
}
func (x *EntityRes) GetEntityId() string {
if x != nil {
return x.EntityId
}
return ""
}
type RevokeReq struct {
state protoimpl.MessageState `protogen:"open.v1"`
EntityId string `protobuf:"bytes,1,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RevokeReq) Reset() {
*x = RevokeReq{}
mi := &file_certs_v1_certs_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RevokeReq) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RevokeReq) ProtoMessage() {}
func (x *RevokeReq) ProtoReflect() protoreflect.Message {
mi := &file_certs_v1_certs_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RevokeReq.ProtoReflect.Descriptor instead.
func (*RevokeReq) Descriptor() ([]byte, []int) {
return file_certs_v1_certs_proto_rawDescGZIP(), []int{2}
}
func (x *RevokeReq) GetEntityId() string {
if x != nil {
return x.EntityId
}
return ""
}
var File_certs_v1_certs_proto protoreflect.FileDescriptor
const file_certs_v1_certs_proto_rawDesc = "" +
"\n" +
"\x14certs/v1/certs.proto\x12\rabsmach.certs\x1a\x1bgoogle/protobuf/empty.proto\"0\n" +
"\tEntityReq\x12#\n" +
"\rserial_number\x18\x01 \x01(\tR\fserialNumber\"(\n" +
"\tEntityRes\x12\x1b\n" +
"\tentity_id\x18\x01 \x01(\tR\bentityId\"(\n" +
"\tRevokeReq\x12\x1b\n" +
"\tentity_id\x18\x01 \x01(\tR\bentityId2\x96\x01\n" +
"\fCertsService\x12C\n" +
"\vGetEntityID\x12\x18.absmach.certs.EntityReq\x1a\x18.absmach.certs.EntityRes\"\x00\x12A\n" +
"\vRevokeCerts\x12\x18.absmach.certs.RevokeReq\x1a\x16.google.protobuf.Empty\"\x00B1Z/github.com/absmach/magistrala/api/grpc/certs/v1b\x06proto3"
var (
file_certs_v1_certs_proto_rawDescOnce sync.Once
file_certs_v1_certs_proto_rawDescData []byte
)
func file_certs_v1_certs_proto_rawDescGZIP() []byte {
file_certs_v1_certs_proto_rawDescOnce.Do(func() {
file_certs_v1_certs_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_certs_v1_certs_proto_rawDesc), len(file_certs_v1_certs_proto_rawDesc)))
})
return file_certs_v1_certs_proto_rawDescData
}
var file_certs_v1_certs_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_certs_v1_certs_proto_goTypes = []any{
(*EntityReq)(nil), // 0: absmach.certs.EntityReq
(*EntityRes)(nil), // 1: absmach.certs.EntityRes
(*RevokeReq)(nil), // 2: absmach.certs.RevokeReq
(*emptypb.Empty)(nil), // 3: google.protobuf.Empty
}
var file_certs_v1_certs_proto_depIdxs = []int32{
0, // 0: absmach.certs.CertsService.GetEntityID:input_type -> absmach.certs.EntityReq
2, // 1: absmach.certs.CertsService.RevokeCerts:input_type -> absmach.certs.RevokeReq
1, // 2: absmach.certs.CertsService.GetEntityID:output_type -> absmach.certs.EntityRes
3, // 3: absmach.certs.CertsService.RevokeCerts:output_type -> google.protobuf.Empty
2, // [2:4] is the sub-list for method output_type
0, // [0:2] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_certs_v1_certs_proto_init() }
func file_certs_v1_certs_proto_init() {
if File_certs_v1_certs_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_certs_v1_certs_proto_rawDesc), len(file_certs_v1_certs_proto_rawDesc)),
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_certs_v1_certs_proto_goTypes,
DependencyIndexes: file_certs_v1_certs_proto_depIdxs,
MessageInfos: file_certs_v1_certs_proto_msgTypes,
}.Build()
File_certs_v1_certs_proto = out.File
file_certs_v1_certs_proto_goTypes = nil
file_certs_v1_certs_proto_depIdxs = nil
}
+163
View File
@@ -0,0 +1,163 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.6.2
// - protoc v7.35.1
// source: certs/v1/certs.proto
package v1
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
CertsService_GetEntityID_FullMethodName = "/absmach.certs.CertsService/GetEntityID"
CertsService_RevokeCerts_FullMethodName = "/absmach.certs.CertsService/RevokeCerts"
)
// CertsServiceClient is the client API for CertsService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type CertsServiceClient interface {
GetEntityID(ctx context.Context, in *EntityReq, opts ...grpc.CallOption) (*EntityRes, error)
RevokeCerts(ctx context.Context, in *RevokeReq, opts ...grpc.CallOption) (*emptypb.Empty, error)
}
type certsServiceClient struct {
cc grpc.ClientConnInterface
}
func NewCertsServiceClient(cc grpc.ClientConnInterface) CertsServiceClient {
return &certsServiceClient{cc}
}
func (c *certsServiceClient) GetEntityID(ctx context.Context, in *EntityReq, opts ...grpc.CallOption) (*EntityRes, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(EntityRes)
err := c.cc.Invoke(ctx, CertsService_GetEntityID_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *certsServiceClient) RevokeCerts(ctx context.Context, in *RevokeReq, opts ...grpc.CallOption) (*emptypb.Empty, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, CertsService_RevokeCerts_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// CertsServiceServer is the server API for CertsService service.
// All implementations must embed UnimplementedCertsServiceServer
// for forward compatibility.
type CertsServiceServer interface {
GetEntityID(context.Context, *EntityReq) (*EntityRes, error)
RevokeCerts(context.Context, *RevokeReq) (*emptypb.Empty, error)
mustEmbedUnimplementedCertsServiceServer()
}
// UnimplementedCertsServiceServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedCertsServiceServer struct{}
func (UnimplementedCertsServiceServer) GetEntityID(context.Context, *EntityReq) (*EntityRes, error) {
return nil, status.Error(codes.Unimplemented, "method GetEntityID not implemented")
}
func (UnimplementedCertsServiceServer) RevokeCerts(context.Context, *RevokeReq) (*emptypb.Empty, error) {
return nil, status.Error(codes.Unimplemented, "method RevokeCerts not implemented")
}
func (UnimplementedCertsServiceServer) mustEmbedUnimplementedCertsServiceServer() {}
func (UnimplementedCertsServiceServer) testEmbeddedByValue() {}
// UnsafeCertsServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to CertsServiceServer will
// result in compilation errors.
type UnsafeCertsServiceServer interface {
mustEmbedUnimplementedCertsServiceServer()
}
func RegisterCertsServiceServer(s grpc.ServiceRegistrar, srv CertsServiceServer) {
// If the following call panics, it indicates UnimplementedCertsServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&CertsService_ServiceDesc, srv)
}
func _CertsService_GetEntityID_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(EntityReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(CertsServiceServer).GetEntityID(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: CertsService_GetEntityID_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(CertsServiceServer).GetEntityID(ctx, req.(*EntityReq))
}
return interceptor(ctx, in, info, handler)
}
func _CertsService_RevokeCerts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RevokeReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(CertsServiceServer).RevokeCerts(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: CertsService_RevokeCerts_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(CertsServiceServer).RevokeCerts(ctx, req.(*RevokeReq))
}
return interceptor(ctx, in, info, handler)
}
// CertsService_ServiceDesc is the grpc.ServiceDesc for CertsService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var CertsService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "absmach.certs.CertsService",
HandlerType: (*CertsServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetEntityID",
Handler: _CertsService_GetEntityID_Handler,
},
{
MethodName: "RevokeCerts",
Handler: _CertsService_RevokeCerts_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "certs/v1/certs.proto",
}
+4 -4
View File
@@ -3,14 +3,14 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v6.33.0
// protoc-gen-go v1.36.11
// protoc v7.35.1
// source: channels/v1/channels.proto
package v1
import (
v1 "github.com/absmach/supermq/api/grpc/common/v1"
v1 "github.com/absmach/magistrala/api/grpc/common/v1"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
@@ -333,7 +333,7 @@ const file_channels_v1_channels_proto_rawDesc = "" +
"\x17RemoveClientConnections\x12'.channels.v1.RemoveClientConnectionsReq\x1a'.channels.v1.RemoveClientConnectionsRes\"\x00\x12|\n" +
"\x1cUnsetParentGroupFromChannels\x12,.channels.v1.UnsetParentGroupFromChannelsReq\x1a,.channels.v1.UnsetParentGroupFromChannelsRes\"\x00\x12N\n" +
"\x0eRetrieveEntity\x12\x1c.common.v1.RetrieveEntityReq\x1a\x1c.common.v1.RetrieveEntityRes\"\x00\x12T\n" +
"\x11RetrieveIDByRoute\x12\x1f.common.v1.RetrieveIDByRouteReq\x1a\x1c.common.v1.RetrieveEntityRes\"\x00B1Z/github.com/absmach/supermq/api/grpc/channels/v1b\x06proto3"
"\x11RetrieveIDByRoute\x12\x1f.common.v1.RetrieveIDByRouteReq\x1a\x1c.common.v1.RetrieveEntityRes\"\x00B4Z2github.com/absmach/magistrala/api/grpc/channels/v1b\x06proto3"
var (
file_channels_v1_channels_proto_rawDescOnce sync.Once
+9 -9
View File
@@ -3,15 +3,15 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc v6.33.0
// - protoc-gen-go-grpc v1.6.2
// - protoc v7.35.1
// source: channels/v1/channels.proto
package v1
import (
context "context"
v1 "github.com/absmach/supermq/api/grpc/common/v1"
v1 "github.com/absmach/magistrala/api/grpc/common/v1"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
@@ -119,19 +119,19 @@ type ChannelsServiceServer interface {
type UnimplementedChannelsServiceServer struct{}
func (UnimplementedChannelsServiceServer) Authorize(context.Context, *AuthzReq) (*AuthzRes, error) {
return nil, status.Errorf(codes.Unimplemented, "method Authorize not implemented")
return nil, status.Error(codes.Unimplemented, "method Authorize not implemented")
}
func (UnimplementedChannelsServiceServer) RemoveClientConnections(context.Context, *RemoveClientConnectionsReq) (*RemoveClientConnectionsRes, error) {
return nil, status.Errorf(codes.Unimplemented, "method RemoveClientConnections not implemented")
return nil, status.Error(codes.Unimplemented, "method RemoveClientConnections not implemented")
}
func (UnimplementedChannelsServiceServer) UnsetParentGroupFromChannels(context.Context, *UnsetParentGroupFromChannelsReq) (*UnsetParentGroupFromChannelsRes, error) {
return nil, status.Errorf(codes.Unimplemented, "method UnsetParentGroupFromChannels not implemented")
return nil, status.Error(codes.Unimplemented, "method UnsetParentGroupFromChannels not implemented")
}
func (UnimplementedChannelsServiceServer) RetrieveEntity(context.Context, *v1.RetrieveEntityReq) (*v1.RetrieveEntityRes, error) {
return nil, status.Errorf(codes.Unimplemented, "method RetrieveEntity not implemented")
return nil, status.Error(codes.Unimplemented, "method RetrieveEntity not implemented")
}
func (UnimplementedChannelsServiceServer) RetrieveIDByRoute(context.Context, *v1.RetrieveIDByRouteReq) (*v1.RetrieveEntityRes, error) {
return nil, status.Errorf(codes.Unimplemented, "method RetrieveIDByRoute not implemented")
return nil, status.Error(codes.Unimplemented, "method RetrieveIDByRoute not implemented")
}
func (UnimplementedChannelsServiceServer) mustEmbedUnimplementedChannelsServiceServer() {}
func (UnimplementedChannelsServiceServer) testEmbeddedByValue() {}
@@ -144,7 +144,7 @@ type UnsafeChannelsServiceServer interface {
}
func RegisterChannelsServiceServer(s grpc.ServiceRegistrar, srv ChannelsServiceServer) {
// If the following call pancis, it indicates UnimplementedChannelsServiceServer was
// If the following call panics, it indicates UnimplementedChannelsServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
+4 -4
View File
@@ -3,14 +3,14 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v6.33.0
// protoc-gen-go v1.36.11
// protoc v7.35.1
// source: clients/v1/clients.proto
package v1
import (
v1 "github.com/absmach/supermq/api/grpc/common/v1"
v1 "github.com/absmach/magistrala/api/grpc/common/v1"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
@@ -306,7 +306,7 @@ const file_clients_v1_clients_proto_rawDesc = "" +
"\x0eAddConnections\x12\x1c.common.v1.AddConnectionsReq\x1a\x1c.common.v1.AddConnectionsRes\"\x00\x12W\n" +
"\x11RemoveConnections\x12\x1f.common.v1.RemoveConnectionsReq\x1a\x1f.common.v1.RemoveConnectionsRes\"\x00\x12n\n" +
"\x18RemoveChannelConnections\x12'.clients.v1.RemoveChannelConnectionsReq\x1a'.clients.v1.RemoveChannelConnectionsRes\"\x00\x12t\n" +
"\x1aUnsetParentGroupFromClient\x12).clients.v1.UnsetParentGroupFromClientReq\x1a).clients.v1.UnsetParentGroupFromClientRes\"\x00B0Z.github.com/absmach/supermq/api/grpc/clients/v1b\x06proto3"
"\x1aUnsetParentGroupFromClient\x12).clients.v1.UnsetParentGroupFromClientReq\x1a).clients.v1.UnsetParentGroupFromClientRes\"\x00B3Z1github.com/absmach/magistrala/api/grpc/clients/v1b\x06proto3"
var (
file_clients_v1_clients_proto_rawDescOnce sync.Once
+13 -13
View File
@@ -3,15 +3,15 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc v6.33.0
// - protoc-gen-go-grpc v1.6.2
// - protoc v7.35.1
// source: clients/v1/clients.proto
package v1
import (
context "context"
v1 "github.com/absmach/supermq/api/grpc/common/v1"
v1 "github.com/absmach/magistrala/api/grpc/common/v1"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
@@ -37,7 +37,7 @@ const (
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// ClientsService is a service that provides clients
// authorization functionalities for SuperMQ services.
// authorization functionalities for Magistrala services.
type ClientsServiceClient interface {
// Authorize checks if the client is authorized to perform
Authenticate(ctx context.Context, in *AuthnReq, opts ...grpc.CallOption) (*AuthnRes, error)
@@ -132,7 +132,7 @@ func (c *clientsServiceClient) UnsetParentGroupFromClient(ctx context.Context, i
// for forward compatibility.
//
// ClientsService is a service that provides clients
// authorization functionalities for SuperMQ services.
// authorization functionalities for Magistrala services.
type ClientsServiceServer interface {
// Authorize checks if the client is authorized to perform
Authenticate(context.Context, *AuthnReq) (*AuthnRes, error)
@@ -153,25 +153,25 @@ type ClientsServiceServer interface {
type UnimplementedClientsServiceServer struct{}
func (UnimplementedClientsServiceServer) Authenticate(context.Context, *AuthnReq) (*AuthnRes, error) {
return nil, status.Errorf(codes.Unimplemented, "method Authenticate not implemented")
return nil, status.Error(codes.Unimplemented, "method Authenticate not implemented")
}
func (UnimplementedClientsServiceServer) RetrieveEntity(context.Context, *v1.RetrieveEntityReq) (*v1.RetrieveEntityRes, error) {
return nil, status.Errorf(codes.Unimplemented, "method RetrieveEntity not implemented")
return nil, status.Error(codes.Unimplemented, "method RetrieveEntity not implemented")
}
func (UnimplementedClientsServiceServer) RetrieveEntities(context.Context, *v1.RetrieveEntitiesReq) (*v1.RetrieveEntitiesRes, error) {
return nil, status.Errorf(codes.Unimplemented, "method RetrieveEntities not implemented")
return nil, status.Error(codes.Unimplemented, "method RetrieveEntities not implemented")
}
func (UnimplementedClientsServiceServer) AddConnections(context.Context, *v1.AddConnectionsReq) (*v1.AddConnectionsRes, error) {
return nil, status.Errorf(codes.Unimplemented, "method AddConnections not implemented")
return nil, status.Error(codes.Unimplemented, "method AddConnections not implemented")
}
func (UnimplementedClientsServiceServer) RemoveConnections(context.Context, *v1.RemoveConnectionsReq) (*v1.RemoveConnectionsRes, error) {
return nil, status.Errorf(codes.Unimplemented, "method RemoveConnections not implemented")
return nil, status.Error(codes.Unimplemented, "method RemoveConnections not implemented")
}
func (UnimplementedClientsServiceServer) RemoveChannelConnections(context.Context, *RemoveChannelConnectionsReq) (*RemoveChannelConnectionsRes, error) {
return nil, status.Errorf(codes.Unimplemented, "method RemoveChannelConnections not implemented")
return nil, status.Error(codes.Unimplemented, "method RemoveChannelConnections not implemented")
}
func (UnimplementedClientsServiceServer) UnsetParentGroupFromClient(context.Context, *UnsetParentGroupFromClientReq) (*UnsetParentGroupFromClientRes, error) {
return nil, status.Errorf(codes.Unimplemented, "method UnsetParentGroupFromClient not implemented")
return nil, status.Error(codes.Unimplemented, "method UnsetParentGroupFromClient not implemented")
}
func (UnimplementedClientsServiceServer) mustEmbedUnimplementedClientsServiceServer() {}
func (UnimplementedClientsServiceServer) testEmbeddedByValue() {}
@@ -184,7 +184,7 @@ type UnsafeClientsServiceServer interface {
}
func RegisterClientsServiceServer(s grpc.ServiceRegistrar, srv ClientsServiceServer) {
// If the following call pancis, it indicates UnimplementedClientsServiceServer was
// If the following call panics, it indicates UnimplementedClientsServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
+3 -3
View File
@@ -3,8 +3,8 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v6.33.0
// protoc-gen-go v1.36.11
// protoc v7.35.1
// source: common/v1/common.proto
package v1
@@ -626,7 +626,7 @@ const file_common_v1_common_proto_rawDesc = "" +
"\x04type\x18\x04 \x01(\rR\x04type\"I\n" +
"\x14RetrieveIDByRouteReq\x12\x14\n" +
"\x05route\x18\x01 \x01(\tR\x05route\x12\x1b\n" +
"\tdomain_id\x18\x02 \x01(\tR\bdomainIdB/Z-github.com/absmach/supermq/api/grpc/common/v1b\x06proto3"
"\tdomain_id\x18\x02 \x01(\tR\bdomainIdB2Z0github.com/absmach/magistrala/api/grpc/common/v1b\x06proto3"
var (
file_common_v1_common_proto_rawDescOnce sync.Once
+4 -4
View File
@@ -3,14 +3,14 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v6.33.0
// protoc-gen-go v1.36.11
// protoc v7.35.1
// source: domains/v1/domains.proto
package v1
import (
v1 "github.com/absmach/supermq/api/grpc/common/v1"
v1 "github.com/absmach/magistrala/api/grpc/common/v1"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
@@ -126,7 +126,7 @@ const file_domains_v1_domains_proto_rawDesc = "" +
"\x0eDomainsService\x12O\n" +
"\x15DeleteUserFromDomains\x12\x19.domains.v1.DeleteUserReq\x1a\x19.domains.v1.DeleteUserRes\"\x00\x12N\n" +
"\x0eRetrieveStatus\x12\x1c.common.v1.RetrieveEntityReq\x1a\x1c.common.v1.RetrieveEntityRes\"\x00\x12T\n" +
"\x11RetrieveIDByRoute\x12\x1f.common.v1.RetrieveIDByRouteReq\x1a\x1c.common.v1.RetrieveEntityRes\"\x00B5Z3github.com/absmach/supermq/internal/grpc/domains/v1b\x06proto3"
"\x11RetrieveIDByRoute\x12\x1f.common.v1.RetrieveIDByRouteReq\x1a\x1c.common.v1.RetrieveEntityRes\"\x00B8Z6github.com/absmach/magistrala/internal/grpc/domains/v1b\x06proto3"
var (
file_domains_v1_domains_proto_rawDescOnce sync.Once
+9 -9
View File
@@ -3,15 +3,15 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc v6.33.0
// - protoc-gen-go-grpc v1.6.2
// - protoc v7.35.1
// source: domains/v1/domains.proto
package v1
import (
context "context"
v1 "github.com/absmach/supermq/api/grpc/common/v1"
v1 "github.com/absmach/magistrala/api/grpc/common/v1"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
@@ -33,7 +33,7 @@ const (
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// DomainsService is a service that provides access to
// domains functionalities for SuperMQ services.
// domains functionalities for Magistrala services.
type DomainsServiceClient interface {
DeleteUserFromDomains(ctx context.Context, in *DeleteUserReq, opts ...grpc.CallOption) (*DeleteUserRes, error)
RetrieveStatus(ctx context.Context, in *v1.RetrieveEntityReq, opts ...grpc.CallOption) (*v1.RetrieveEntityRes, error)
@@ -83,7 +83,7 @@ func (c *domainsServiceClient) RetrieveIDByRoute(ctx context.Context, in *v1.Ret
// for forward compatibility.
//
// DomainsService is a service that provides access to
// domains functionalities for SuperMQ services.
// domains functionalities for Magistrala services.
type DomainsServiceServer interface {
DeleteUserFromDomains(context.Context, *DeleteUserReq) (*DeleteUserRes, error)
RetrieveStatus(context.Context, *v1.RetrieveEntityReq) (*v1.RetrieveEntityRes, error)
@@ -99,13 +99,13 @@ type DomainsServiceServer interface {
type UnimplementedDomainsServiceServer struct{}
func (UnimplementedDomainsServiceServer) DeleteUserFromDomains(context.Context, *DeleteUserReq) (*DeleteUserRes, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteUserFromDomains not implemented")
return nil, status.Error(codes.Unimplemented, "method DeleteUserFromDomains not implemented")
}
func (UnimplementedDomainsServiceServer) RetrieveStatus(context.Context, *v1.RetrieveEntityReq) (*v1.RetrieveEntityRes, error) {
return nil, status.Errorf(codes.Unimplemented, "method RetrieveStatus not implemented")
return nil, status.Error(codes.Unimplemented, "method RetrieveStatus not implemented")
}
func (UnimplementedDomainsServiceServer) RetrieveIDByRoute(context.Context, *v1.RetrieveIDByRouteReq) (*v1.RetrieveEntityRes, error) {
return nil, status.Errorf(codes.Unimplemented, "method RetrieveIDByRoute not implemented")
return nil, status.Error(codes.Unimplemented, "method RetrieveIDByRoute not implemented")
}
func (UnimplementedDomainsServiceServer) mustEmbedUnimplementedDomainsServiceServer() {}
func (UnimplementedDomainsServiceServer) testEmbeddedByValue() {}
@@ -118,7 +118,7 @@ type UnsafeDomainsServiceServer interface {
}
func RegisterDomainsServiceServer(s grpc.ServiceRegistrar, srv DomainsServiceServer) {
// If the following call pancis, it indicates UnimplementedDomainsServiceServer was
// If the following call panics, it indicates UnimplementedDomainsServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
+4 -4
View File
@@ -3,14 +3,14 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v6.33.0
// protoc-gen-go v1.36.11
// protoc v7.35.1
// source: groups/v1/groups.proto
package v1
import (
v1 "github.com/absmach/supermq/api/grpc/common/v1"
v1 "github.com/absmach/magistrala/api/grpc/common/v1"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
@@ -30,7 +30,7 @@ const file_groups_v1_groups_proto_rawDesc = "" +
"\n" +
"\x16groups/v1/groups.proto\x12\tgroups.v1\x1a\x16common/v1/common.proto2_\n" +
"\rGroupsService\x12N\n" +
"\x0eRetrieveEntity\x12\x1c.common.v1.RetrieveEntityReq\x1a\x1c.common.v1.RetrieveEntityRes\"\x00B/Z-github.com/absmach/supermq/api/grpc/groups/v1b\x06proto3"
"\x0eRetrieveEntity\x12\x1c.common.v1.RetrieveEntityReq\x1a\x1c.common.v1.RetrieveEntityRes\"\x00B2Z0github.com/absmach/magistrala/api/grpc/groups/v1b\x06proto3"
var file_groups_v1_groups_proto_goTypes = []any{
(*v1.RetrieveEntityReq)(nil), // 0: common.v1.RetrieveEntityReq
+7 -7
View File
@@ -3,15 +3,15 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc v6.33.0
// - protoc-gen-go-grpc v1.6.2
// - protoc v7.35.1
// source: groups/v1/groups.proto
package v1
import (
context "context"
v1 "github.com/absmach/supermq/api/grpc/common/v1"
v1 "github.com/absmach/magistrala/api/grpc/common/v1"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
@@ -31,7 +31,7 @@ const (
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// GroupssService is a service that provides groups
// functionalities for SuperMQ services.
// functionalities for Magistrala services.
type GroupsServiceClient interface {
RetrieveEntity(ctx context.Context, in *v1.RetrieveEntityReq, opts ...grpc.CallOption) (*v1.RetrieveEntityRes, error)
}
@@ -59,7 +59,7 @@ func (c *groupsServiceClient) RetrieveEntity(ctx context.Context, in *v1.Retriev
// for forward compatibility.
//
// GroupssService is a service that provides groups
// functionalities for SuperMQ services.
// functionalities for Magistrala services.
type GroupsServiceServer interface {
RetrieveEntity(context.Context, *v1.RetrieveEntityReq) (*v1.RetrieveEntityRes, error)
mustEmbedUnimplementedGroupsServiceServer()
@@ -73,7 +73,7 @@ type GroupsServiceServer interface {
type UnimplementedGroupsServiceServer struct{}
func (UnimplementedGroupsServiceServer) RetrieveEntity(context.Context, *v1.RetrieveEntityReq) (*v1.RetrieveEntityRes, error) {
return nil, status.Errorf(codes.Unimplemented, "method RetrieveEntity not implemented")
return nil, status.Error(codes.Unimplemented, "method RetrieveEntity not implemented")
}
func (UnimplementedGroupsServiceServer) mustEmbedUnimplementedGroupsServiceServer() {}
func (UnimplementedGroupsServiceServer) testEmbeddedByValue() {}
@@ -86,7 +86,7 @@ type UnsafeGroupsServiceServer interface {
}
func RegisterGroupsServiceServer(s grpc.ServiceRegistrar, srv GroupsServiceServer) {
// If the following call pancis, it indicates UnimplementedGroupsServiceServer was
// If the following call panics, it indicates UnimplementedGroupsServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
+884
View File
@@ -0,0 +1,884 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.11
// protoc v7.35.1
// source: readers/v1/readers.proto
package v1
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// Aggregation defines supported data aggregations.
type Aggregation int32
const (
Aggregation_AGGREGATION_UNSPECIFIED Aggregation = 0
Aggregation_AGGREGATION_MAX Aggregation = 1
Aggregation_AGGREGATION_MIN Aggregation = 2
Aggregation_AGGREGATION_SUM Aggregation = 3
Aggregation_AGGREGATION_COUNT Aggregation = 4
Aggregation_AGGREGATION_AVG Aggregation = 5
)
// Enum value maps for Aggregation.
var (
Aggregation_name = map[int32]string{
0: "AGGREGATION_UNSPECIFIED",
1: "AGGREGATION_MAX",
2: "AGGREGATION_MIN",
3: "AGGREGATION_SUM",
4: "AGGREGATION_COUNT",
5: "AGGREGATION_AVG",
}
Aggregation_value = map[string]int32{
"AGGREGATION_UNSPECIFIED": 0,
"AGGREGATION_MAX": 1,
"AGGREGATION_MIN": 2,
"AGGREGATION_SUM": 3,
"AGGREGATION_COUNT": 4,
"AGGREGATION_AVG": 5,
}
)
func (x Aggregation) Enum() *Aggregation {
p := new(Aggregation)
*p = x
return p
}
func (x Aggregation) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (Aggregation) Descriptor() protoreflect.EnumDescriptor {
return file_readers_v1_readers_proto_enumTypes[0].Descriptor()
}
func (Aggregation) Type() protoreflect.EnumType {
return &file_readers_v1_readers_proto_enumTypes[0]
}
func (x Aggregation) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use Aggregation.Descriptor instead.
func (Aggregation) EnumDescriptor() ([]byte, []int) {
return file_readers_v1_readers_proto_rawDescGZIP(), []int{0}
}
type PageMetadata struct {
state protoimpl.MessageState `protogen:"open.v1"`
Limit uint64 `protobuf:"varint,1,opt,name=limit,proto3" json:"limit,omitempty"`
Offset uint64 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"`
Protocol string `protobuf:"bytes,3,opt,name=protocol,proto3" json:"protocol,omitempty"`
Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"`
Value float64 `protobuf:"fixed64,5,opt,name=value,proto3" json:"value,omitempty"`
Publisher string `protobuf:"bytes,6,opt,name=publisher,proto3" json:"publisher,omitempty"`
BoolValue bool `protobuf:"varint,7,opt,name=bool_value,json=boolValue,proto3" json:"bool_value,omitempty"`
StringValue string `protobuf:"bytes,8,opt,name=string_value,json=stringValue,proto3" json:"string_value,omitempty"`
DataValue string `protobuf:"bytes,9,opt,name=data_value,json=dataValue,proto3" json:"data_value,omitempty"`
From float64 `protobuf:"fixed64,10,opt,name=from,proto3" json:"from,omitempty"`
To float64 `protobuf:"fixed64,11,opt,name=to,proto3" json:"to,omitempty"`
Subtopic string `protobuf:"bytes,12,opt,name=subtopic,proto3" json:"subtopic,omitempty"`
Interval string `protobuf:"bytes,13,opt,name=interval,proto3" json:"interval,omitempty"`
Read bool `protobuf:"varint,14,opt,name=read,proto3" json:"read,omitempty"`
Aggregation Aggregation `protobuf:"varint,15,opt,name=aggregation,proto3,enum=readers.v1.Aggregation" json:"aggregation,omitempty"`
Comparator string `protobuf:"bytes,16,opt,name=comparator,proto3" json:"comparator,omitempty"`
Format string `protobuf:"bytes,17,opt,name=format,proto3" json:"format,omitempty"`
Order string `protobuf:"bytes,18,opt,name=order,proto3" json:"order,omitempty"`
Dir string `protobuf:"bytes,19,opt,name=dir,proto3" json:"dir,omitempty"`
Publishers []string `protobuf:"bytes,20,rep,name=publishers,proto3" json:"publishers,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PageMetadata) Reset() {
*x = PageMetadata{}
mi := &file_readers_v1_readers_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PageMetadata) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PageMetadata) ProtoMessage() {}
func (x *PageMetadata) ProtoReflect() protoreflect.Message {
mi := &file_readers_v1_readers_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PageMetadata.ProtoReflect.Descriptor instead.
func (*PageMetadata) Descriptor() ([]byte, []int) {
return file_readers_v1_readers_proto_rawDescGZIP(), []int{0}
}
func (x *PageMetadata) GetLimit() uint64 {
if x != nil {
return x.Limit
}
return 0
}
func (x *PageMetadata) GetOffset() uint64 {
if x != nil {
return x.Offset
}
return 0
}
func (x *PageMetadata) GetProtocol() string {
if x != nil {
return x.Protocol
}
return ""
}
func (x *PageMetadata) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *PageMetadata) GetValue() float64 {
if x != nil {
return x.Value
}
return 0
}
func (x *PageMetadata) GetPublisher() string {
if x != nil {
return x.Publisher
}
return ""
}
func (x *PageMetadata) GetBoolValue() bool {
if x != nil {
return x.BoolValue
}
return false
}
func (x *PageMetadata) GetStringValue() string {
if x != nil {
return x.StringValue
}
return ""
}
func (x *PageMetadata) GetDataValue() string {
if x != nil {
return x.DataValue
}
return ""
}
func (x *PageMetadata) GetFrom() float64 {
if x != nil {
return x.From
}
return 0
}
func (x *PageMetadata) GetTo() float64 {
if x != nil {
return x.To
}
return 0
}
func (x *PageMetadata) GetSubtopic() string {
if x != nil {
return x.Subtopic
}
return ""
}
func (x *PageMetadata) GetInterval() string {
if x != nil {
return x.Interval
}
return ""
}
func (x *PageMetadata) GetRead() bool {
if x != nil {
return x.Read
}
return false
}
func (x *PageMetadata) GetAggregation() Aggregation {
if x != nil {
return x.Aggregation
}
return Aggregation_AGGREGATION_UNSPECIFIED
}
func (x *PageMetadata) GetComparator() string {
if x != nil {
return x.Comparator
}
return ""
}
func (x *PageMetadata) GetFormat() string {
if x != nil {
return x.Format
}
return ""
}
func (x *PageMetadata) GetOrder() string {
if x != nil {
return x.Order
}
return ""
}
func (x *PageMetadata) GetDir() string {
if x != nil {
return x.Dir
}
return ""
}
func (x *PageMetadata) GetPublishers() []string {
if x != nil {
return x.Publishers
}
return nil
}
type ReadMessagesRes struct {
state protoimpl.MessageState `protogen:"open.v1"`
Total uint64 `protobuf:"varint,1,opt,name=total,proto3" json:"total,omitempty"`
PageMetadata *PageMetadata `protobuf:"bytes,2,opt,name=page_metadata,json=pageMetadata,proto3" json:"page_metadata,omitempty"`
Messages []*Message `protobuf:"bytes,3,rep,name=messages,proto3" json:"messages,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ReadMessagesRes) Reset() {
*x = ReadMessagesRes{}
mi := &file_readers_v1_readers_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ReadMessagesRes) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReadMessagesRes) ProtoMessage() {}
func (x *ReadMessagesRes) ProtoReflect() protoreflect.Message {
mi := &file_readers_v1_readers_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReadMessagesRes.ProtoReflect.Descriptor instead.
func (*ReadMessagesRes) Descriptor() ([]byte, []int) {
return file_readers_v1_readers_proto_rawDescGZIP(), []int{1}
}
func (x *ReadMessagesRes) GetTotal() uint64 {
if x != nil {
return x.Total
}
return 0
}
func (x *ReadMessagesRes) GetPageMetadata() *PageMetadata {
if x != nil {
return x.PageMetadata
}
return nil
}
func (x *ReadMessagesRes) GetMessages() []*Message {
if x != nil {
return x.Messages
}
return nil
}
type Message struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Payload:
//
// *Message_Senml
// *Message_Json
Payload isMessage_Payload `protobuf_oneof:"payload"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Message) Reset() {
*x = Message{}
mi := &file_readers_v1_readers_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Message) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Message) ProtoMessage() {}
func (x *Message) ProtoReflect() protoreflect.Message {
mi := &file_readers_v1_readers_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Message.ProtoReflect.Descriptor instead.
func (*Message) Descriptor() ([]byte, []int) {
return file_readers_v1_readers_proto_rawDescGZIP(), []int{2}
}
func (x *Message) GetPayload() isMessage_Payload {
if x != nil {
return x.Payload
}
return nil
}
func (x *Message) GetSenml() *SenMLMessage {
if x != nil {
if x, ok := x.Payload.(*Message_Senml); ok {
return x.Senml
}
}
return nil
}
func (x *Message) GetJson() *JsonMessage {
if x != nil {
if x, ok := x.Payload.(*Message_Json); ok {
return x.Json
}
}
return nil
}
type isMessage_Payload interface {
isMessage_Payload()
}
type Message_Senml struct {
Senml *SenMLMessage `protobuf:"bytes,1,opt,name=senml,proto3,oneof"`
}
type Message_Json struct {
Json *JsonMessage `protobuf:"bytes,2,opt,name=json,proto3,oneof"`
}
func (*Message_Senml) isMessage_Payload() {}
func (*Message_Json) isMessage_Payload() {}
type BaseMessage struct {
state protoimpl.MessageState `protogen:"open.v1"`
Channel string `protobuf:"bytes,1,opt,name=channel,proto3" json:"channel,omitempty"`
Subtopic string `protobuf:"bytes,2,opt,name=subtopic,proto3" json:"subtopic,omitempty"`
Publisher string `protobuf:"bytes,3,opt,name=publisher,proto3" json:"publisher,omitempty"`
Protocol string `protobuf:"bytes,4,opt,name=protocol,proto3" json:"protocol,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BaseMessage) Reset() {
*x = BaseMessage{}
mi := &file_readers_v1_readers_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BaseMessage) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BaseMessage) ProtoMessage() {}
func (x *BaseMessage) ProtoReflect() protoreflect.Message {
mi := &file_readers_v1_readers_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BaseMessage.ProtoReflect.Descriptor instead.
func (*BaseMessage) Descriptor() ([]byte, []int) {
return file_readers_v1_readers_proto_rawDescGZIP(), []int{3}
}
func (x *BaseMessage) GetChannel() string {
if x != nil {
return x.Channel
}
return ""
}
func (x *BaseMessage) GetSubtopic() string {
if x != nil {
return x.Subtopic
}
return ""
}
func (x *BaseMessage) GetPublisher() string {
if x != nil {
return x.Publisher
}
return ""
}
func (x *BaseMessage) GetProtocol() string {
if x != nil {
return x.Protocol
}
return ""
}
type SenMLMessage struct {
state protoimpl.MessageState `protogen:"open.v1"`
Base *BaseMessage `protobuf:"bytes,1,opt,name=base,proto3" json:"base,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
Unit string `protobuf:"bytes,3,opt,name=unit,proto3" json:"unit,omitempty"`
Time float64 `protobuf:"fixed64,4,opt,name=time,proto3" json:"time,omitempty"`
UpdateTime float64 `protobuf:"fixed64,5,opt,name=update_time,json=updateTime,proto3" json:"update_time,omitempty"`
Value *float64 `protobuf:"fixed64,6,opt,name=value,proto3,oneof" json:"value,omitempty"`
StringValue *string `protobuf:"bytes,7,opt,name=string_value,json=stringValue,proto3,oneof" json:"string_value,omitempty"`
DataValue *string `protobuf:"bytes,8,opt,name=data_value,json=dataValue,proto3,oneof" json:"data_value,omitempty"`
BoolValue *bool `protobuf:"varint,9,opt,name=bool_value,json=boolValue,proto3,oneof" json:"bool_value,omitempty"`
Sum *float64 `protobuf:"fixed64,10,opt,name=sum,proto3,oneof" json:"sum,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SenMLMessage) Reset() {
*x = SenMLMessage{}
mi := &file_readers_v1_readers_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SenMLMessage) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SenMLMessage) ProtoMessage() {}
func (x *SenMLMessage) ProtoReflect() protoreflect.Message {
mi := &file_readers_v1_readers_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SenMLMessage.ProtoReflect.Descriptor instead.
func (*SenMLMessage) Descriptor() ([]byte, []int) {
return file_readers_v1_readers_proto_rawDescGZIP(), []int{4}
}
func (x *SenMLMessage) GetBase() *BaseMessage {
if x != nil {
return x.Base
}
return nil
}
func (x *SenMLMessage) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *SenMLMessage) GetUnit() string {
if x != nil {
return x.Unit
}
return ""
}
func (x *SenMLMessage) GetTime() float64 {
if x != nil {
return x.Time
}
return 0
}
func (x *SenMLMessage) GetUpdateTime() float64 {
if x != nil {
return x.UpdateTime
}
return 0
}
func (x *SenMLMessage) GetValue() float64 {
if x != nil && x.Value != nil {
return *x.Value
}
return 0
}
func (x *SenMLMessage) GetStringValue() string {
if x != nil && x.StringValue != nil {
return *x.StringValue
}
return ""
}
func (x *SenMLMessage) GetDataValue() string {
if x != nil && x.DataValue != nil {
return *x.DataValue
}
return ""
}
func (x *SenMLMessage) GetBoolValue() bool {
if x != nil && x.BoolValue != nil {
return *x.BoolValue
}
return false
}
func (x *SenMLMessage) GetSum() float64 {
if x != nil && x.Sum != nil {
return *x.Sum
}
return 0
}
type JsonMessage struct {
state protoimpl.MessageState `protogen:"open.v1"`
Base *BaseMessage `protobuf:"bytes,1,opt,name=base,proto3" json:"base,omitempty"`
Created int64 `protobuf:"varint,2,opt,name=created,proto3" json:"created,omitempty"`
Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *JsonMessage) Reset() {
*x = JsonMessage{}
mi := &file_readers_v1_readers_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *JsonMessage) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*JsonMessage) ProtoMessage() {}
func (x *JsonMessage) ProtoReflect() protoreflect.Message {
mi := &file_readers_v1_readers_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use JsonMessage.ProtoReflect.Descriptor instead.
func (*JsonMessage) Descriptor() ([]byte, []int) {
return file_readers_v1_readers_proto_rawDescGZIP(), []int{5}
}
func (x *JsonMessage) GetBase() *BaseMessage {
if x != nil {
return x.Base
}
return nil
}
func (x *JsonMessage) GetCreated() int64 {
if x != nil {
return x.Created
}
return 0
}
func (x *JsonMessage) GetPayload() []byte {
if x != nil {
return x.Payload
}
return nil
}
type ReadMessagesReq struct {
state protoimpl.MessageState `protogen:"open.v1"`
ChannelId string `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
DomainId string `protobuf:"bytes,2,opt,name=domain_id,json=domainId,proto3" json:"domain_id,omitempty"`
PageMetadata *PageMetadata `protobuf:"bytes,3,opt,name=page_metadata,json=pageMetadata,proto3" json:"page_metadata,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ReadMessagesReq) Reset() {
*x = ReadMessagesReq{}
mi := &file_readers_v1_readers_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ReadMessagesReq) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReadMessagesReq) ProtoMessage() {}
func (x *ReadMessagesReq) ProtoReflect() protoreflect.Message {
mi := &file_readers_v1_readers_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReadMessagesReq.ProtoReflect.Descriptor instead.
func (*ReadMessagesReq) Descriptor() ([]byte, []int) {
return file_readers_v1_readers_proto_rawDescGZIP(), []int{6}
}
func (x *ReadMessagesReq) GetChannelId() string {
if x != nil {
return x.ChannelId
}
return ""
}
func (x *ReadMessagesReq) GetDomainId() string {
if x != nil {
return x.DomainId
}
return ""
}
func (x *ReadMessagesReq) GetPageMetadata() *PageMetadata {
if x != nil {
return x.PageMetadata
}
return nil
}
var File_readers_v1_readers_proto protoreflect.FileDescriptor
const file_readers_v1_readers_proto_rawDesc = "" +
"\n" +
"\x18readers/v1/readers.proto\x12\n" +
"readers.v1\"\xac\x04\n" +
"\fPageMetadata\x12\x14\n" +
"\x05limit\x18\x01 \x01(\x04R\x05limit\x12\x16\n" +
"\x06offset\x18\x02 \x01(\x04R\x06offset\x12\x1a\n" +
"\bprotocol\x18\x03 \x01(\tR\bprotocol\x12\x12\n" +
"\x04name\x18\x04 \x01(\tR\x04name\x12\x14\n" +
"\x05value\x18\x05 \x01(\x01R\x05value\x12\x1c\n" +
"\tpublisher\x18\x06 \x01(\tR\tpublisher\x12\x1d\n" +
"\n" +
"bool_value\x18\a \x01(\bR\tboolValue\x12!\n" +
"\fstring_value\x18\b \x01(\tR\vstringValue\x12\x1d\n" +
"\n" +
"data_value\x18\t \x01(\tR\tdataValue\x12\x12\n" +
"\x04from\x18\n" +
" \x01(\x01R\x04from\x12\x0e\n" +
"\x02to\x18\v \x01(\x01R\x02to\x12\x1a\n" +
"\bsubtopic\x18\f \x01(\tR\bsubtopic\x12\x1a\n" +
"\binterval\x18\r \x01(\tR\binterval\x12\x12\n" +
"\x04read\x18\x0e \x01(\bR\x04read\x129\n" +
"\vaggregation\x18\x0f \x01(\x0e2\x17.readers.v1.AggregationR\vaggregation\x12\x1e\n" +
"\n" +
"comparator\x18\x10 \x01(\tR\n" +
"comparator\x12\x16\n" +
"\x06format\x18\x11 \x01(\tR\x06format\x12\x14\n" +
"\x05order\x18\x12 \x01(\tR\x05order\x12\x10\n" +
"\x03dir\x18\x13 \x01(\tR\x03dir\x12\x1e\n" +
"\n" +
"publishers\x18\x14 \x03(\tR\n" +
"publishers\"\x97\x01\n" +
"\x0fReadMessagesRes\x12\x14\n" +
"\x05total\x18\x01 \x01(\x04R\x05total\x12=\n" +
"\rpage_metadata\x18\x02 \x01(\v2\x18.readers.v1.PageMetadataR\fpageMetadata\x12/\n" +
"\bmessages\x18\x03 \x03(\v2\x13.readers.v1.MessageR\bmessages\"u\n" +
"\aMessage\x120\n" +
"\x05senml\x18\x01 \x01(\v2\x18.readers.v1.SenMLMessageH\x00R\x05senml\x12-\n" +
"\x04json\x18\x02 \x01(\v2\x17.readers.v1.JsonMessageH\x00R\x04jsonB\t\n" +
"\apayload\"}\n" +
"\vBaseMessage\x12\x18\n" +
"\achannel\x18\x01 \x01(\tR\achannel\x12\x1a\n" +
"\bsubtopic\x18\x02 \x01(\tR\bsubtopic\x12\x1c\n" +
"\tpublisher\x18\x03 \x01(\tR\tpublisher\x12\x1a\n" +
"\bprotocol\x18\x04 \x01(\tR\bprotocol\"\xfb\x02\n" +
"\fSenMLMessage\x12+\n" +
"\x04base\x18\x01 \x01(\v2\x17.readers.v1.BaseMessageR\x04base\x12\x12\n" +
"\x04name\x18\x02 \x01(\tR\x04name\x12\x12\n" +
"\x04unit\x18\x03 \x01(\tR\x04unit\x12\x12\n" +
"\x04time\x18\x04 \x01(\x01R\x04time\x12\x1f\n" +
"\vupdate_time\x18\x05 \x01(\x01R\n" +
"updateTime\x12\x19\n" +
"\x05value\x18\x06 \x01(\x01H\x00R\x05value\x88\x01\x01\x12&\n" +
"\fstring_value\x18\a \x01(\tH\x01R\vstringValue\x88\x01\x01\x12\"\n" +
"\n" +
"data_value\x18\b \x01(\tH\x02R\tdataValue\x88\x01\x01\x12\"\n" +
"\n" +
"bool_value\x18\t \x01(\bH\x03R\tboolValue\x88\x01\x01\x12\x15\n" +
"\x03sum\x18\n" +
" \x01(\x01H\x04R\x03sum\x88\x01\x01B\b\n" +
"\x06_valueB\x0f\n" +
"\r_string_valueB\r\n" +
"\v_data_valueB\r\n" +
"\v_bool_valueB\x06\n" +
"\x04_sum\"n\n" +
"\vJsonMessage\x12+\n" +
"\x04base\x18\x01 \x01(\v2\x17.readers.v1.BaseMessageR\x04base\x12\x18\n" +
"\acreated\x18\x02 \x01(\x03R\acreated\x12\x18\n" +
"\apayload\x18\x03 \x01(\fR\apayload\"\x8c\x01\n" +
"\x0fReadMessagesReq\x12\x1d\n" +
"\n" +
"channel_id\x18\x01 \x01(\tR\tchannelId\x12\x1b\n" +
"\tdomain_id\x18\x02 \x01(\tR\bdomainId\x12=\n" +
"\rpage_metadata\x18\x03 \x01(\v2\x18.readers.v1.PageMetadataR\fpageMetadata*\x95\x01\n" +
"\vAggregation\x12\x1b\n" +
"\x17AGGREGATION_UNSPECIFIED\x10\x00\x12\x13\n" +
"\x0fAGGREGATION_MAX\x10\x01\x12\x13\n" +
"\x0fAGGREGATION_MIN\x10\x02\x12\x13\n" +
"\x0fAGGREGATION_SUM\x10\x03\x12\x15\n" +
"\x11AGGREGATION_COUNT\x10\x04\x12\x13\n" +
"\x0fAGGREGATION_AVG\x10\x052\\\n" +
"\x0eReadersService\x12J\n" +
"\fReadMessages\x12\x1b.readers.v1.ReadMessagesReq\x1a\x1b.readers.v1.ReadMessagesRes\"\x00B3Z1github.com/absmach/magistrala/api/grpc/readers/v1b\x06proto3"
var (
file_readers_v1_readers_proto_rawDescOnce sync.Once
file_readers_v1_readers_proto_rawDescData []byte
)
func file_readers_v1_readers_proto_rawDescGZIP() []byte {
file_readers_v1_readers_proto_rawDescOnce.Do(func() {
file_readers_v1_readers_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_readers_v1_readers_proto_rawDesc), len(file_readers_v1_readers_proto_rawDesc)))
})
return file_readers_v1_readers_proto_rawDescData
}
var file_readers_v1_readers_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_readers_v1_readers_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_readers_v1_readers_proto_goTypes = []any{
(Aggregation)(0), // 0: readers.v1.Aggregation
(*PageMetadata)(nil), // 1: readers.v1.PageMetadata
(*ReadMessagesRes)(nil), // 2: readers.v1.ReadMessagesRes
(*Message)(nil), // 3: readers.v1.Message
(*BaseMessage)(nil), // 4: readers.v1.BaseMessage
(*SenMLMessage)(nil), // 5: readers.v1.SenMLMessage
(*JsonMessage)(nil), // 6: readers.v1.JsonMessage
(*ReadMessagesReq)(nil), // 7: readers.v1.ReadMessagesReq
}
var file_readers_v1_readers_proto_depIdxs = []int32{
0, // 0: readers.v1.PageMetadata.aggregation:type_name -> readers.v1.Aggregation
1, // 1: readers.v1.ReadMessagesRes.page_metadata:type_name -> readers.v1.PageMetadata
3, // 2: readers.v1.ReadMessagesRes.messages:type_name -> readers.v1.Message
5, // 3: readers.v1.Message.senml:type_name -> readers.v1.SenMLMessage
6, // 4: readers.v1.Message.json:type_name -> readers.v1.JsonMessage
4, // 5: readers.v1.SenMLMessage.base:type_name -> readers.v1.BaseMessage
4, // 6: readers.v1.JsonMessage.base:type_name -> readers.v1.BaseMessage
1, // 7: readers.v1.ReadMessagesReq.page_metadata:type_name -> readers.v1.PageMetadata
7, // 8: readers.v1.ReadersService.ReadMessages:input_type -> readers.v1.ReadMessagesReq
2, // 9: readers.v1.ReadersService.ReadMessages:output_type -> readers.v1.ReadMessagesRes
9, // [9:10] is the sub-list for method output_type
8, // [8:9] is the sub-list for method input_type
8, // [8:8] is the sub-list for extension type_name
8, // [8:8] is the sub-list for extension extendee
0, // [0:8] is the sub-list for field type_name
}
func init() { file_readers_v1_readers_proto_init() }
func file_readers_v1_readers_proto_init() {
if File_readers_v1_readers_proto != nil {
return
}
file_readers_v1_readers_proto_msgTypes[2].OneofWrappers = []any{
(*Message_Senml)(nil),
(*Message_Json)(nil),
}
file_readers_v1_readers_proto_msgTypes[4].OneofWrappers = []any{}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_readers_v1_readers_proto_rawDesc), len(file_readers_v1_readers_proto_rawDesc)),
NumEnums: 1,
NumMessages: 7,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_readers_v1_readers_proto_goTypes,
DependencyIndexes: file_readers_v1_readers_proto_depIdxs,
EnumInfos: file_readers_v1_readers_proto_enumTypes,
MessageInfos: file_readers_v1_readers_proto_msgTypes,
}.Build()
File_readers_v1_readers_proto = out.File
file_readers_v1_readers_proto_goTypes = nil
file_readers_v1_readers_proto_depIdxs = nil
}
+130
View File
@@ -0,0 +1,130 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.6.2
// - protoc v7.35.1
// source: readers/v1/readers.proto
package v1
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
ReadersService_ReadMessages_FullMethodName = "/readers.v1.ReadersService/ReadMessages"
)
// ReadersServiceClient is the client API for ReadersService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// ReadersService is a service that provides access to
// readers functionalities for Magistrala services.
type ReadersServiceClient interface {
ReadMessages(ctx context.Context, in *ReadMessagesReq, opts ...grpc.CallOption) (*ReadMessagesRes, error)
}
type readersServiceClient struct {
cc grpc.ClientConnInterface
}
func NewReadersServiceClient(cc grpc.ClientConnInterface) ReadersServiceClient {
return &readersServiceClient{cc}
}
func (c *readersServiceClient) ReadMessages(ctx context.Context, in *ReadMessagesReq, opts ...grpc.CallOption) (*ReadMessagesRes, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ReadMessagesRes)
err := c.cc.Invoke(ctx, ReadersService_ReadMessages_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// ReadersServiceServer is the server API for ReadersService service.
// All implementations must embed UnimplementedReadersServiceServer
// for forward compatibility.
//
// ReadersService is a service that provides access to
// readers functionalities for Magistrala services.
type ReadersServiceServer interface {
ReadMessages(context.Context, *ReadMessagesReq) (*ReadMessagesRes, error)
mustEmbedUnimplementedReadersServiceServer()
}
// UnimplementedReadersServiceServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedReadersServiceServer struct{}
func (UnimplementedReadersServiceServer) ReadMessages(context.Context, *ReadMessagesReq) (*ReadMessagesRes, error) {
return nil, status.Error(codes.Unimplemented, "method ReadMessages not implemented")
}
func (UnimplementedReadersServiceServer) mustEmbedUnimplementedReadersServiceServer() {}
func (UnimplementedReadersServiceServer) testEmbeddedByValue() {}
// UnsafeReadersServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to ReadersServiceServer will
// result in compilation errors.
type UnsafeReadersServiceServer interface {
mustEmbedUnimplementedReadersServiceServer()
}
func RegisterReadersServiceServer(s grpc.ServiceRegistrar, srv ReadersServiceServer) {
// If the following call panics, it indicates UnimplementedReadersServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&ReadersService_ServiceDesc, srv)
}
func _ReadersService_ReadMessages_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ReadMessagesReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ReadersServiceServer).ReadMessages(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ReadersService_ReadMessages_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ReadersServiceServer).ReadMessages(ctx, req.(*ReadMessagesReq))
}
return interceptor(ctx, in, info, handler)
}
// ReadersService_ServiceDesc is the grpc.ServiceDesc for ReadersService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var ReadersService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "readers.v1.ReadersService",
HandlerType: (*ReadersServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "ReadMessages",
Handler: _ReadersService_ReadMessages_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "readers/v1/readers.proto",
}
+285 -25
View File
@@ -3,8 +3,8 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v6.33.0
// protoc-gen-go v1.36.11
// protoc v7.35.1
// source: token/v1/token.proto
package v1
@@ -30,6 +30,7 @@ type IssueReq struct {
UserRole uint32 `protobuf:"varint,2,opt,name=user_role,json=userRole,proto3" json:"user_role,omitempty"`
Type uint32 `protobuf:"varint,3,opt,name=type,proto3" json:"type,omitempty"`
Verified bool `protobuf:"varint,4,opt,name=verified,proto3" json:"verified,omitempty"`
Description string `protobuf:"bytes,5,opt,name=description,proto3" json:"description,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@@ -92,6 +93,13 @@ func (x *IssueReq) GetVerified() bool {
return false
}
func (x *IssueReq) GetDescription() string {
if x != nil {
return x.Description
}
return ""
}
type RefreshReq struct {
state protoimpl.MessageState `protogen:"open.v1"`
RefreshToken string `protobuf:"bytes,1,opt,name=refresh_token,json=refreshToken,proto3" json:"refresh_token,omitempty"`
@@ -144,6 +152,58 @@ func (x *RefreshReq) GetVerified() bool {
return false
}
type RevokeReq struct {
state protoimpl.MessageState `protogen:"open.v1"`
TokenId string `protobuf:"bytes,1,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"`
UserId string `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RevokeReq) Reset() {
*x = RevokeReq{}
mi := &file_token_v1_token_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RevokeReq) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RevokeReq) ProtoMessage() {}
func (x *RevokeReq) ProtoReflect() protoreflect.Message {
mi := &file_token_v1_token_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RevokeReq.ProtoReflect.Descriptor instead.
func (*RevokeReq) Descriptor() ([]byte, []int) {
return file_token_v1_token_proto_rawDescGZIP(), []int{2}
}
func (x *RevokeReq) GetTokenId() string {
if x != nil {
return x.TokenId
}
return ""
}
func (x *RevokeReq) GetUserId() string {
if x != nil {
return x.UserId
}
return ""
}
// If a token is not carrying any information itself, the type
// field can be used to determine how to validate the token.
// Also, different tokens can be encoded in different ways.
@@ -158,7 +218,7 @@ type Token struct {
func (x *Token) Reset() {
*x = Token{}
mi := &file_token_v1_token_proto_msgTypes[2]
mi := &file_token_v1_token_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -170,7 +230,7 @@ func (x *Token) String() string {
func (*Token) ProtoMessage() {}
func (x *Token) ProtoReflect() protoreflect.Message {
mi := &file_token_v1_token_proto_msgTypes[2]
mi := &file_token_v1_token_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -183,7 +243,7 @@ func (x *Token) ProtoReflect() protoreflect.Message {
// Deprecated: Use Token.ProtoReflect.Descriptor instead.
func (*Token) Descriptor() ([]byte, []int) {
return file_token_v1_token_proto_rawDescGZIP(), []int{2}
return file_token_v1_token_proto_rawDescGZIP(), []int{3}
}
func (x *Token) GetAccessToken() string {
@@ -207,29 +267,219 @@ func (x *Token) GetAccessType() string {
return ""
}
type RevokeRes struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RevokeRes) Reset() {
*x = RevokeRes{}
mi := &file_token_v1_token_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RevokeRes) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RevokeRes) ProtoMessage() {}
func (x *RevokeRes) ProtoReflect() protoreflect.Message {
mi := &file_token_v1_token_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RevokeRes.ProtoReflect.Descriptor instead.
func (*RevokeRes) Descriptor() ([]byte, []int) {
return file_token_v1_token_proto_rawDescGZIP(), []int{4}
}
type ListUserRefreshTokensReq struct {
state protoimpl.MessageState `protogen:"open.v1"`
UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ListUserRefreshTokensReq) Reset() {
*x = ListUserRefreshTokensReq{}
mi := &file_token_v1_token_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ListUserRefreshTokensReq) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListUserRefreshTokensReq) ProtoMessage() {}
func (x *ListUserRefreshTokensReq) ProtoReflect() protoreflect.Message {
mi := &file_token_v1_token_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ListUserRefreshTokensReq.ProtoReflect.Descriptor instead.
func (*ListUserRefreshTokensReq) Descriptor() ([]byte, []int) {
return file_token_v1_token_proto_rawDescGZIP(), []int{5}
}
func (x *ListUserRefreshTokensReq) GetUserId() string {
if x != nil {
return x.UserId
}
return ""
}
type ListUserRefreshTokensRes struct {
state protoimpl.MessageState `protogen:"open.v1"`
RefreshTokens []*RefreshToken `protobuf:"bytes,1,rep,name=refresh_tokens,json=refreshTokens,proto3" json:"refresh_tokens,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ListUserRefreshTokensRes) Reset() {
*x = ListUserRefreshTokensRes{}
mi := &file_token_v1_token_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ListUserRefreshTokensRes) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListUserRefreshTokensRes) ProtoMessage() {}
func (x *ListUserRefreshTokensRes) ProtoReflect() protoreflect.Message {
mi := &file_token_v1_token_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ListUserRefreshTokensRes.ProtoReflect.Descriptor instead.
func (*ListUserRefreshTokensRes) Descriptor() ([]byte, []int) {
return file_token_v1_token_proto_rawDescGZIP(), []int{6}
}
func (x *ListUserRefreshTokensRes) GetRefreshTokens() []*RefreshToken {
if x != nil {
return x.RefreshTokens
}
return nil
}
type RefreshToken struct {
state protoimpl.MessageState `protogen:"open.v1"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RefreshToken) Reset() {
*x = RefreshToken{}
mi := &file_token_v1_token_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RefreshToken) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RefreshToken) ProtoMessage() {}
func (x *RefreshToken) ProtoReflect() protoreflect.Message {
mi := &file_token_v1_token_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RefreshToken.ProtoReflect.Descriptor instead.
func (*RefreshToken) Descriptor() ([]byte, []int) {
return file_token_v1_token_proto_rawDescGZIP(), []int{7}
}
func (x *RefreshToken) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (x *RefreshToken) GetDescription() string {
if x != nil {
return x.Description
}
return ""
}
var File_token_v1_token_proto protoreflect.FileDescriptor
const file_token_v1_token_proto_rawDesc = "" +
"\n" +
"\x14token/v1/token.proto\x12\btoken.v1\"p\n" +
"\x14token/v1/token.proto\x12\btoken.v1\"\x92\x01\n" +
"\bIssueReq\x12\x17\n" +
"\auser_id\x18\x01 \x01(\tR\x06userId\x12\x1b\n" +
"\tuser_role\x18\x02 \x01(\rR\buserRole\x12\x12\n" +
"\x04type\x18\x03 \x01(\rR\x04type\x12\x1a\n" +
"\bverified\x18\x04 \x01(\bR\bverified\"M\n" +
"\bverified\x18\x04 \x01(\bR\bverified\x12 \n" +
"\vdescription\x18\x05 \x01(\tR\vdescription\"M\n" +
"\n" +
"RefreshReq\x12#\n" +
"\rrefresh_token\x18\x01 \x01(\tR\frefreshToken\x12\x1a\n" +
"\bverified\x18\x02 \x01(\bR\bverified\"\x87\x01\n" +
"\bverified\x18\x02 \x01(\bR\bverified\"?\n" +
"\tRevokeReq\x12\x19\n" +
"\btoken_id\x18\x01 \x01(\tR\atokenId\x12\x17\n" +
"\auser_id\x18\x02 \x01(\tR\x06userId\"\x87\x01\n" +
"\x05Token\x12!\n" +
"\faccess_token\x18\x01 \x01(\tR\vaccessToken\x12(\n" +
"\rrefresh_token\x18\x02 \x01(\tH\x00R\frefreshToken\x88\x01\x01\x12\x1f\n" +
"\vaccess_type\x18\x03 \x01(\tR\n" +
"accessTypeB\x10\n" +
"\x0e_refresh_token2r\n" +
"\x0e_refresh_token\"\v\n" +
"\tRevokeRes\"3\n" +
"\x18ListUserRefreshTokensReq\x12\x17\n" +
"\auser_id\x18\x01 \x01(\tR\x06userId\"Y\n" +
"\x18ListUserRefreshTokensRes\x12=\n" +
"\x0erefresh_tokens\x18\x01 \x03(\v2\x16.token.v1.RefreshTokenR\rrefreshTokens\"@\n" +
"\fRefreshToken\x12\x0e\n" +
"\x02id\x18\x01 \x01(\tR\x02id\x12 \n" +
"\vdescription\x18\x02 \x01(\tR\vdescription2\x8b\x02\n" +
"\fTokenService\x12.\n" +
"\x05Issue\x12\x12.token.v1.IssueReq\x1a\x0f.token.v1.Token\"\x00\x122\n" +
"\aRefresh\x12\x14.token.v1.RefreshReq\x1a\x0f.token.v1.Token\"\x00B.Z,github.com/absmach/supermq/api/grpc/token/v1b\x06proto3"
"\aRefresh\x12\x14.token.v1.RefreshReq\x1a\x0f.token.v1.Token\"\x00\x124\n" +
"\x06Revoke\x12\x13.token.v1.RevokeReq\x1a\x13.token.v1.RevokeRes\"\x00\x12a\n" +
"\x15ListUserRefreshTokens\x12\".token.v1.ListUserRefreshTokensReq\x1a\".token.v1.ListUserRefreshTokensRes\"\x00B1Z/github.com/absmach/magistrala/api/grpc/token/v1b\x06proto3"
var (
file_token_v1_token_proto_rawDescOnce sync.Once
@@ -243,22 +493,32 @@ func file_token_v1_token_proto_rawDescGZIP() []byte {
return file_token_v1_token_proto_rawDescData
}
var file_token_v1_token_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_token_v1_token_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
var file_token_v1_token_proto_goTypes = []any{
(*IssueReq)(nil), // 0: token.v1.IssueReq
(*RefreshReq)(nil), // 1: token.v1.RefreshReq
(*Token)(nil), // 2: token.v1.Token
(*IssueReq)(nil), // 0: token.v1.IssueReq
(*RefreshReq)(nil), // 1: token.v1.RefreshReq
(*RevokeReq)(nil), // 2: token.v1.RevokeReq
(*Token)(nil), // 3: token.v1.Token
(*RevokeRes)(nil), // 4: token.v1.RevokeRes
(*ListUserRefreshTokensReq)(nil), // 5: token.v1.ListUserRefreshTokensReq
(*ListUserRefreshTokensRes)(nil), // 6: token.v1.ListUserRefreshTokensRes
(*RefreshToken)(nil), // 7: token.v1.RefreshToken
}
var file_token_v1_token_proto_depIdxs = []int32{
0, // 0: token.v1.TokenService.Issue:input_type -> token.v1.IssueReq
1, // 1: token.v1.TokenService.Refresh:input_type -> token.v1.RefreshReq
2, // 2: token.v1.TokenService.Issue:output_type -> token.v1.Token
2, // 3: token.v1.TokenService.Refresh:output_type -> token.v1.Token
2, // [2:4] is the sub-list for method output_type
0, // [0:2] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
7, // 0: token.v1.ListUserRefreshTokensRes.refresh_tokens:type_name -> token.v1.RefreshToken
0, // 1: token.v1.TokenService.Issue:input_type -> token.v1.IssueReq
1, // 2: token.v1.TokenService.Refresh:input_type -> token.v1.RefreshReq
2, // 3: token.v1.TokenService.Revoke:input_type -> token.v1.RevokeReq
5, // 4: token.v1.TokenService.ListUserRefreshTokens:input_type -> token.v1.ListUserRefreshTokensReq
3, // 5: token.v1.TokenService.Issue:output_type -> token.v1.Token
3, // 6: token.v1.TokenService.Refresh:output_type -> token.v1.Token
4, // 7: token.v1.TokenService.Revoke:output_type -> token.v1.RevokeRes
6, // 8: token.v1.TokenService.ListUserRefreshTokens:output_type -> token.v1.ListUserRefreshTokensRes
5, // [5:9] is the sub-list for method output_type
1, // [1:5] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_token_v1_token_proto_init() }
@@ -266,14 +526,14 @@ func file_token_v1_token_proto_init() {
if File_token_v1_token_proto != nil {
return
}
file_token_v1_token_proto_msgTypes[2].OneofWrappers = []any{}
file_token_v1_token_proto_msgTypes[3].OneofWrappers = []any{}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_token_v1_token_proto_rawDesc), len(file_token_v1_token_proto_rawDesc)),
NumEnums: 0,
NumMessages: 3,
NumMessages: 8,
NumExtensions: 0,
NumServices: 1,
},
+83 -7
View File
@@ -3,8 +3,8 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc v6.33.0
// - protoc-gen-go-grpc v1.6.2
// - protoc v7.35.1
// source: token/v1/token.proto
package v1
@@ -22,8 +22,10 @@ import (
const _ = grpc.SupportPackageIsVersion9
const (
TokenService_Issue_FullMethodName = "/token.v1.TokenService/Issue"
TokenService_Refresh_FullMethodName = "/token.v1.TokenService/Refresh"
TokenService_Issue_FullMethodName = "/token.v1.TokenService/Issue"
TokenService_Refresh_FullMethodName = "/token.v1.TokenService/Refresh"
TokenService_Revoke_FullMethodName = "/token.v1.TokenService/Revoke"
TokenService_ListUserRefreshTokens_FullMethodName = "/token.v1.TokenService/ListUserRefreshTokens"
)
// TokenServiceClient is the client API for TokenService service.
@@ -32,6 +34,8 @@ const (
type TokenServiceClient interface {
Issue(ctx context.Context, in *IssueReq, opts ...grpc.CallOption) (*Token, error)
Refresh(ctx context.Context, in *RefreshReq, opts ...grpc.CallOption) (*Token, error)
Revoke(ctx context.Context, in *RevokeReq, opts ...grpc.CallOption) (*RevokeRes, error)
ListUserRefreshTokens(ctx context.Context, in *ListUserRefreshTokensReq, opts ...grpc.CallOption) (*ListUserRefreshTokensRes, error)
}
type tokenServiceClient struct {
@@ -62,12 +66,34 @@ func (c *tokenServiceClient) Refresh(ctx context.Context, in *RefreshReq, opts .
return out, nil
}
func (c *tokenServiceClient) Revoke(ctx context.Context, in *RevokeReq, opts ...grpc.CallOption) (*RevokeRes, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(RevokeRes)
err := c.cc.Invoke(ctx, TokenService_Revoke_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *tokenServiceClient) ListUserRefreshTokens(ctx context.Context, in *ListUserRefreshTokensReq, opts ...grpc.CallOption) (*ListUserRefreshTokensRes, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ListUserRefreshTokensRes)
err := c.cc.Invoke(ctx, TokenService_ListUserRefreshTokens_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// TokenServiceServer is the server API for TokenService service.
// All implementations must embed UnimplementedTokenServiceServer
// for forward compatibility.
type TokenServiceServer interface {
Issue(context.Context, *IssueReq) (*Token, error)
Refresh(context.Context, *RefreshReq) (*Token, error)
Revoke(context.Context, *RevokeReq) (*RevokeRes, error)
ListUserRefreshTokens(context.Context, *ListUserRefreshTokensReq) (*ListUserRefreshTokensRes, error)
mustEmbedUnimplementedTokenServiceServer()
}
@@ -79,10 +105,16 @@ type TokenServiceServer interface {
type UnimplementedTokenServiceServer struct{}
func (UnimplementedTokenServiceServer) Issue(context.Context, *IssueReq) (*Token, error) {
return nil, status.Errorf(codes.Unimplemented, "method Issue not implemented")
return nil, status.Error(codes.Unimplemented, "method Issue not implemented")
}
func (UnimplementedTokenServiceServer) Refresh(context.Context, *RefreshReq) (*Token, error) {
return nil, status.Errorf(codes.Unimplemented, "method Refresh not implemented")
return nil, status.Error(codes.Unimplemented, "method Refresh not implemented")
}
func (UnimplementedTokenServiceServer) Revoke(context.Context, *RevokeReq) (*RevokeRes, error) {
return nil, status.Error(codes.Unimplemented, "method Revoke not implemented")
}
func (UnimplementedTokenServiceServer) ListUserRefreshTokens(context.Context, *ListUserRefreshTokensReq) (*ListUserRefreshTokensRes, error) {
return nil, status.Error(codes.Unimplemented, "method ListUserRefreshTokens not implemented")
}
func (UnimplementedTokenServiceServer) mustEmbedUnimplementedTokenServiceServer() {}
func (UnimplementedTokenServiceServer) testEmbeddedByValue() {}
@@ -95,7 +127,7 @@ type UnsafeTokenServiceServer interface {
}
func RegisterTokenServiceServer(s grpc.ServiceRegistrar, srv TokenServiceServer) {
// If the following call pancis, it indicates UnimplementedTokenServiceServer was
// If the following call panics, it indicates UnimplementedTokenServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
@@ -141,6 +173,42 @@ func _TokenService_Refresh_Handler(srv interface{}, ctx context.Context, dec fun
return interceptor(ctx, in, info, handler)
}
func _TokenService_Revoke_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RevokeReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TokenServiceServer).Revoke(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: TokenService_Revoke_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TokenServiceServer).Revoke(ctx, req.(*RevokeReq))
}
return interceptor(ctx, in, info, handler)
}
func _TokenService_ListUserRefreshTokens_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListUserRefreshTokensReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TokenServiceServer).ListUserRefreshTokens(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: TokenService_ListUserRefreshTokens_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TokenServiceServer).ListUserRefreshTokens(ctx, req.(*ListUserRefreshTokensReq))
}
return interceptor(ctx, in, info, handler)
}
// TokenService_ServiceDesc is the grpc.ServiceDesc for TokenService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
@@ -156,6 +224,14 @@ var TokenService_ServiceDesc = grpc.ServiceDesc{
MethodName: "Refresh",
Handler: _TokenService_Refresh_Handler,
},
{
MethodName: "Revoke",
Handler: _TokenService_Revoke_Handler,
},
{
MethodName: "ListUserRefreshTokens",
Handler: _TokenService_ListUserRefreshTokens_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "token/v1/token.proto",
+56 -46
View File
@@ -3,8 +3,8 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc v6.33.0
// protoc-gen-go v1.36.11
// protoc v7.35.1
// source: users/v1/users.proto
package v1
@@ -155,25 +155,26 @@ func (x *RetrieveUsersRes) GetUsers() []*User {
}
type User struct {
state protoimpl.MessageState `protogen:"open.v1"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
FirstName string `protobuf:"bytes,2,opt,name=first_name,json=firstName,proto3" json:"first_name,omitempty"`
LastName string `protobuf:"bytes,3,opt,name=last_name,json=lastName,proto3" json:"last_name,omitempty"`
Tags []string `protobuf:"bytes,4,rep,name=tags,proto3" json:"tags,omitempty"`
Metadata *structpb.Struct `protobuf:"bytes,5,opt,name=metadata,proto3" json:"metadata,omitempty"`
Status uint32 `protobuf:"varint,6,opt,name=status,proto3" json:"status,omitempty"`
Role uint32 `protobuf:"varint,7,opt,name=role,proto3" json:"role,omitempty"`
ProfilePicture string `protobuf:"bytes,8,opt,name=profile_picture,json=profilePicture,proto3" json:"profile_picture,omitempty"`
Username string `protobuf:"bytes,9,opt,name=username,proto3" json:"username,omitempty"`
Email string `protobuf:"bytes,10,opt,name=email,proto3" json:"email,omitempty"`
CreatedAt *timestamppb.Timestamp `protobuf:"bytes,11,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"`
UpdatedBy string `protobuf:"bytes,13,opt,name=updated_by,json=updatedBy,proto3" json:"updated_by,omitempty"`
VerifiedAt *timestamppb.Timestamp `protobuf:"bytes,14,opt,name=verified_at,json=verifiedAt,proto3" json:"verified_at,omitempty"`
AuthProvider string `protobuf:"bytes,15,opt,name=auth_provider,json=authProvider,proto3" json:"auth_provider,omitempty"`
Permissions []string `protobuf:"bytes,16,rep,name=permissions,proto3" json:"permissions,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
FirstName string `protobuf:"bytes,2,opt,name=first_name,json=firstName,proto3" json:"first_name,omitempty"`
LastName string `protobuf:"bytes,3,opt,name=last_name,json=lastName,proto3" json:"last_name,omitempty"`
Tags []string `protobuf:"bytes,4,rep,name=tags,proto3" json:"tags,omitempty"`
Metadata *structpb.Struct `protobuf:"bytes,5,opt,name=metadata,proto3" json:"metadata,omitempty"`
PrivateMetadata *structpb.Struct `protobuf:"bytes,6,opt,name=private_metadata,json=privateMetadata,proto3" json:"private_metadata,omitempty"`
Status uint32 `protobuf:"varint,7,opt,name=status,proto3" json:"status,omitempty"`
Role uint32 `protobuf:"varint,8,opt,name=role,proto3" json:"role,omitempty"`
ProfilePicture string `protobuf:"bytes,9,opt,name=profile_picture,json=profilePicture,proto3" json:"profile_picture,omitempty"`
Username string `protobuf:"bytes,10,opt,name=username,proto3" json:"username,omitempty"`
Email string `protobuf:"bytes,11,opt,name=email,proto3" json:"email,omitempty"`
CreatedAt *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,13,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"`
UpdatedBy string `protobuf:"bytes,14,opt,name=updated_by,json=updatedBy,proto3" json:"updated_by,omitempty"`
VerifiedAt *timestamppb.Timestamp `protobuf:"bytes,15,opt,name=verified_at,json=verifiedAt,proto3" json:"verified_at,omitempty"`
AuthProvider string `protobuf:"bytes,16,opt,name=auth_provider,json=authProvider,proto3" json:"auth_provider,omitempty"`
Permissions []string `protobuf:"bytes,17,rep,name=permissions,proto3" json:"permissions,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *User) Reset() {
@@ -241,6 +242,13 @@ func (x *User) GetMetadata() *structpb.Struct {
return nil
}
func (x *User) GetPrivateMetadata() *structpb.Struct {
if x != nil {
return x.PrivateMetadata
}
return nil
}
func (x *User) GetStatus() uint32 {
if x != nil {
return x.Status
@@ -331,32 +339,33 @@ const file_users_v1_users_proto_rawDesc = "" +
"\x05total\x18\x01 \x01(\x04R\x05total\x12\x14\n" +
"\x05limit\x18\x02 \x01(\x04R\x05limit\x12\x16\n" +
"\x06offset\x18\x03 \x01(\x04R\x06offset\x12$\n" +
"\x05users\x18\x04 \x03(\v2\x0e.users.v1.UserR\x05users\"\xbb\x04\n" +
"\x05users\x18\x04 \x03(\v2\x0e.users.v1.UserR\x05users\"\xff\x04\n" +
"\x04User\x12\x0e\n" +
"\x02id\x18\x01 \x01(\tR\x02id\x12\x1d\n" +
"\n" +
"first_name\x18\x02 \x01(\tR\tfirstName\x12\x1b\n" +
"\tlast_name\x18\x03 \x01(\tR\blastName\x12\x12\n" +
"\x04tags\x18\x04 \x03(\tR\x04tags\x123\n" +
"\bmetadata\x18\x05 \x01(\v2\x17.google.protobuf.StructR\bmetadata\x12\x16\n" +
"\x06status\x18\x06 \x01(\rR\x06status\x12\x12\n" +
"\x04role\x18\a \x01(\rR\x04role\x12'\n" +
"\x0fprofile_picture\x18\b \x01(\tR\x0eprofilePicture\x12\x1a\n" +
"\busername\x18\t \x01(\tR\busername\x12\x14\n" +
"\x05email\x18\n" +
" \x01(\tR\x05email\x129\n" +
"\bmetadata\x18\x05 \x01(\v2\x17.google.protobuf.StructR\bmetadata\x12B\n" +
"\x10private_metadata\x18\x06 \x01(\v2\x17.google.protobuf.StructR\x0fprivateMetadata\x12\x16\n" +
"\x06status\x18\a \x01(\rR\x06status\x12\x12\n" +
"\x04role\x18\b \x01(\rR\x04role\x12'\n" +
"\x0fprofile_picture\x18\t \x01(\tR\x0eprofilePicture\x12\x1a\n" +
"\busername\x18\n" +
" \x01(\tR\busername\x12\x14\n" +
"\x05email\x18\v \x01(\tR\x05email\x129\n" +
"\n" +
"created_at\x18\v \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\x129\n" +
"created_at\x18\f \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\x129\n" +
"\n" +
"updated_at\x18\f \x01(\v2\x1a.google.protobuf.TimestampR\tupdatedAt\x12\x1d\n" +
"updated_at\x18\r \x01(\v2\x1a.google.protobuf.TimestampR\tupdatedAt\x12\x1d\n" +
"\n" +
"updated_by\x18\r \x01(\tR\tupdatedBy\x12;\n" +
"\vverified_at\x18\x0e \x01(\v2\x1a.google.protobuf.TimestampR\n" +
"updated_by\x18\x0e \x01(\tR\tupdatedBy\x12;\n" +
"\vverified_at\x18\x0f \x01(\v2\x1a.google.protobuf.TimestampR\n" +
"verifiedAt\x12#\n" +
"\rauth_provider\x18\x0f \x01(\tR\fauthProvider\x12 \n" +
"\vpermissions\x18\x10 \x03(\tR\vpermissions2Y\n" +
"\rauth_provider\x18\x10 \x01(\tR\fauthProvider\x12 \n" +
"\vpermissions\x18\x11 \x03(\tR\vpermissions2Y\n" +
"\fUsersService\x12I\n" +
"\rRetrieveUsers\x12\x1a.users.v1.RetrieveUsersReq\x1a\x1a.users.v1.RetrieveUsersRes\"\x00B.Z,github.com/absmach/supermq/api/grpc/users/v1b\x06proto3"
"\rRetrieveUsers\x12\x1a.users.v1.RetrieveUsersReq\x1a\x1a.users.v1.RetrieveUsersRes\"\x00B1Z/github.com/absmach/magistrala/api/grpc/users/v1b\x06proto3"
var (
file_users_v1_users_proto_rawDescOnce sync.Once
@@ -381,16 +390,17 @@ var file_users_v1_users_proto_goTypes = []any{
var file_users_v1_users_proto_depIdxs = []int32{
2, // 0: users.v1.RetrieveUsersRes.users:type_name -> users.v1.User
3, // 1: users.v1.User.metadata:type_name -> google.protobuf.Struct
4, // 2: users.v1.User.created_at:type_name -> google.protobuf.Timestamp
4, // 3: users.v1.User.updated_at:type_name -> google.protobuf.Timestamp
4, // 4: users.v1.User.verified_at:type_name -> google.protobuf.Timestamp
0, // 5: users.v1.UsersService.RetrieveUsers:input_type -> users.v1.RetrieveUsersReq
1, // 6: users.v1.UsersService.RetrieveUsers:output_type -> users.v1.RetrieveUsersRes
6, // [6:7] is the sub-list for method output_type
5, // [5:6] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
3, // 2: users.v1.User.private_metadata:type_name -> google.protobuf.Struct
4, // 3: users.v1.User.created_at:type_name -> google.protobuf.Timestamp
4, // 4: users.v1.User.updated_at:type_name -> google.protobuf.Timestamp
4, // 5: users.v1.User.verified_at:type_name -> google.protobuf.Timestamp
0, // 6: users.v1.UsersService.RetrieveUsers:input_type -> users.v1.RetrieveUsersReq
1, // 7: users.v1.UsersService.RetrieveUsers:output_type -> users.v1.RetrieveUsersRes
7, // [7:8] is the sub-list for method output_type
6, // [6:7] is the sub-list for method input_type
6, // [6:6] is the sub-list for extension type_name
6, // [6:6] is the sub-list for extension extendee
0, // [0:6] is the sub-list for field type_name
}
func init() { file_users_v1_users_proto_init() }
+4 -4
View File
@@ -3,8 +3,8 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc v6.33.0
// - protoc-gen-go-grpc v1.6.2
// - protoc v7.35.1
// source: users/v1/users.proto
package v1
@@ -72,7 +72,7 @@ type UsersServiceServer interface {
type UnimplementedUsersServiceServer struct{}
func (UnimplementedUsersServiceServer) RetrieveUsers(context.Context, *RetrieveUsersReq) (*RetrieveUsersRes, error) {
return nil, status.Errorf(codes.Unimplemented, "method RetrieveUsers not implemented")
return nil, status.Error(codes.Unimplemented, "method RetrieveUsers not implemented")
}
func (UnimplementedUsersServiceServer) mustEmbedUnimplementedUsersServiceServer() {}
func (UnimplementedUsersServiceServer) testEmbeddedByValue() {}
@@ -85,7 +85,7 @@ type UnsafeUsersServiceServer interface {
}
func RegisterUsersServiceServer(s grpc.ServiceRegistrar, srv UsersServiceServer) {
// If the following call pancis, it indicates UnimplementedUsersServiceServer was
// If the following call panics, it indicates UnimplementedUsersServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
+23 -10
View File
@@ -11,12 +11,9 @@ import (
"regexp"
"strings"
"github.com/absmach/supermq"
apiutil "github.com/absmach/supermq/api/http/util"
"github.com/absmach/supermq/clients"
"github.com/absmach/supermq/groups"
"github.com/absmach/supermq/pkg/errors"
"github.com/absmach/supermq/users"
"github.com/absmach/magistrala"
apiutil "github.com/absmach/magistrala/api/http/util"
"github.com/absmach/magistrala/pkg/errors"
"github.com/gofrs/uuid/v5"
)
@@ -37,6 +34,7 @@ const (
MetadataKey = "metadata"
NameKey = "name"
TagKey = "tag"
TagsKey = "tags"
StatusKey = "status"
ClientKey = "client"
@@ -79,9 +77,9 @@ const (
DefStartLevel = 1
DefEndLevel = 0
DefStatus = "enabled"
DefClientStatus = clients.Enabled
DefUserStatus = users.Enabled
DefGroupStatus = groups.Enabled
DefClientStatus = "enabled"
DefUserStatus = "enabled"
DefGroupStatus = "enabled"
// ContentType represents JSON content type.
ContentType = "application/json"
@@ -157,7 +155,7 @@ func ValidateUserName(name string) error {
// EncodeResponse encodes successful response.
func EncodeResponse(_ context.Context, w http.ResponseWriter, response any) error {
if ar, ok := response.(supermq.Response); ok {
if ar, ok := response.(magistrala.Response); ok {
for k, v := range ar.Headers() {
w.Header().Set(k, v)
}
@@ -183,6 +181,21 @@ func EncodeError(_ context.Context, err error, w http.ResponseWriter) {
return
}
if errors.Contains(err, errors.ErrAuthentication) {
w.WriteHeader(http.StatusUnauthorized)
if err := json.NewEncoder(w).Encode(err); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
return
}
if errors.Contains(err, errors.ErrAuthorization) {
w.WriteHeader(http.StatusForbidden)
if err := json.NewEncoder(w).Encode(err); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
return
}
switch retErr := err.(type) {
case *errors.RequestError:
w.WriteHeader(http.StatusBadRequest)
+19 -7
View File
@@ -10,16 +10,16 @@ import (
"testing"
"time"
"github.com/absmach/supermq"
api "github.com/absmach/supermq/api/http"
apiutil "github.com/absmach/supermq/api/http/util"
"github.com/absmach/supermq/internal/testsutil"
"github.com/absmach/supermq/pkg/errors"
svcerr "github.com/absmach/supermq/pkg/errors/service"
"github.com/absmach/magistrala"
api "github.com/absmach/magistrala/api/http"
apiutil "github.com/absmach/magistrala/api/http/util"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
"github.com/absmach/magistrala/pkg/testsutil"
"github.com/stretchr/testify/assert"
)
var _ supermq.Response = (*response)(nil)
var _ magistrala.Response = (*response)(nil)
var validUUID = testsutil.GenerateUUID(&testing.T{})
@@ -260,12 +260,24 @@ func TestEncodeError(t *testing.T) {
code: http.StatusUnauthorized,
hasBody: true,
},
{
desc: "Generic Authentication Failed",
err: errors.ErrAuthentication,
code: http.StatusUnauthorized,
hasBody: true,
},
{
desc: "AuthZError - Authorization Failed",
err: svcerr.ErrAuthorization,
code: http.StatusForbidden,
hasBody: true,
},
{
desc: "Generic Authorization Failed",
err: errors.Wrap(errors.New("not authorized"), errors.ErrAuthorization),
code: http.StatusForbidden,
hasBody: true,
},
{
desc: "AuthZError - Domain Authorization Failed",
err: svcerr.ErrDomainAuthorization,
+2 -2
View File
@@ -7,11 +7,11 @@ import (
"context"
"net/http"
"github.com/absmach/supermq"
"github.com/absmach/magistrala"
"github.com/go-chi/chi/v5/middleware"
)
func RequestIDMiddleware(idp supermq.IDProvider) func(http.Handler) http.Handler {
func RequestIDMiddleware(idp magistrala.IDProvider) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
requestID, err := idp.ID()
+1 -1
View File
@@ -3,7 +3,7 @@
package util
import "github.com/absmach/supermq/pkg/errors"
import "github.com/absmach/magistrala/pkg/errors"
// Errors defined in this file are used by the LoggingErrorEncoder decorator
// to distinguish and log API request validation errors and avoid that service
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"net/http"
"testing"
apiutil "github.com/absmach/supermq/api/http/util"
apiutil "github.com/absmach/magistrala/api/http/util"
"github.com/stretchr/testify/assert"
)
+1 -1
View File
@@ -10,7 +10,7 @@ import (
"net/http"
"strconv"
"github.com/absmach/supermq/pkg/errors"
"github.com/absmach/magistrala/pkg/errors"
kithttp "github.com/go-kit/kit/transport/http"
)
+5 -5
View File
@@ -11,10 +11,10 @@ import (
"net/url"
"testing"
apiutil "github.com/absmach/supermq/api/http/util"
smqlog "github.com/absmach/supermq/logger"
"github.com/absmach/supermq/pkg/errors"
svcerr "github.com/absmach/supermq/pkg/errors/service"
apiutil "github.com/absmach/magistrala/api/http/util"
mglog "github.com/absmach/magistrala/logger"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
"github.com/stretchr/testify/assert"
)
@@ -355,7 +355,7 @@ func TestLoggingErrorEncoder(t *testing.T) {
encCalled = true
}
errorEncoder := apiutil.LoggingErrorEncoder(smqlog.NewMock(), encFunc)
errorEncoder := apiutil.LoggingErrorEncoder(mglog.NewMock(), encFunc)
errorEncoder(context.Background(), c.err, httptest.NewRecorder())
assert.True(t, encCalled)
+5 -5
View File
@@ -2,13 +2,13 @@
# SPDX-License-Identifier: Apache-2.0
asyncapi: '2.6.0'
id: 'https://github.com/absmach/supermq/blob/main/api/asyncapi/mqtt.yaml'
id: 'https://github.com/absmach/magistrala/blob/main/api/asyncapi/mqtt.yaml'
info:
title: SuperMQ MQTT Adapter
title: Magistrala MQTT Adapter
version: '0.18.0'
contact:
name: SuperMQ Team
url: 'https://github.com/absmach/supermq'
name: Magistrala Team
url: 'https://github.com/absmach/magistrala'
email: info@absmach.eu
description: |
MQTT adapter provides an MQTT API for sending messages through the platform. MQTT adapter uses [mProxy](https://github.com/absmach/mproxy) for proxying traffic between client and MQTT broker.
@@ -16,7 +16,7 @@ info:
license:
name: Apache 2.0
url: 'https://github.com/absmach/supermq/blob/main/LICENSE'
url: 'https://github.com/absmach/magistrala/blob/main/LICENSE'
defaultContentType: application/json
+7 -7
View File
@@ -2,18 +2,18 @@
# SPDX-License-Identifier: Apache-2.0
asyncapi: 2.6.0
id: 'https://github.com/absmach/supermq/blob/main/api/asyncapi/websocket.yaml'
id: 'https://github.com/absmach/magistrala/blob/main/api/asyncapi/websocket.yaml'
info:
title: SuperMQ WebSocket adapter
title: Magistrala WebSocket adapter
description: WebSocket adapter provides a WebSocket API for sending messages through communication channels. WebSocket adapter uses [mProxy](https://github.com/absmach/mproxy) for proxying traffic between client and MQTT broker.
version: '0.18.0'
contact:
name: SuperMQ Team
url: 'https://github.com/absmach/supermq'
name: Magistrala Team
url: 'https://github.com/absmach/magistrala'
email: info@absmach.eu
license:
name: Apache 2.0
url: 'https://github.com/absmach/supermq/blob/main/LICENSE'
url: 'https://github.com/absmach/magistrala/blob/main/LICENSE'
tags:
- name: WebSocket
defaultContentType: application/json
@@ -28,7 +28,7 @@ servers:
description: Hostname of the WebSocket adapter
default: localhost
port:
description: SuperMQ WebSocket Adapter port
description: Magistrala WebSocket Adapter port
default: '8008'
channels:
@@ -74,7 +74,7 @@ channels:
- bearerAuth: []
/version:
subscribe:
summary: Get the version of the SuperMQ adapter
summary: Get the version of the Magistrala adapter
operationId: getVersion
bindings:
http:
+3 -3
View File
@@ -1,5 +1,5 @@
# SuperMQ OpenAPI Specification
# Magistrala OpenAPI Specification
This folder contains an OpenAPI specifications for SuperMQ API.
This folder contains an OpenAPI specifications for Magistrala API.
View specification in Swagger UI at [docs.api.supermq.absmach.eu](https://docs.api.supermq.absmach.eu)
View specification in Swagger UI at [docs.api.magistrala.absmach.eu](https://docs.api.magistrala.absmach.eu)
+508
View File
@@ -0,0 +1,508 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
openapi: 3.0.1
info:
title: Magistrala Alarms API
description: |
HTTP API for managing alarms service.
Some useful links:
- [The Magistrala repository](https://github.com/absmach/magistrala)
contact:
email: info@absmach.eu
license:
name: Apache 2.0
url: https://github.com/absmach/magistrala/blob/main/LICENSE
version: 0.18.5
servers:
- url: http://localhost:8050
- url: https://localhost:8050
tags:
- name: alarms
description: Everything about your Alarms
externalDocs:
description: Find out more about alarms
url: https://magistrala.absmach.eu/docs/
paths:
/{domainID}/alarms:
get:
operationId: listAlarms
summary: List Alarms
description: |
Retrieves a list of alarms with optional filtering
tags:
- alarms
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/Offset'
- $ref: '#/components/parameters/Limit'
- $ref: '#/components/parameters/Order'
- $ref: '#/components/parameters/Dir'
- $ref: '#/components/parameters/ChannelID'
- $ref: '#/components/parameters/ClientID'
- $ref: '#/components/parameters/Subtopic'
- $ref: '#/components/parameters/RuleID'
- $ref: '#/components/parameters/Status'
- $ref: '#/components/parameters/AssigneeID'
- $ref: '#/components/parameters/Severity'
- $ref: '#/components/parameters/UpdatedBy'
- $ref: '#/components/parameters/AssignedBy'
- $ref: '#/components/parameters/AcknowledgedBy'
- $ref: '#/components/parameters/ResolvedBy'
- $ref: '#/components/parameters/CreatedFrom'
- $ref: '#/components/parameters/CreatedTo'
security:
- bearerAuth: []
responses:
'200':
$ref: '#/components/responses/AlarmsPageRes'
'400':
description: Failed due to malformed query parameters
'401':
description: Missing or invalid access token
'422':
description: Database can't process request
'500':
$ref: '#/components/responses/ServiceError'
/{domainID}/alarms/{alarmID}:
get:
operationId: viewAlarm
summary: View Alarm
description: Retrieves an alarm by ID
tags:
- alarms
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/AlarmID'
security:
- bearerAuth: []
responses:
'200':
$ref: '#/components/responses/AlarmRes'
'400':
description: Missing or invalid alarm ID
'401':
description: Missing or invalid access token
'403':
description: Failed to perform authorization over the entity
'404':
description: Alarm does not exist
'422':
description: Database can't process request
'500':
$ref: '#/components/responses/ServiceError'
put:
operationId: updateAlarm
summary: Update Alarm
description: Updates an existing alarm
tags:
- alarms
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/AlarmID'
security:
- bearerAuth: []
requestBody:
$ref: '#/components/requestBodies/AlarmUpdateReq'
responses:
'200':
$ref: '#/components/responses/AlarmRes'
'400':
description: Failed due to malformed JSON
'401':
description: Missing or invalid access token
'403':
description: Failed to perform authorization over the entity
'404':
description: Alarm does not exist
'415':
description: Missing or invalid content type
'422':
description: Database can't process request
'500':
$ref: '#/components/responses/ServiceError'
delete:
operationId: deleteAlarm
summary: Delete Alarm
description: Deletes an alarm
tags:
- alarms
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/AlarmID'
security:
- bearerAuth: []
responses:
'204':
description: Alarm deleted successfully
'400':
description: Failed due to malformed alarm ID
'401':
description: Missing or invalid access token
'403':
description: Failed to perform authorization over the entity
'404':
description: Alarm does not exist
'422':
description: Database can't process request
'500':
$ref: '#/components/responses/ServiceError'
/health:
get:
summary: Retrieves service health check info
tags:
- health
security: []
responses:
'200':
$ref: '#/components/responses/HealthRes'
'500':
$ref: '#/components/responses/ServiceError'
components:
schemas:
Alarm:
type: object
properties:
id:
type: string
description: Unique alarm identifier
readOnly: true
rule_id:
type: string
description: Rule ID that triggered this alarm
domain_id:
type: string
description: Domain ID this alarm belongs to
channel_id:
type: string
description: Channel ID where the alarm was triggered
client_id:
type: string
description: Client ID that triggered the alarm
subtopic:
type: string
description: Subtopic associated with the alarm
status:
type: string
description: Alarm status
enum: [active, cleared]
measurement:
type: string
description: Measurement that triggered the alarm
value:
type: string
description: Value that triggered the alarm
unit:
type: string
description: Unit of measurement
threshold:
type: string
description: Threshold value that was exceeded
cause:
type: string
description: Cause or description of the alarm
severity:
type: integer
description: Severity level (0-100)
minimum: 0
maximum: 100
assignee_id:
type: string
description: ID of the user assigned to this alarm
created_at:
type: string
format: date-time
description: Creation timestamp
readOnly: true
updated_at:
type: string
format: date-time
description: Last update timestamp
readOnly: true
updated_by:
type: string
description: User who last updated the alarm
readOnly: true
assigned_at:
type: string
format: date-time
description: When the alarm was assigned
readOnly: true
assigned_by:
type: string
description: User who assigned the alarm
readOnly: true
acknowledged_at:
type: string
format: date-time
description: When the alarm was acknowledged
readOnly: true
acknowledged_by:
type: string
description: User who acknowledged the alarm
readOnly: true
resolved_at:
type: string
format: date-time
description: When the alarm was resolved
readOnly: true
resolved_by:
type: string
description: User who resolved the alarm
readOnly: true
metadata:
type: object
description: Custom metadata
additionalProperties: true
AlarmsPage:
type: object
properties:
offset:
type: integer
description: Number of items to skip during retrieval
minimum: 0
default: 0
limit:
type: integer
description: Size of the subset to retrieve
minimum: 1
maximum: 1000
default: 10
total:
type: integer
description: Total number of results
minimum: 0
alarms:
type: array
minItems: 0
items:
$ref: '#/components/schemas/Alarm'
required:
- alarms
- total
- offset
- limit
parameters:
DomainID:
name: domainID
description: Domain ID
in: path
required: true
schema:
type: string
AlarmID:
name: alarmID
description: Alarm ID
in: path
required: true
schema:
type: string
Offset:
name: offset
description: Number of items to skip
in: query
required: false
schema:
type: integer
default: 0
minimum: 0
Limit:
name: limit
description: Size of the subset to retrieve
in: query
required: false
schema:
type: integer
default: 10
minimum: 1
maximum: 1000
Order:
name: order
description: Order by field
in: query
required: false
schema:
type: string
enum: [created_at, updated_at]
default: created_at
Dir:
name: dir
description: Sort direction
in: query
required: false
schema:
type: string
enum: [asc, desc]
default: desc
ChannelID:
name: channel_id
description: Filter by channel ID
in: query
required: false
schema:
type: string
ClientID:
name: client_id
description: Filter by client ID
in: query
required: false
schema:
type: string
Subtopic:
name: subtopic
description: Filter by subtopic
in: query
required: false
schema:
type: string
RuleID:
name: rule_id
description: Filter by rule ID
in: query
required: false
schema:
type: string
Status:
name: status
description: Filter by alarm status
in: query
required: false
schema:
type: string
enum: [active, cleared, all]
default: all
AssigneeID:
name: assignee_id
description: Filter by assignee ID
in: query
required: false
schema:
type: string
Severity:
name: severity
description: Filter by severity level
in: query
required: false
schema:
type: integer
minimum: 0
maximum: 100
UpdatedBy:
name: updated_by
description: Filter by user who updated
in: query
required: false
schema:
type: string
AssignedBy:
name: assigned_by
description: Filter by user who assigned
in: query
required: false
schema:
type: string
AcknowledgedBy:
name: acknowledged_by
description: Filter by user who acknowledged
in: query
required: false
schema:
type: string
ResolvedBy:
name: resolved_by
description: Filter by user who resolved
in: query
required: false
schema:
type: string
CreatedFrom:
name: created_from
description: Filter alarms created after this time (RFC3339 format)
in: query
required: false
schema:
type: string
format: date-time
CreatedTo:
name: created_to
description: Filter alarms created before this time (RFC3339 format)
in: query
required: false
schema:
type: string
format: date-time
requestBodies:
AlarmUpdateReq:
description: JSON-formatted document describing the alarm update
required: true
content:
application/json:
schema:
type: object
properties:
status:
type: string
description: Alarm status
enum: [active, cleared]
assignee_id:
type: string
description: ID of the user assigned to this alarm
severity:
type: integer
description: Severity level (0-100)
minimum: 0
maximum: 100
metadata:
type: object
description: Custom metadata
additionalProperties: true
responses:
AlarmRes:
description: Alarm data retrieved
content:
application/json:
schema:
$ref: '#/components/schemas/Alarm'
links:
update:
operationId: updateAlarm
parameters:
alarmID: $response.body#/id
domainID: $response.body#/domain_id
delete:
operationId: deleteAlarm
parameters:
alarmID: $response.body#/id
domainID: $response.body#/domain_id
AlarmsPageRes:
description: Alarms page retrieved
content:
application/json:
schema:
$ref: '#/components/schemas/AlarmsPage'
ServiceError:
description: Unexpected server-side error occurred
HealthRes:
description: Service Health Check
content:
application/health+json:
schema:
$ref: "./schemas/health_info.yaml"
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: |
* Users access: "Authorization: Bearer <user_token>"
+52 -41
View File
@@ -3,16 +3,16 @@
openapi: 3.0.3
info:
title: SuperMQ Auth Service
title: Magistrala Auth Service
description: |
This is the Auth Server based on the OpenAPI 3.0 specification. It is the HTTP API for managing platform users. You can now help us improve the API whether it's by making changes to the definition itself or to the code.
Some useful links:
- [The SuperMQ repository](https://github.com/absmach/supermq)
- [The Magistrala repository](https://github.com/absmach/magistrala)
contact:
email: info@absmach.eu
license:
name: Apache 2.0
url: https://github.com/absmach/supermq/blob/main/LICENSE
url: https://github.com/absmach/magistrala/blob/main/LICENSE
version: 0.18.0
servers:
@@ -24,17 +24,17 @@ tags:
description: Everything about your Keys.
externalDocs:
description: Find out more about keys
url: https://docs.supermq.absmach.eu/
url: https://magistrala.absmach.eu/docs/
- name: PATs
description: Everything about your Personal Access Tokens.
externalDocs:
description: Find out more about Personal Access Tokens
url: https://docs.supermq.absmach.eu/
url: https://magistrala.absmach.eu/docs/
- name: Health
description: Service health check endpoint.
externalDocs:
description: Find out more about health check
url: https://docs.supermq.absmach.eu/
url: https://magistrala.absmach.eu/docs/
paths:
/keys:
@@ -81,6 +81,8 @@ paths:
description: Missing or invalid access token provided.
"404":
description: A non-existent entity request.
"422":
description: Service can't process request.
"500":
$ref: "#/components/responses/ServiceError"
@@ -100,6 +102,8 @@ paths:
description: Missing or invalid access token provided.
"404":
description: A non-existent entity request.
"422":
description: Service can't process request.
"500":
$ref: "#/components/responses/ServiceError"
@@ -124,7 +128,7 @@ paths:
description: Missing or invalid content type.
"500":
$ref: "#/components/responses/ServiceError"
get:
operationId: listPATs
tags:
@@ -144,7 +148,7 @@ paths:
description: Missing or invalid access token provided.
"500":
$ref: "#/components/responses/ServiceError"
delete:
operationId: clearAllPATs
tags:
@@ -159,7 +163,7 @@ paths:
description: Missing or invalid access token provided.
"500":
$ref: "#/components/responses/ServiceError"
/pats/{patID}:
get:
operationId: retrievePAT
@@ -181,7 +185,7 @@ paths:
description: PAT not found.
"500":
$ref: "#/components/responses/ServiceError"
delete:
operationId: deletePAT
tags:
@@ -200,7 +204,7 @@ paths:
description: PAT not found.
"500":
$ref: "#/components/responses/ServiceError"
/pats/{patID}/name:
patch:
operationId: updatePATName
@@ -226,7 +230,7 @@ paths:
description: Missing or invalid content type.
"500":
$ref: "#/components/responses/ServiceError"
/pats/{patID}/description:
patch:
operationId: updatePATDescription
@@ -252,7 +256,7 @@ paths:
description: Missing or invalid content type.
"500":
$ref: "#/components/responses/ServiceError"
/pats/{patID}/secret/reset:
patch:
operationId: resetPATSecret
@@ -278,7 +282,7 @@ paths:
description: Missing or invalid content type.
"500":
$ref: "#/components/responses/ServiceError"
/pats/{patID}/secret/revoke:
patch:
operationId: revokePATSecret
@@ -298,7 +302,7 @@ paths:
description: PAT not found.
"500":
$ref: "#/components/responses/ServiceError"
/pats/{patID}/scope:
get:
operationId: listScopes
@@ -322,7 +326,7 @@ paths:
description: PAT not found.
"500":
$ref: "#/components/responses/ServiceError"
delete:
operationId: clearAllScopes
tags:
@@ -341,7 +345,7 @@ paths:
description: PAT not found.
"500":
$ref: "#/components/responses/ServiceError"
/pats/{patID}/scope/add:
patch:
operationId: addScope
@@ -369,7 +373,7 @@ paths:
description: Database cannot process the request.
"500":
$ref: "#/components/responses/ServiceError"
/pats/{patID}/scope/remove:
patch:
operationId: removeScope
@@ -396,7 +400,6 @@ paths:
"500":
$ref: "#/components/responses/ServiceError"
/health:
get:
summary: Retrieves service health check info.
@@ -465,7 +468,7 @@ components:
format: date-time
example: "2019-11-26T13:31:52Z"
description: Time when the PAT was revoked
PATsPage:
type: object
properties:
@@ -486,20 +489,10 @@ components:
items:
$ref: "#/components/schemas/PAT"
description: List of Personal Access Tokens
Scope:
type: object
properties:
id:
type: string
format: uuid
example: "c5747f2f-2a7c-4fe1-b41a-51a5ae290945"
description: Scope unique identifier
pat_id:
type: string
format: uuid
example: "9118de62-c680-46b7-ad0a-21748a52833a"
description: PAT ID this scope belongs to
optional_domain_id:
type: string
format: uuid
@@ -507,7 +500,8 @@ components:
description: Optional domain ID for the scope
entity_type:
type: string
enum: [groups, channels, clients, domains, users, dashboards, messages]
enum:
[groups, channels, clients, domains, users, dashboards, messages]
example: "groups"
description: Type of entity the scope applies to
entity_id:
@@ -516,10 +510,21 @@ components:
description: ID of the entity the scope applies to. '*' means all entities of the specified type.
operation:
type: string
enum: [create, read, list, update, delete, share, unshare, publish, subscribe]
enum:
[
create,
read,
list,
update,
delete,
share,
unshare,
publish,
subscribe,
]
example: "read"
description: Operation allowed by this scope
ScopesPage:
type: object
properties:
@@ -679,9 +684,11 @@ components:
type: object
required:
- name
- duration
properties:
name:
type: string
minLength: 1
example: "My PAT"
description: Name of the Personal Access Token
description:
@@ -690,9 +697,10 @@ components:
description: Description of the Personal Access Token
duration:
type: string
pattern: "^[0-9]+(ns|us|µs|ms|s|m|h|d|w|y)$"
example: "30d"
description: Duration for which the PAT is valid. Format is a duration string (e.g. "30d", "24h", "1y").
UpdatePATNameRequest:
description: JSON-formatted document describing PAT name update request.
required: true
@@ -707,7 +715,7 @@ components:
type: string
example: "New PAT Name"
description: New name for the Personal Access Token
UpdatePATDescriptionRequest:
description: JSON-formatted document describing PAT description update request.
required: true
@@ -722,7 +730,7 @@ components:
type: string
example: "New PAT Description"
description: New description for the Personal Access Token
ResetPATSecretRequest:
description: JSON-formatted document describing PAT secret reset request.
required: true
@@ -730,12 +738,15 @@ components:
application/json:
schema:
type: object
required:
- duration
properties:
duration:
type: string
pattern: "^[0-9]+(ns|us|µs|ms|s|m|h|d|w|y)$"
example: "30d"
description: Duration for which the new PAT secret is valid. Format is a duration string (e.g. "30d", "24h", "1y").
AddScopeRequest:
description: JSON-formatted document describing add scope request.
required: true
@@ -751,7 +762,7 @@ components:
items:
$ref: "#/components/schemas/Scope"
description: List of scopes to add
RemoveScopeRequest:
description: JSON-formatted document describing remove scope request.
required: true
@@ -793,14 +804,14 @@ components:
application/json:
schema:
$ref: "#/components/schemas/PAT"
PATsPageRes:
description: Page of Personal Access Tokens.
content:
application/json:
schema:
$ref: "#/components/schemas/PATsPage"
ScopesPageRes:
description: Page of scopes.
content:
File diff suppressed because it is too large Load Diff
+722
View File
@@ -0,0 +1,722 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
openapi: 3.0.3
info:
title: Certs Service API
description: |
Certificate management service for issuing, renewing, revoking, and managing X.509 certificates.
This service provides PKI functionality including certificate lifecycle management, OCSP responder,
and CRL generation.
version: 1.0.0
contact:
name: Abstract Machines
license:
name: Apache-2.0
url: https://www.apache.org/licenses/LICENSE-2.0.html
servers:
- url: http://localhost:9019
description: Development server
tags:
- name: certificates
description: Certificate lifecycle management operations
- name: pki
description: PKI infrastructure operations (OCSP, CRL, CA)
- name: health
description: Service health and monitoring
security:
- BearerAuth: []
paths:
/{domainID}/certs/issue/{entityID}:
post:
tags:
- certificates
summary: Issue a new certificate
description: Issues a new X.509 certificate for the specified entity with custom subject options
operationId: issueCert
security:
- BearerAuth: []
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/EntityID'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/IssueCertRequest'
responses:
'201':
description: Certificate successfully issued
content:
application/json:
schema:
$ref: '#/components/schemas/CertificateResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'500':
$ref: '#/components/responses/InternalServerError'
/{domainID}/certs/{id}/renew:
patch:
tags:
- certificates
summary: Renew a certificate
description: Renews an existing certificate with extended TTL and new serial number
operationId: renewCert
security:
- BearerAuth: []
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/CertID'
responses:
'200':
description: Certificate successfully renewed
content:
application/json:
schema:
$ref: '#/components/schemas/RenewCertResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
'500':
$ref: '#/components/responses/InternalServerError'
/{domainID}/certs/{id}/revoke:
patch:
tags:
- certificates
summary: Revoke a certificate
description: Revokes a certificate by its serial number
operationId: revokeCert
security:
- BearerAuth: []
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/CertID'
responses:
'204':
description: Certificate successfully revoked
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
'422':
$ref: '#/components/responses/UnprocessableEntity'
'500':
$ref: '#/components/responses/InternalServerError'
/{domainID}/certs/{entityID}/delete:
delete:
tags:
- certificates
summary: Delete certificates for an entity
description: Deletes all certificates associated with the specified entity
operationId: deleteCert
security:
- BearerAuth: []
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/EntityID'
responses:
'204':
description: Certificates successfully deleted
'401':
$ref: '#/components/responses/Unauthorized'
'422':
$ref: '#/components/responses/UnprocessableEntity'
'500':
$ref: '#/components/responses/InternalServerError'
/{domainID}/certs:
get:
tags:
- certificates
summary: List certificates
description: Retrieves a paginated list of certificates with optional filtering by entity ID
operationId: listCerts
security:
- BearerAuth: []
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/Offset'
- $ref: '#/components/parameters/Limit'
- $ref: '#/components/parameters/EntityIDFilter'
responses:
'200':
description: Certificates successfully retrieved
content:
application/json:
schema:
$ref: '#/components/schemas/CertificateListResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'500':
$ref: '#/components/responses/InternalServerError'
/{domainID}/certs/{id}:
get:
tags:
- certificates
summary: View certificate details
description: Retrieves detailed information about a specific certificate by serial number
operationId: viewCert
security:
- BearerAuth: []
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/CertID'
responses:
'200':
description: Certificate details successfully retrieved
content:
application/json:
schema:
$ref: '#/components/schemas/ViewCertResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
'500':
$ref: '#/components/responses/InternalServerError'
/{domainID}/certs/csrs/{entityID}:
post:
tags:
- certificates
summary: Issue certificate from CSR
description: Issues a certificate from a Certificate Signing Request (CSR)
operationId: issueFromCSR
security:
- BearerAuth: []
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/EntityID'
- $ref: '#/components/parameters/TTL'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/IssueFromCSRRequest'
responses:
'200':
description: Certificate successfully issued from CSR
content:
application/json:
schema:
$ref: '#/components/schemas/IssueFromCSRResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'500':
$ref: '#/components/responses/InternalServerError'
/certs/csrs/{entityID}:
post:
tags:
- certificates
summary: Issue certificate from CSR (Internal)
description: Issues a certificate from a CSR using internal agent authentication
operationId: issueFromCSRInternal
security:
- AgentAuth: []
parameters:
- $ref: '#/components/parameters/EntityID'
- $ref: '#/components/parameters/TTL'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/IssueFromCSRRequest'
responses:
'200':
description: Certificate successfully issued from CSR
content:
application/json:
schema:
$ref: '#/components/schemas/IssueFromCSRResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'500':
$ref: '#/components/responses/InternalServerError'
/certs/ocsp:
post:
tags:
- pki
summary: OCSP responder
description: |
Online Certificate Status Protocol (OCSP) responder endpoint.
Accepts both binary OCSP requests and JSON format requests.
operationId: ocsp
security: []
parameters:
- name: force_status
in: query
description: Force a specific OCSP status for testing
required: false
schema:
type: string
requestBody:
required: true
content:
application/ocsp-request:
schema:
type: string
format: binary
description: DER-encoded OCSP request
application/json:
schema:
$ref: '#/components/schemas/OCSPRequest'
responses:
'200':
description: OCSP response
content:
application/ocsp-response:
schema:
type: string
format: binary
description: DER-encoded OCSP response
'400':
$ref: '#/components/responses/BadRequest'
'500':
$ref: '#/components/responses/InternalServerError'
/certs/crl:
get:
tags:
- pki
summary: Generate Certificate Revocation List
description: Generates and returns the current Certificate Revocation List (CRL)
operationId: generateCRL
security: []
responses:
'200':
description: CRL successfully generated
content:
application/json:
schema:
$ref: '#/components/schemas/CRLResponse'
'500':
$ref: '#/components/responses/InternalServerError'
/certs/view-ca:
get:
tags:
- pki
summary: View CA certificate
description: Retrieves the CA certificate chain (root and intermediate certificates)
operationId: viewCA
security: []
responses:
'200':
description: CA certificate successfully retrieved
content:
application/json:
schema:
$ref: '#/components/schemas/ViewCertResponse'
'500':
$ref: '#/components/responses/InternalServerError'
/certs/download-ca:
get:
tags:
- pki
summary: Download CA certificate
description: Downloads the CA certificate as a ZIP file
operationId: downloadCA
security: []
responses:
'200':
description: CA certificate ZIP file
content:
application/zip:
schema:
type: string
format: binary
'500':
$ref: '#/components/responses/InternalServerError'
/health:
get:
summary: Retrieves service health check info.
tags:
- health
security: []
responses:
'200':
$ref: '#/components/responses/HealthRes'
'500':
$ref: '#/components/responses/InternalServerError'
/metrics:
get:
tags:
- health
summary: Prometheus metrics
description: Returns Prometheus metrics for monitoring
operationId: metrics
security: []
responses:
'200':
description: Metrics successfully retrieved
content:
text/plain:
schema:
type: string
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: User authentication token
AgentAuth:
type: http
scheme: bearer
description: Agent authentication token for internal operations
parameters:
DomainID:
name: domainID
in: path
required: true
description: Domain identifier
schema:
type: string
EntityID:
name: entityID
in: path
required: true
description: Entity identifier for the certificate
schema:
type: string
CertID:
name: id
in: path
required: true
description: Certificate serial number
schema:
type: string
Offset:
name: offset
in: query
description: Number of items to skip
schema:
type: integer
minimum: 0
default: 0
Limit:
name: limit
in: query
description: Maximum number of items to return
schema:
type: integer
minimum: 1
maximum: 100
default: 10
EntityIDFilter:
name: entity_id
in: query
description: Filter certificates by entity ID
schema:
type: string
TTL:
name: ttl
in: query
description: Time to live for the certificate (e.g., "8760h", "365d")
schema:
type: string
schemas:
IssueCertRequest:
type: object
required:
- options
properties:
ttl:
type: string
description: Time to live for the certificate (e.g., "8760h" for 1 year)
example: "8760h"
ip_addresses:
type: array
items:
type: string
description: IP addresses to include in the certificate
example: ["192.168.1.1", "10.0.0.1"]
options:
$ref: '#/components/schemas/SubjectOptions'
SubjectOptions:
type: object
required:
- common_name
properties:
common_name:
type: string
description: Common Name (CN) for the certificate subject
example: "example.com"
organization:
type: array
items:
type: string
description: Organization (O)
example: ["Abstract Machines"]
organizational_unit:
type: array
items:
type: string
description: Organizational Unit (OU)
example: ["Engineering"]
country:
type: array
items:
type: string
description: Country (C)
example: ["US"]
province:
type: array
items:
type: string
description: Province or State (ST)
example: ["California"]
locality:
type: array
items:
type: string
description: Locality or City (L)
example: ["San Francisco"]
street_address:
type: array
items:
type: string
description: Street Address
example: ["123 Main St"]
postal_code:
type: array
items:
type: string
description: Postal Code
example: ["94105"]
dns_names:
type: array
items:
type: string
description: DNS names for Subject Alternative Names
example: ["example.com", "www.example.com"]
ip_addresses:
type: array
items:
type: string
description: IP addresses for Subject Alternative Names
example: ["192.168.1.1"]
CertificateResponse:
type: object
properties:
serial_number:
type: string
description: Unique serial number of the certificate
example: "4a:3f:5e:2c:1b:8d:9e:7f"
certificate:
type: string
description: PEM-encoded certificate
example: "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
key:
type: string
description: PEM-encoded private key
example: "-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"
revoked:
type: boolean
description: Whether the certificate is revoked
example: false
expiry_time:
type: string
format: date-time
description: Certificate expiration time
example: "2026-11-05T12:00:00Z"
entity_id:
type: string
description: Entity identifier associated with the certificate
example: "entity-123"
RenewCertResponse:
type: object
properties:
certificate:
$ref: '#/components/schemas/ViewCertResponse'
ViewCertResponse:
type: object
properties:
serial_number:
type: string
description: Certificate serial number
example: "4a:3f:5e:2c:1b:8d:9e:7f"
certificate:
type: string
description: PEM-encoded certificate
example: "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
key:
type: string
description: PEM-encoded private key
example: "-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"
revoked:
type: boolean
description: Revocation status
example: false
expiry_time:
type: string
format: date-time
description: Expiration timestamp
example: "2026-11-05T12:00:00Z"
entity_id:
type: string
description: Associated entity identifier
example: "entity-123"
CertificateListResponse:
type: object
properties:
total:
type: integer
format: uint64
description: Total number of certificates
example: 100
offset:
type: integer
format: uint64
description: Current offset
example: 0
limit:
type: integer
format: uint64
description: Current limit
example: 10
certificates:
type: array
items:
$ref: '#/components/schemas/ViewCertResponse'
IssueFromCSRRequest:
type: object
required:
- csr
properties:
csr:
type: string
format: byte
description: PEM-encoded Certificate Signing Request
example: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K..."
IssueFromCSRResponse:
type: object
properties:
serial_number:
type: string
description: Serial number of the issued certificate
example: "4a:3f:5e:2c:1b:8d:9e:7f"
certificate:
type: string
description: PEM-encoded certificate
example: "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
revoked:
type: boolean
description: Revocation status
example: false
expiry_time:
type: string
format: date-time
description: Expiration timestamp
example: "2026-11-05T12:00:00Z"
entity_id:
type: string
description: Associated entity identifier
example: "entity-123"
OCSPRequest:
type: object
properties:
serial_number:
type: string
description: Certificate serial number to check
example: "4a:3f:5e:2c:1b:8d:9e:7f"
certificate:
type: string
description: PEM-encoded certificate to check
example: "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
status:
type: string
description: Force a specific status (for testing)
enum: [good, revoked, unknown]
CRLResponse:
type: object
properties:
crl:
type: string
format: byte
description: DER-encoded Certificate Revocation List
Error:
type: object
properties:
error:
type: string
description: Error message
example: "invalid request"
responses:
BadRequest:
description: Bad request - invalid parameters or malformed request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Unauthorized:
description: Unauthorized - invalid or missing authentication token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
UnprocessableEntity:
description: Unprocessable entity - request cannot be processed
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
InternalServerError:
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
HealthRes:
description: Service Health Check.
content:
application/health+json:
schema:
$ref: './schemas/health_info.yaml'
+43 -21
View File
@@ -3,16 +3,16 @@
openapi: 3.0.3
info:
title: SuperMQ Channels Service
title: Magistrala Channels Service
description: |
This is the Channels Server based on the OpenAPI 3.0 specification. It is the HTTP API for managing platform channels. You can now help us improve the API whether it's by making changes to the definition itself or to the code.
Some useful links:
- [The SuperMQ repository](https://github.com/absmach/supermq)
- [The Magistrala repository](https://github.com/absmach/magistrala)
contact:
email: info@absmach.eu
license:
name: Apache 2.0
url: https://github.com/absmach/supermq/blob/main/LICENSE
url: https://github.com/absmach/magistrala/blob/main/LICENSE
version: 0.18.0
servers:
@@ -24,17 +24,17 @@ tags:
description: CRUD operations for your channels
externalDocs:
description: Find out more about channels
url: https://docs.supermq.absmach.eu/
url: https://magistrala.absmach.eu/docs/
- name: Connections
description: All operations involving channel and client connections
externalDocs:
description: Find out more about channel and client connections
url: https://docs.supermq.absmach.eu/
url: https://magistrala.absmach.eu/docs/
- name: Health
description: Health check operations
externalDocs:
description: Find out more about health checks
url: https://docs.supermq.absmach.eu/
url: https://magistrala.absmach.eu/docs/
paths:
/{domainID}/channels:
@@ -89,6 +89,7 @@ paths:
- $ref: "#/components/parameters/Offset"
- $ref: "#/components/parameters/Order"
- $ref: "#/components/parameters/Direction"
- $ref: "#/components/parameters/Tags"
- $ref: "#/components/parameters/Metadata"
- $ref: "#/components/parameters/Status"
- $ref: "#/components/parameters/ChannelName"
@@ -101,6 +102,8 @@ paths:
- $ref: "#/components/parameters/Client"
- $ref: "#/components/parameters/Group"
- $ref: "#/components/parameters/User"
- $ref: "#/components/parameters/CreatedFrom"
- $ref: "#/components/parameters/CreatedTo"
responses:
"200":
$ref: "#/components/responses/ChannelPageRes"
@@ -656,9 +659,7 @@ components:
example: 10
description: Maximum number of items to return in one page.
required:
- channels
- total
- offset
ChannelUpdate:
type: object
@@ -705,7 +706,10 @@ components:
type: array
description: Connection types.
items:
example: publish
type: string
enum:
- publish
- subscribe
ChannelConnectionReqSchema:
type: object
@@ -719,7 +723,10 @@ components:
type: array
description: Connection types.
items:
example: publish
type: string
enum:
- publish
- subscribe
Error:
type: object
@@ -776,16 +783,12 @@ components:
Tags:
name: tags
description: Client tags.
description: Channel tags. Multiple tags can be specified separated by comma for OR condition and plus for AND condition.
in: query
schema:
type: array
minItems: 0
uniqueItems: true
items:
type: string
type: string
required: false
example: ["yello", "orange"]
example: "orange,yellow"
ChannelName:
name: name
@@ -831,7 +834,6 @@ components:
in: query
schema:
type: string
minimum: 0
required: false
Limit:
@@ -844,7 +846,7 @@ components:
maximum: 100
minimum: 1
required: false
example: "100"
example: 100
Offset:
name: offset
@@ -855,8 +857,8 @@ components:
default: 0
minimum: 0
required: false
example: "0"
example: 0
Order:
name: order
description: Field by which to order the results
@@ -944,6 +946,26 @@ components:
required: false
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
CreatedFrom:
name: created_from
description: Filter channels created from this date (inclusive).
in: query
schema:
type: string
format: date-time
required: false
example: "2023-01-01T00:00:00Z"
CreatedTo:
name: created_to
description: Filter channels created up to this date (inclusive).
in: query
schema:
type: string
format: date-time
required: false
example: "2023-12-31T23:59:59Z"
requestBodies:
ChannelCreateReq:
description: JSON-formatted document describing the new channel to be registered
+57 -23
View File
@@ -3,16 +3,16 @@
openapi: 3.0.3
info:
title: SuperMQ Clients Service
title: Magistrala Clients Service
description: |
This is the Clients Server based on the OpenAPI 3.0 specification. It is the HTTP API for managing platform clients. You can now help us improve the API whether it's by making changes to the definition itself or to the code.
Some useful links:
- [The SuperMQ repository](https://github.com/absmach/supermq)
- [The Magistrala repository](https://github.com/absmach/magistrala)
contact:
email: info@absmach.eu
license:
name: Apache 2.0
url: https://github.com/absmach/supermq/blob/main/LICENSE
url: https://github.com/absmach/magistrala/blob/main/LICENSE
version: 0.18.0
servers:
@@ -24,17 +24,17 @@ tags:
description: CRUD operations for your clients
externalDocs:
description: Find out more about clients
url: https://docs.supermq.absmach.eu/
url: https://magistrala.absmach.eu/docs/
- name: Roles
description: All operations involving roles for clients
externalDocs:
description: Find out more about roles
url: https://docs.supermq.absmach.eu/
url: https://magistrala.absmach.eu/docs/
- name: Health
description: Health check operations
externalDocs:
description: Find out more about health checks
url: https://docs.supermq.absmach.eu/
url: https://magistrala.absmach.eu/docs/
paths:
/{domainID}/clients:
@@ -100,6 +100,8 @@ paths:
- $ref: "#/components/parameters/ConnectionType"
- $ref: "#/components/parameters/Group"
- $ref: "#/components/parameters/User"
- $ref: "#/components/parameters/CreatedFrom"
- $ref: "#/components/parameters/CreatedTo"
security:
- bearerAuth: []
responses:
@@ -181,7 +183,7 @@ paths:
patch:
operationId: updateClient
summary: Updates name and metadata of the client.
summary: Updates name, metadata, and private metadata of the client.
description: |
Update is performed by replacing the current resource data with values
provided in a request payload. Note that the client's type and ID
@@ -943,10 +945,14 @@ components:
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
minimum: 8
description: Free-form account secret used for acquiring auth token(s).
private_metadata:
type: object
example: { "model": "example" }
description: Arbitrary, object-encoded client's data private to the client.
metadata:
type: object
example: { "model": "example" }
description: Arbitrary, object-encoded client's data.
description: Arbitrary, object-encoded client's data visible to other clients.
status:
type: string
description: Client Status
@@ -1001,10 +1007,14 @@ components:
type: string
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
description: Client secret password.
private_metadata:
type: object
example: { "model": "example" }
description: Arbitrary, object-encoded client's data private to the client.
metadata:
type: object
example: { "model": "example" }
description: Arbitrary, object-encoded client's data.
description: Arbitrary, object-encoded client's data visible to other clients.
status:
type: string
description: Client Status
@@ -1058,10 +1068,14 @@ components:
type: string
example: ""
description: Client secret password.
private_metadata:
type: object
example: { "model": "example" }
description: Arbitrary, object-encoded client's data private to the client.
metadata:
type: object
example: { "model": "example" }
description: Arbitrary, object-encoded client's data.
description: Arbitrary, object-encoded client's data visible to other clients.
status:
type: string
description: Client Status
@@ -1113,9 +1127,14 @@ components:
metadata:
type: object
example: { "role": "general" }
description: Arbitrary, object-encoded client's data.
description: Arbitrary, object-encoded client's data visible to other clients.
private_metadata:
type: object
example: { "role": "general" }
description: Arbitrary, object-encoded client's data private to the client.
required:
- name
- private_metadata
- metadata
ClientTags:
@@ -1168,7 +1187,7 @@ components:
metadata:
type: object
example: { "model": "example" }
description: Arbitrary, object-encoded client's data.
description: Arbitrary, object-encoded client's data visible to other clients.
status:
type: string
description: Client Status
@@ -1265,16 +1284,12 @@ components:
Tags:
name: tags
description: Client tags.
description: Clients tags. Multiple tags can be specified separated by comma for OR condition and plus for AND condition.
in: query
schema:
type: array
minItems: 0
uniqueItems: true
items:
type: string
type: string
required: false
example: ["yello", "orange"]
example: "orange,yellow"
Metadata:
name: metadata
@@ -1282,7 +1297,6 @@ components:
in: query
schema:
type: string
minimum: 0
required: false
Limit:
@@ -1295,7 +1309,7 @@ components:
maximum: 100
minimum: 1
required: false
example: "100"
example: 100
Offset:
name: offset
@@ -1306,7 +1320,7 @@ components:
default: 0
minimum: 0
required: false
example: "0"
example: 0
Order:
name: order
@@ -1406,6 +1420,26 @@ components:
minLength: 36
required: false
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
CreatedFrom:
name: created_from
description: Filter clients created from this date (inclusive).
in: query
schema:
type: string
format: date-time
required: false
example: "2023-01-01T00:00:00Z"
CreatedTo:
name: created_to
description: Filter clients created up to this date (inclusive).
in: query
schema:
type: string
format: date-time
required: false
example: "2023-12-31T23:59:59Z"
requestBodies:
ClientCreateReq:
@@ -1427,7 +1461,7 @@ components:
$ref: "#/components/schemas/ClientReqObj"
ClientUpdateReq:
description: JSON-formated document describing the metadata and name of client to be update
description: JSON-formated document describing the metadata, private metadata and name of client to be update
required: true
content:
application/json:
+38 -7
View File
@@ -3,16 +3,16 @@
openapi: 3.0.3
info:
title: SuperMQ Domains Service
title: Magistrala Domains Service
description: |
This is the Domains Server based on the OpenAPI 3.0 specification. It is the HTTP API for managing platform domains. You can now help us improve the API whether it's by making changes to the definition itself or to the code.
Some useful links:
- [The SuperMQ repository](https://github.com/absmach/supermq)
- [The Magistrala repository](https://github.com/absmach/magistrala)
contact:
email: info@absmach.eu
license:
name: Apache 2.0
url: https://github.com/absmach/supermq/blob/main/LICENSE
url: https://github.com/absmach/magistrala/blob/main/LICENSE
version: 0.18.0
servers:
@@ -24,22 +24,22 @@ tags:
description: CRUD operations for your domains
externalDocs:
description: Find out more about domains
url: https://docs.supermq.absmach.eu/
url: https://magistrala.absmach.eu/docs/
- name: Roles
description: All operations involving roles for domains
externalDocs:
description: Find out more about roles
url: https://docs.supermq.absmach.eu/
url: https://magistrala.absmach.eu/docs/
- name: Invitations
description: All operations involving invitations for domains
externalDocs:
description: Find out more about Invitations
url: https://docs.supermq.absmach.eu/
url: https://magistrala.absmach.eu/docs/
- name: Health
description: Service health check endpoint.
externalDocs:
description: Find out more about health check
url: https://docs.supermq.absmach.eu/
url: https://magistrala.absmach.eu/docs/
paths:
/domains:
@@ -76,6 +76,7 @@ paths:
- $ref: "#/components/parameters/Order"
- $ref: "#/components/parameters/Direction"
- $ref: "#/components/parameters/Metadata"
- $ref: "#/components/parameters/Tags"
- $ref: "#/components/parameters/Status"
- $ref: "#/components/parameters/DomainName"
- $ref: "./schemas/roles.yaml#/components/parameters/ActionsQuery"
@@ -83,6 +84,8 @@ paths:
- $ref: "./schemas/roles.yaml#/components/parameters/RoleNameQuery"
- $ref: "#/components/parameters/AccessType"
- $ref: "#/components/parameters/OnlyTotal"
- $ref: "#/components/parameters/CreatedFrom"
- $ref: "#/components/parameters/CreatedTo"
tags:
- Domains
security:
@@ -1179,6 +1182,14 @@ components:
schema:
type: object
additionalProperties: {}
Tags:
name: tags
description: Domain tags. Multiple tags can be specified separated by comma for OR condition and plus for AND condition.
in: query
schema:
type: string
required: false
example: "orange,yellow"
Type:
name: type
description: The type of the API Key.
@@ -1282,6 +1293,26 @@ components:
default: false
required: false
CreatedFrom:
name: created_from
description: Filter domains created from this date (inclusive).
in: query
schema:
type: string
format: date-time
required: false
example: "2023-01-01T00:00:00Z"
CreatedTo:
name: created_to
description: Filter domains created up to this date (inclusive).
in: query
schema:
type: string
format: date-time
required: false
example: "2023-12-31T23:59:59Z"
requestBodies:
DomainCreateReq:
description: JSON-formatted document describing the new domain to be registered
+65 -32
View File
@@ -3,16 +3,16 @@
openapi: 3.0.3
info:
title: SuperMQ Groups Service
title: Magistrala Groups Service
description: |
This is the Groups Server based on the OpenAPI 3.0 specification. It is the HTTP API for managing platform groups. You can now help us improve the API whether it's by making changes to the definition itself or to the code.
Some useful links:
- [The SuperMQ repository](https://github.com/absmach/supermq)
- [The Magistrala repository](https://github.com/absmach/magistrala)
contact:
email: info@absmach.eu
license:
name: Apache 2.0
url: https://github.com/absmach/supermq/blob/main/LICENSE
url: https://github.com/absmach/magistrala/blob/main/LICENSE
version: 0.18.0
servers:
@@ -24,17 +24,17 @@ tags:
description: CRUD operations for your groups
externalDocs:
description: Find out more about users groups
url: https://docs.supermq.absmach.eu/
url: https://magistrala.absmach.eu/docs/
- name: Roles
description: All operations involving roles for groups
externalDocs:
description: Find out more about roles
url: https://docs.supermq.absmach.eu/
url: https://magistrala.absmach.eu/docs/
- name: Health
description: Health check operations
externalDocs:
description: Find out more about health checks
url: https://docs.supermq.absmach.eu/
url: https://magistrala.absmach.eu/docs/
paths:
/{domainID}/groups:
@@ -92,16 +92,19 @@ paths:
- $ref: "#/components/parameters/DirectionOrder"
- $ref: "#/components/parameters/Level"
- $ref: "#/components/parameters/Tree"
- $ref: "#/components/parameters/Tags"
- $ref: "#/components/parameters/Metadata"
- $ref: "#/components/parameters/GroupName"
- $ref: "#/components/parameters/RootGroup"
- $ref: "#/components/parameters/Status"
- $ref: "#/components/parameters/ID"
- $ref: "#/components/parameters/ID"
- $ref: "./schemas/roles.yaml#/components/parameters/ActionsQuery"
- $ref: "./schemas/roles.yaml#/components/parameters/RoleIDQuery"
- $ref: "./schemas/roles.yaml#/components/parameters/RoleNameQuery"
- $ref: "#/components/parameters/AccessType"
- $ref: "#/components/parameters/OnlyTotal"
- $ref: "#/components/parameters/OnlyTotal"
- $ref: "#/components/parameters/CreatedFrom"
- $ref: "#/components/parameters/CreatedTo"
responses:
"200":
$ref: "#/components/responses/GroupPageRes"
@@ -328,6 +331,8 @@ paths:
- $ref: "#/components/parameters/Level"
- $ref: "#/components/parameters/Tree"
- $ref: "#/components/parameters/Direction"
- $ref: "#/components/parameters/CreatedFrom"
- $ref: "#/components/parameters/CreatedTo"
responses:
"200":
$ref: "#/components/responses/GroupsHierarchyPageRes"
@@ -362,6 +367,11 @@ paths:
responses:
"200":
description: Parent group set.
content:
application/json:
schema:
type: object
links: {}
"400":
description: Failed due to malformed group's ID.
"401":
@@ -392,6 +402,11 @@ paths:
responses:
"200":
description: Parent group removed.
content:
application/json:
schema:
type: object
links: {}
"400":
description: Failed due to malformed group's ID.
"401":
@@ -1140,7 +1155,7 @@ components:
description: User's last name.
email:
type: string
example: user@supermq.com
example: user@magistrala.com
description: User's email address.
tags:
type: array
@@ -1377,16 +1392,12 @@ components:
Tags:
name: tags
description: User tags.
description: Group tags. Multiple tags can be specified separated by comma for OR condition and plus for AND condition.
in: query
schema:
type: array
minItems: 0
uniqueItems: true
items:
type: string
type: string
required: false
example: ["yello", "orange"]
example: "orange,yellow"
GroupName:
name: name
@@ -1513,7 +1524,6 @@ components:
in: query
schema:
type: string
minimum: 0
required: false
Limit:
@@ -1526,7 +1536,7 @@ components:
maximum: 100
minimum: 1
required: false
example: "100"
example: 100
Offset:
name: offset
@@ -1537,9 +1547,9 @@ components:
default: 0
minimum: 0
required: false
example: "0"
Order:
example: 0
Order:
name: order
description: Field by which to order the results
in: query
@@ -1547,8 +1557,8 @@ components:
type: string
required: false
example: created_at
DirectionOrder:
DirectionOrder:
name: order
description: Direction of ordering the results.
in: query
@@ -1560,7 +1570,7 @@ components:
required: false
example: desc
ID:
ID:
name: id
description: List groups with the given ID.
in: query
@@ -1569,7 +1579,7 @@ components:
format: uuid
required: false
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
AccessType:
name: access_type
description: Type of access the user has on the group.
@@ -1583,8 +1593,8 @@ components:
- indirect_group
required: false
example: direct
OnlyTotal:
OnlyTotal:
name: only_total
description: If true, the response will contain only the total number of groups that match the query parameters.
in: query
@@ -1592,7 +1602,27 @@ components:
type: boolean
default: false
required: false
CreatedFrom:
name: created_from
description: Filter groups created from this date (inclusive).
in: query
schema:
type: string
format: date-time
required: false
example: "2023-01-01T00:00:00Z"
CreatedTo:
name: created_to
description: Filter groups created up to this date (inclusive).
in: query
schema:
type: string
format: date-time
required: false
example: "2023-12-31T23:59:59Z"
User:
name: user
description: If provided lists groups associated with a user with the provided ID. Only available for admin users.
@@ -1663,10 +1693,10 @@ components:
operationId: getGroup
parameters:
groupID: $response.body#/id
get_children:
operationId: listChildrenGroups
parameters:
groupID: $response.body#/id
# get_children:
# operationId: listChildrenGroups
# parameters:
# groupID: $response.body#/id
update:
operationId: updateGroup
parameters:
@@ -1710,6 +1740,7 @@ components:
application/json:
schema:
$ref: "#/components/schemas/GroupsPage"
links: {}
GroupsHierarchyPageRes:
description: Group hierarchy retrieved.
@@ -1717,6 +1748,7 @@ components:
application/json:
schema:
$ref: "#/components/schemas/GroupsHierarchyPage"
links: {}
MembersPageRes:
description: Group members retrieved.
@@ -1724,6 +1756,7 @@ components:
application/json:
schema:
$ref: "#/components/schemas/MembersPage"
links: {}
HealthRes:
description: Service Health Check.
+4 -4
View File
@@ -3,16 +3,16 @@
openapi: 3.0.1
info:
title: SuperMQ http adapter
title: Magistrala http adapter
description: |
HTTP API for sending messages through communication channels.
Some useful links:
- [The SuperMQ repository](https://github.com/absmach/supermq)
- [The Magistrala repository](https://github.com/absmach/magistrala)
contact:
email: info@absmach.eu
license:
name: Apache 2.0
url: https://github.com/absmach/supermq/blob/main/LICENSE
url: https://github.com/absmach/magistrala/blob/main/LICENSE
version: 0.18.0
servers:
@@ -24,7 +24,7 @@ tags:
description: Everything about your Messages
externalDocs:
description: Find out more about messages
url: https://docs.supermq.absmach.eu/
url: https://magistrala.absmach.eu/docs/
paths:
/m/{domainPrefix}/c/{channelPrefix}:
-426
View File
@@ -1,426 +0,0 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
openapi: 3.0.3
info:
title: SuperMQ Journal Log Service
description: |
This is the Journal Log Server based on the OpenAPI 3.0 specification. It is the HTTP API for viewing journal log history. You can now help us improve the API whether it's by making changes to the definition itself or to the code.
Some useful links:
- [The SuperMQ repository](https://github.com/absmach/supermq)
contact:
email: info@mainflux.com
license:
name: Apache 2.0
url: https://github.com/absmach/supermq/blob/main/LICENSE
version: 0.18.0
servers:
- url: http://localhost:9021
- url: https://localhost:9021
tags:
- name: journal-log
description: Everything about your Journal Log
externalDocs:
description: Find out more about Journal Log
url: http://docs.mainflux.io/
paths:
/journal/user/{userID}:
get:
tags:
- journal-log
summary: List user journal log
description: |
Retrieves a list of journal. Due to performance concerns, data
is retrieved in subsets. The API must ensure that the entire
dataset is consumed either by making subsequent requests, or by
increasing the subset size of the initial request.
parameters:
- $ref: "#/components/parameters/user_id"
- $ref: "#/components/parameters/offset"
- $ref: "#/components/parameters/limit"
- $ref: "#/components/parameters/operation"
- $ref: "#/components/parameters/with_attributes"
- $ref: "#/components/parameters/with_metadata"
- $ref: "#/components/parameters/from"
- $ref: "#/components/parameters/to"
- $ref: "#/components/parameters/dir"
security:
- bearerAuth: []
responses:
"200":
$ref: "#/components/responses/JournalsPageRes"
"400":
description: Failed due to malformed query parameters.
"401":
description: Missing or invalid access token provided.
"403":
description: Failed to perform authorization over the entity.
"404":
description: A non-existent entity request.
"422":
description: Database can't process request.
"500":
$ref: "#/components/responses/ServiceError"
/{domainID}/journal/client/{clientID}/telemetry:
get:
tags:
- journal-log
summary: View client telemetry
description: |
Retrieves telemetry data for a specific client within a domain.
This includes connection status, messages sent/received, and other metrics.
parameters:
- $ref: "#/components/parameters/domain_id"
- $ref: '#/components/parameters/client_id'
security:
- bearerAuth: []
responses:
"200":
description: Client telemetry data retrieved successfully
content:
application/json:
schema:
$ref: "#/components/schemas/Telemetry"
"400":
description: Failed due to malformed request parameters.
"401":
description: Missing or invalid access token provided.
"403":
description: Failed to perform authorization over the entity.
"404":
description: Client not found.
"422":
description: Database can't process request.
"500":
$ref: "#/components/responses/ServiceError"
/{domainID}/journal/{entityType}/{id}:
get:
tags:
- journal-log
summary: List entity journal log
description: |
Retrieves a list of journal. Due to performance concerns, data
is retrieved in subsets. The API must ensure that the entire
dataset is consumed either by making subsequent requests, or by
increasing the subset size of the initial request.
parameters:
- $ref: "#/components/parameters/domain_id"
- $ref: "#/components/parameters/entity_type"
- $ref: "#/components/parameters/id"
- $ref: "#/components/parameters/offset"
- $ref: "#/components/parameters/limit"
- $ref: "#/components/parameters/operation"
- $ref: "#/components/parameters/with_attributes"
- $ref: "#/components/parameters/with_metadata"
- $ref: "#/components/parameters/from"
- $ref: "#/components/parameters/to"
- $ref: "#/components/parameters/dir"
security:
- bearerAuth: []
responses:
"200":
$ref: "#/components/responses/JournalsPageRes"
"400":
description: Failed due to malformed query parameters.
"401":
description: Missing or invalid access token provided.
"403":
description: Failed to perform authorization over the entity.
"404":
description: A non-existent entity request.
"422":
description: Database can't process request.
"500":
$ref: "#/components/responses/ServiceError"
/health:
get:
summary: Retrieves service health check info.
tags:
- health
security: []
responses:
"200":
$ref: "#/components/responses/HealthRes"
"500":
$ref: "#/components/responses/ServiceError"
components:
schemas:
Telemetry:
type: object
properties:
client_id:
type: string
format: uuid
description: Unique identifier of the client
example: "bb7edb32-2eac-4aad-aebe-ed96fe073879"
domain_id:
type: string
format: uuid
description: Unique identifier of the domain
example: "29d425c8-542b-4614-8a4d-a5951945d720"
subscriptions:
type: integer
format: int64
description: Number of active subscriptions for the client
example: 5
inbound_messages:
type: integer
format: int64
description: Number of messages received by the client
example: 1234567
outbound_messages:
type: integer
format: int64
description: Number of messages sent by the client
example: 987654
first_seen:
type: string
format: date-time
description: Timestamp when the client was first seen
example: "2024-01-11T10:00:00.000Z"
last_seen:
type: string
format: date-time
description: Timestamp when the client was last seen
example: "2024-01-11T12:05:07.449053Z"
Journal:
type: object
properties:
operation:
type: string
example: user.create
description: Journal operation.
occurred_at:
type: string
format: date-time
example: "2024-01-11T12:05:07.449053Z"
description: Time when the journal occurred.
attributes:
type: object
description: Journal attributes.
example:
{
"created_at": "2024-06-12T11:34:32.991591Z",
"id": "29d425c8-542b-4614-8a4d-a5951945d720",
"identity": "Gawne-Havlicek@email.com",
"name": "Newgard-Frisina",
"status": "enabled",
"updated_at": "2024-06-12T11:34:33.116795Z",
"updated_by": "ad228f20-4741-47c5-bef7-d871b541c019",
}
metadata:
type: object
description: Journal payload.
example: { "Update": "Calvo-Felkins" }
xml:
name: journal
JournalPage:
type: object
properties:
journals:
type: array
minItems: 0
uniqueItems: true
items:
$ref: "#/components/schemas/Journal"
total:
type: integer
example: 1
description: Total number of items.
offset:
type: integer
description: Number of items to skip during retrieval.
limit:
type: integer
example: 10
description: Maximum number of items to return in one page.
required:
- journals
- total
- offset
Error:
type: object
properties:
error:
type: string
description: Error message
example: { "error": "malformed entity specification" }
parameters:
domain_id:
name: domainID
description: Unique identifier for a domain.
in: path
schema:
type: string
format: uuid
required: true
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
client_id:
name: clientID
description: Unique identifier for a client
in: path
schema:
type: string
format: uuid
required: true
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
entity_type:
name: entityType
description: Type of entity, e.g. group, client, channel.
in: path
schema:
type: string
enum:
- group
- client
- channel
required: true
example: group
user_id:
name: userID
description: Unique identifier for a user.
in: path
schema:
type: string
format: uuid
required: true
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
id:
name: id
description: Unique identifier for an entity, e.g. group, channel or client. Used together with entity_type.
in: path
schema:
type: string
format: uuid
required: true
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
offset:
name: offset
description: Number of items to skip during retrieval.
in: query
schema:
type: integer
default: 0
minimum: 0
required: false
example: "0"
limit:
name: limit
description: Size of the subset to retrieve.
in: query
schema:
type: integer
default: 10
maximum: 10
minimum: 1
required: false
example: "10"
operation:
name: operation
description: Journal operation.
in: query
schema:
type: string
required: false
example: user.create
with_attributes:
name: with_attributes
description: Include journal attributes.
in: query
schema:
type: boolean
required: false
example: true
with_metadata:
name: with_metadata
description: Include journal metadata.
in: query
schema:
type: boolean
required: false
example: true
from:
name: from
description: Start date in unix time.
in: query
schema:
type: string
format: int64
required: false
example: 1966777289
to:
name: to
description: End date in unix time.
in: query
schema:
type: string
format: int64
required: false
example: 1966777289
dir:
name: dir
description: Sort direction.
in: query
schema:
type: string
enum:
- asc
- desc
required: false
example: desc
responses:
JournalsPageRes:
description: Data retrieved.
content:
application/json:
schema:
$ref: "#/components/schemas/JournalPage"
HealthRes:
description: Service Health Check.
content:
application/health+json:
schema:
$ref: "./schemas/health_info.yaml"
ServiceError:
description: Unexpected server-side error occurred.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: |
* User access: "Authorization: Bearer <user_access_token>"
security:
- bearerAuth: []
+292
View File
@@ -0,0 +1,292 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
openapi: 3.0.1
info:
title: Magistrala Notifiers service
description: |
HTTP API for Notifiers service.
Some useful links:
- [The Magistrala repository](https://github.com/absmach/magistrala)
contact:
email: info@absmach.eu
license:
name: Apache 2.0
url: https://github.com/absmach/magistrala/blob/main/LICENSE
version: 0.18.5
servers:
- url: http://localhost:9014
- url: https://localhost:9014
- url: http://localhost:9015
- url: https://localhost:9015
tags:
- name: notifiers
description: Everything about your Notifiers
externalDocs:
description: Find out more about notifiers
url: https://magistrala.absmach.eu/docs/
paths:
/subscriptions:
post:
operationId: createSubscription
summary: Create subscription
description: Creates a new subscription give a topic and contact.
tags:
- notifiers
requestBody:
$ref: "#/components/requestBodies/Create"
responses:
"201":
$ref: "#/components/responses/Create"
"400":
description: Failed due to malformed JSON.
"401":
description: Missing or invalid access token provided.
"403":
description: Failed to perform authorization over the entity.
"409":
description: Failed due to using an existing topic and contact.
"415":
description: Missing or invalid content type.
"422":
description: Database can't process request.
"500":
$ref: "#/components/responses/ServiceError"
get:
operationId: listSubscriptions
summary: List subscriptions
description: List subscriptions given list parameters.
tags:
- notifiers
parameters:
- $ref: "#/components/parameters/Topic"
- $ref: "#/components/parameters/Contact"
- $ref: "#/components/parameters/Offset"
- $ref: "#/components/parameters/Limit"
responses:
"200":
$ref: "#/components/responses/Page"
"400":
description: Failed due to malformed query parameters.
"401":
description: Missing or invalid access token provided.
"403":
description: Failed to perform authorization over the entity.
"404":
description: A non-existent entity request.
"422":
description: Database can't process request.
"500":
$ref: "#/components/responses/ServiceError"
/subscriptions/{id}:
get:
operationId: viewSubscription
summary: Get subscription with the provided id
description: Retrieves a subscription with the provided id.
tags:
- notifiers
parameters:
- $ref: "#/components/parameters/Id"
responses:
"200":
$ref: "#/components/responses/View"
"400":
description: Failed due to malformed ID.
"401":
description: Missing or invalid access token provided.
"403":
description: Failed to perform authorization over the entity.
"404":
description: A non-existent entity request.
"422":
description: Database can't process request.
"500":
$ref: "#/components/responses/ServiceError"
delete:
operationId: removeSubscription
summary: Delete subscription with the provided id
description: Removes a subscription with the provided id.
tags:
- notifiers
parameters:
- $ref: "#/components/parameters/Id"
responses:
"204":
description: Subscription removed
"401":
description: Missing or invalid access token provided.
"403":
description: Failed to perform authorization over the entity.
"404":
description: A non-existent entity request.
"422":
description: Database can't process request.
"500":
$ref: "#/components/responses/ServiceError"
/health:
get:
summary: Retrieves service health check info.
tags:
- health
security: []
responses:
"200":
$ref: "#/components/responses/HealthRes"
"500":
$ref: "#/components/responses/ServiceError"
components:
schemas:
Subscription:
type: object
properties:
id:
type: string
format: ulid
example: 01EWDVKBQSG80B6PQRS9PAAY35
description: ULID id of the subscription.
owner_id:
type: string
format: uuid
example: 18167738-f7a8-4e96-a123-58c3cd14de3a
description: An id of the owner who created subscription.
topic:
type: string
example: topic/subtopic
description: Topic to which the user subscribes.
contact:
type: string
example: user@example.com
description: The contact of the user to which the notification will be sent.
CreateSubscription:
type: object
properties:
topic:
type: string
example: topic/subtopic
description: Topic to which the user subscribes.
contact:
type: string
example: user@example.com
description: The contact of the user to which the notification will be sent.
Page:
type: object
properties:
subscriptions:
type: array
minItems: 0
uniqueItems: true
items:
$ref: "#/components/schemas/Subscription"
total:
type: integer
description: Total number of items.
offset:
type: integer
description: Number of items to skip during retrieval.
limit:
type: integer
description: Maximum number of items to return in one page.
parameters:
Id:
name: id
description: Unique identifier.
in: path
schema:
type: string
format: ulid
required: true
Limit:
name: limit
description: Size of the subset to retrieve.
in: query
schema:
type: integer
default: 10
maximum: 100
minimum: 1
required: false
Offset:
name: offset
description: Number of items to skip during retrieval.
in: query
schema:
type: integer
default: 0
minimum: 0
required: false
Topic:
name: topic
description: Topic name.
in: query
schema:
type: string
required: false
Contact:
name: contact
description: Subscription contact.
in: query
schema:
type: string
required: false
requestBodies:
Create:
description: JSON-formatted document describing the new subscription to be created
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateSubscription"
responses:
Create:
description: Created a new subscription.
headers:
Location:
content:
text/plain:
schema:
type: string
description: Created subscription relative URL
example: /subscriptions/{id}
View:
description: View subscription.
content:
application/json:
schema:
$ref: "#/components/schemas/Subscription"
links:
delete:
operationId: removeSubscription
parameters:
id: $response.body#/id
Page:
description: Data retrieved.
content:
application/json:
schema:
$ref: "#/components/schemas/Page"
ServiceError:
description: Unexpected server-side error occurred.
HealthRes:
description: Service Health Check.
content:
application/health+json:
schema:
$ref: "./schemas/health_info.yaml"
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: |
* Users access: "Authorization: Bearer <user_token>"
security:
- bearerAuth: []
+314
View File
@@ -0,0 +1,314 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
openapi: 3.0.1
info:
title: Magistrala reader service
description: |
HTTP API for reading messages.
Some useful links:
- [The Magistrala repository](https://github.com/absmach/magistrala)
contact:
email: info@absmach.eu
license:
name: Apache 2.0
url: https://github.com/absmach/magistrala/blob/main/LICENSE
version: 0.18.5
servers:
- url: http://localhost:9003
- url: https://localhost:9003
- url: http://localhost:9005
- url: https://localhost:9005
- url: http://localhost:9009
- url: https://localhost:9009
- url: http://localhost:9011
- url: https://localhost:9011
tags:
- name: readers
description: Everything about your Readers
externalDocs:
description: Find out more about readers
url: https://magistrala.absmach.eu/docs/
paths:
/{domainID}/channels/{chanId}/messages:
get:
operationId: getMessages
summary: Retrieves messages sent to single channel
description: |
Retrieves a list of messages sent to specific channel. Due to
performance concerns, data is retrieved in subsets. The API readers must
ensure that the entire dataset is consumed either by making subsequent
requests, or by increasing the subset size of the initial request.
tags:
- readers
parameters:
- $ref: "#/components/parameters/DomainID"
- $ref: "#/components/parameters/ChanId"
- $ref: "#/components/parameters/Limit"
- $ref: "#/components/parameters/Offset"
- $ref: "#/components/parameters/Publisher"
- $ref: "#/components/parameters/Name"
- $ref: "#/components/parameters/Value"
- $ref: "#/components/parameters/BoolValue"
- $ref: "#/components/parameters/StringValue"
- $ref: "#/components/parameters/DataValue"
- $ref: "#/components/parameters/From"
- $ref: "#/components/parameters/To"
- $ref: "#/components/parameters/Aggregation"
- $ref: "#/components/parameters/Interval"
responses:
"200":
$ref: "#/components/responses/MessagesPageRes"
"400":
description: Failed due to malformed query parameters.
"401":
description: Missing or invalid access token provided.
"403":
description: Failed to perform authorization over the entity.
"500":
$ref: "#/components/responses/ServiceError"
/health:
get:
operationId: health
summary: Retrieves service health check info.
tags:
- health
security: []
responses:
"200":
$ref: "#/components/responses/HealthRes"
"500":
$ref: "#/components/responses/ServiceError"
components:
schemas:
MessagesPage:
type: object
properties:
total:
type: number
description: Total number of items that are present on the system.
offset:
type: number
description: Number of items that were skipped during retrieval.
limit:
type: number
description: Size of the subset that was retrieved.
messages:
type: array
minItems: 0
uniqueItems: true
items:
type: object
properties:
channel:
type: integer
description: Unique channel id.
publisher:
type: integer
description: Unique publisher id.
protocol:
type: string
description: Protocol name.
name:
type: string
description: Measured parameter name.
unit:
type: string
description: Value unit.
value:
type: number
description: Measured value in number.
stringValue:
type: string
description: Measured value in string format.
boolValue:
type: boolean
description: Measured value in boolean format.
dataValue:
type: string
description: Measured value in binary format.
valueSum:
type: number
description: Sum value.
time:
type: number
description: Time of measurement.
updateTime:
type: number
description: Time of updating measurement.
parameters:
DomainID:
name: domainID
description: Unique domain identifier.
in: path
schema:
type: string
format: uuid
required: true
ChanId:
name: chanId
description: Unique channel identifier.
in: path
schema:
type: string
format: uuid
required: true
Limit:
name: limit
description: Size of the subset to retrieve.
in: query
schema:
type: integer
default: 10
maximum: 100
minimum: 1
required: false
Offset:
name: offset
description: Number of items to skip during retrieval.
in: query
schema:
type: integer
default: 0
minimum: 0
required: false
Publisher:
name: Publisher
description: Unique thing identifier.
in: query
schema:
type: string
format: uuid
required: false
Name:
name: name
description: SenML message name.
in: query
schema:
type: string
required: false
Value:
name: v
description: SenML message value.
in: query
schema:
type: string
required: false
BoolValue:
name: vb
description: SenML message bool value.
in: query
schema:
type: boolean
required: false
StringValue:
name: vs
description: SenML message string value.
in: query
schema:
type: string
required: false
DataValue:
name: vd
description: SenML message data value.
in: query
schema:
type: string
required: false
Comparator:
name: comparator
description: Value comparison operator.
in: query
schema:
type: string
default: eq
enum:
- eq
- lt
- le
- gt
- ge
required: false
From:
name: from
description: SenML message time in nanoseconds (integer part represents seconds).
in: query
schema:
type: number
example: 1709218556069
required: false
To:
name: to
description: SenML message time in nanoseconds (integer part represents seconds).
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:
MessagesPageRes:
description: Data retrieved.
content:
application/json:
schema:
$ref: "#/components/schemas/MessagesPage"
ServiceError:
description: Unexpected server-side error occurred.
HealthRes:
description: Service Health Check.
content:
application/health+json:
schema:
$ref: "./schemas/health_info.yaml"
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: |
* Users access: "Authorization: Bearer <user_token>"
thingAuth:
type: http
scheme: bearer
bearerFormat: uuid
description: |
* Things access: "Authorization: Thing <thing_key>"
security:
- bearerAuth: []
- thingAuth: []
+553
View File
@@ -0,0 +1,553 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
openapi: 3.0.1
info:
title: Magistrala Reports Service API
description: |
HTTP API for managing reports service.
version: 0.18.5
servers:
- url: http://localhost:9017
tags:
- name: reports
description: Operations related to report configurations and generation
paths:
/{domainID}/reports:
post:
operationId: generateReport
summary: Generate a report
description: Generates a report based on the provided configuration or an existing config. The action determines the response format.
tags:
- reports
parameters:
- $ref: '#/components/parameters/DomainID'
security:
- bearerAuth: []
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/GenerateReportRequest'
responses:
'200':
description: Report generated successfully (content varies by action)
content:
application/json:
schema:
$ref: '#/components/schemas/GenerateReportResponse'
application/octet-stream:
schema:
type: string
format: binary
'400':
description: Invalid request parameters
'401':
description: Missing or invalid access token
'500':
$ref: '#/components/responses/ServiceError'
/{domainID}/reports/configs:
post:
operationId: addReportConfig
summary: Create a report configuration
description: Creates a new report configuration.
tags:
- reports
parameters:
- $ref: '#/components/parameters/DomainID'
security:
- bearerAuth: []
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/AddReportConfigRequest'
responses:
'201':
description: Report configuration created
headers:
Location:
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/ReportConfig'
'400':
description: Invalid request body
'401':
description: Missing or invalid access token
'500':
$ref: '#/components/responses/ServiceError'
get:
operationId: listReportConfigs
summary: List report configurations
description: Retrieves a paginated list of report configurations.
tags:
- reports
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/Offset'
- $ref: '#/components/parameters/Limit'
security:
- bearerAuth: []
responses:
'200':
description: List of report configurations
content:
application/json:
schema:
$ref: '#/components/schemas/ListReportsConfigResponse'
'400':
description: Invalid query parameters
'401':
description: Missing or invalid access token
'500':
$ref: '#/components/responses/ServiceError'
/{domainID}/reports/configs/{reportID}:
get:
operationId: viewReportConfig
summary: View a report configuration
description: Retrieves details of a specific report configuration.
tags:
- reports
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/ReportID'
security:
- bearerAuth: []
responses:
'200':
description: Report configuration details
content:
application/json:
schema:
$ref: '#/components/schemas/ReportConfig'
'404':
description: Report configuration not found
'401':
description: Missing or invalid access token
'500':
$ref: '#/components/responses/ServiceError'
patch:
operationId: updateReportConfig
summary: Update a report configuration
description: Updates specified fields of a report configuration.
tags:
- reports
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/ReportID'
security:
- bearerAuth: []
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateReportConfigRequest'
responses:
'200':
description: Report configuration updated
content:
application/json:
schema:
$ref: '#/components/schemas/ReportConfig'
'400':
description: Invalid request body
'401':
description: Missing or invalid access token
'404':
description: Report configuration not found
'500':
$ref: '#/components/responses/ServiceError'
delete:
operationId: deleteReportConfig
summary: Delete a report configuration
description: Permanently deletes a report configuration.
tags:
- reports
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/ReportID'
security:
- bearerAuth: []
responses:
'204':
description: Report configuration deleted
'401':
description: Missing or invalid access token
'404':
description: Report configuration not found
'500':
$ref: '#/components/responses/ServiceError'
/{domainID}/reports/configs/{reportID}/schedule:
patch:
operationId: updateReportSchedule
summary: Update report schedule
description: Updates the schedule of a report configuration.
tags:
- reports
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/ReportID'
security:
- bearerAuth: []
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/Schedule'
responses:
'200':
description: Schedule updated
content:
application/json:
schema:
$ref: '#/components/schemas/ReportConfig'
'400':
description: Invalid schedule
'401':
description: Missing or invalid access token
'404':
description: Report configuration not found
'500':
$ref: '#/components/responses/ServiceError'
/{domainID}/reports/configs/{reportID}/enable:
post:
operationId: enableReportConfig
summary: Enable a report configuration
description: Enables a report configuration to generate scheduled reports.
tags:
- reports
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/ReportID'
security:
- bearerAuth: []
responses:
'200':
description: Report configuration enabled
content:
application/json:
schema:
$ref: '#/components/schemas/ReportConfig'
'401':
description: Missing or invalid access token
'404':
description: Report configuration not found
'500':
$ref: '#/components/responses/ServiceError'
/{domainID}/reports/configs/{reportID}/disable:
post:
operationId: disableReportConfig
summary: Disable a report configuration
description: Disables a report configuration, stopping scheduled reports.
tags:
- reports
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/ReportID'
security:
- bearerAuth: []
responses:
'200':
description: Report configuration disabled
content:
application/json:
schema:
$ref: '#/components/schemas/ReportConfig'
'401':
description: Missing or invalid access token
'404':
description: Report configuration not found
'500':
$ref: '#/components/responses/ServiceError'
/health:
get:
summary: Service health check
tags:
- health
responses:
'200':
$ref: '#/components/responses/HealthRes'
components:
schemas:
ReportConfig:
type: object
properties:
id:
type: string
readOnly: true
name:
type: string
description:
type: string
domain_id:
type: string
readOnly: true
schedule:
$ref: '#/components/schemas/Schedule'
config:
$ref: '#/components/schemas/MetricConfig'
email:
$ref: '#/components/schemas/EmailSetting'
metrics:
type: array
items:
$ref: '#/components/schemas/ReqMetric'
status:
$ref: '#/components/schemas/Status'
created_at:
type: string
format: date-time
readOnly: true
created_by:
type: string
readOnly: true
updated_at:
type: string
format: date-time
readOnly: true
updated_by:
type: string
readOnly: true
required:
- name
- metrics
- config
Schedule:
type: object
properties:
recurring:
type: string
enum: [None, Daily, Weekly, Monthly]
recurring_period:
type: integer
minimum: 1
start_time:
type: string
format: date-time
next_run:
type: string
format: date-time
readOnly: true
MetricConfig:
type: object
properties:
title:
type: string
maxLength: 100
format:
type: string
enum: [pdf, csv, html]
aggregation:
$ref: '#/components/schemas/AggConfig'
AggConfig:
type: object
properties:
window:
type: string
function:
type: string
enum: [sum, average, max, min]
EmailSetting:
type: object
properties:
recipients:
type: array
items:
type: string
format: email
subject:
type: string
body_template:
type: string
required:
- recipients
- subject
ReqMetric:
type: object
properties:
name:
type: string
type:
type: string
enum: [gauge, counter, histogram]
parameters:
type: object
required:
- name
- type
Status:
type: string
enum: [enabled, disabled]
GenerateReportRequest:
type: object
properties:
action:
type: string
enum: [view, download, email]
config_id:
type: string
name:
type: string
description:
type: string
schedule:
$ref: '#/components/schemas/Schedule'
config:
$ref: '#/components/schemas/MetricConfig'
email:
$ref: '#/components/schemas/EmailSetting'
metrics:
type: array
items:
$ref: '#/components/schemas/ReqMetric'
required:
- action
GenerateReportResponse:
type: object
properties:
total:
type: integer
from:
type: string
format: date-time
to:
type: string
format: date-time
aggregation:
$ref: '#/components/schemas/AggConfig'
reports:
type: array
items:
$ref: '#/components/schemas/Report'
Report:
type: object
properties:
timestamp:
type: string
format: date-time
value:
type: number
metric_name:
type: string
AddReportConfigRequest:
type: object
properties:
name:
type: string
description:
type: string
schedule:
$ref: '#/components/schemas/Schedule'
config:
$ref: '#/components/schemas/MetricConfig'
email:
$ref: '#/components/schemas/EmailSetting'
metrics:
type: array
items:
$ref: '#/components/schemas/ReqMetric'
status:
$ref: '#/components/schemas/Status'
required:
- name
- metrics
- config
UpdateReportConfigRequest:
type: object
properties:
name:
type: string
description:
type: string
schedule:
$ref: '#/components/schemas/Schedule'
config:
$ref: '#/components/schemas/MetricConfig'
email:
$ref: '#/components/schemas/EmailSetting'
metrics:
type: array
items:
$ref: '#/components/schemas/ReqMetric'
status:
$ref: '#/components/schemas/Status'
ListReportsConfigResponse:
type: object
properties:
total:
type: integer
offset:
type: integer
limit:
type: integer
report_configs:
type: array
items:
$ref: '#/components/schemas/ReportConfig'
parameters:
DomainID:
name: domainID
in: path
required: true
schema:
type: string
ReportID:
name: reportID
in: path
required: true
schema:
type: string
Offset:
name: offset
in: query
schema:
type: integer
default: 0
minimum: 0
Limit:
name: limit
in: query
schema:
type: integer
default: 10
minimum: 1
maximum: 100
responses:
ServiceError:
description: Unexpected server error
HealthRes:
description: Service Health Check.
content:
application/health+json:
schema:
$ref: './schemas/health_info.yaml'
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
+586
View File
@@ -0,0 +1,586 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
openapi: 3.0.1
info:
title: Magistrala Rules Engine API
description: |
HTTP API for managing rules engine service.
Some useful links:
- [The Magistrala repository](https://github.com/absmach/magistrala)
contact:
email: info@absmach.eu
license:
name: Apache 2.0
url: https://github.com/absmach/magistrala/blob/main/LICENSE
version: 0.18.5
servers:
- url: http://localhost:9008
- url: http://localhost:9008
tags:
- name: rules engine
description: Everything about your Rules Engine
externalDocs:
description: Find out more about rules engine
url: https://magistrala.absmach.eu/docs/
paths:
/{domainID}/rules:
post:
operationId: createRule
summary: Create Rule
description: |
Creates a new rule for message processing
tags:
- rules
parameters:
- $ref: '#/components/parameters/DomainID'
security:
- bearerAuth: []
requestBody:
$ref: '#/components/requestBodies/RuleCreateReq'
responses:
'201':
$ref: '#/components/responses/RuleCreateRes'
'400':
description: Failed due to malformed JSON
'401':
description: Missing or invalid access token
'415':
description: Missing or invalid content type
"500":
$ref: "#/components/responses/ServiceError"
"503":
description: Failed to receive response from the clients service.
get:
operationId: getRules
summary: List Rules
description: |
Retrieves a list of rules with optional filtering
tags:
- rules
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/Offset'
- $ref: '#/components/parameters/Limit'
- $ref: '#/components/parameters/InputChannel'
- $ref: '#/components/parameters/OutputChannel'
- $ref: '#/components/parameters/Status'
security:
- bearerAuth: []
responses:
'200':
$ref: '#/components/responses/RuleListRes'
'400':
description: Failed due to malformed query parameters
'401':
description: Missing or invalid access token
"422":
description: Database can't process request.
"500":
$ref: "#/components/responses/ServiceError"
/{domainID}/rules/{ruleID}:
get:
operationId: getRule
summary: View Rule
description: Retrieves a rule by ID
tags:
- rules
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/RuleID'
security:
- bearerAuth: []
responses:
'200':
$ref: '#/components/responses/RuleRes'
"400":
description: Missing or invalid rule
"403":
description: Failed to perform authorization over the entity
'401':
description: Missing or invalid access token
'404':
description: Rule does not exist
"422":
description: Database can't process request
"500":
$ref: "#/components/responses/ServiceError"
put:
operationId: updateRule
summary: Update Rule
description: Updates an existing rule
tags:
- rules
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/RuleID'
security:
- bearerAuth: []
requestBody:
$ref: '#/components/requestBodies/RuleUpdateReq'
responses:
'200':
$ref: '#/components/responses/RuleRes'
'400':
description: Failed due to malformed JSON
'401':
description: Missing or invalid access token
'404':
description: Rule does not exist
"415":
description: Missing or invalid content type.
"422":
description: Database can't process request.
"500":
$ref: "#/components/responses/ServiceError"
delete:
operationId: removeRule
summary: Delete Rule
description: Deletes a rule
tags:
- rules
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/RuleID'
security:
- bearerAuth: []
responses:
'204':
description: Rule deleted successfully
"400":
description: Failed due to malformed rule ID
'401':
description: Missing or invalid access token
"403":
description: Failed to perform authorization over the entity
"422":
description: Database can't process request
"500":
$ref: "#/components/responses/ServiceError"
/{domainID}/rules/{ruleID}/enable:
put:
operationId: enableRule
summary: Enable Rule
description: Enables a rule for processing
tags:
- rules
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/RuleID'
security:
- bearerAuth: []
responses:
'200':
description: Rule enabled successfully
"400":
description: Failed due to malformed JSON
'401':
description: Missing or invalid access token
"403":
description: Failed to perform authorization over the entity
'404':
description: Rule does not exist
"422":
description: Database can't process request.
"500":
$ref: "#/components/responses/ServiceError"
/{domainID}/rules/{ruleID}/disable:
put:
operationId: disableRule
summary: Disable Rule
description: Disables a rule from processing
tags:
- Rules
parameters:
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/RuleID'
security:
- bearerAuth: []
responses:
'200':
description: Rule disabled successfully
"400":
description: Failed due to malformed JSON
'401':
description: Missing or invalid access token
"403":
description: Failed to perform authorization over the entity
'404':
description: Rule does not exist
"422":
description: Database can't process request
"500":
$ref: "#/components/responses/ServiceError"
/health:
get:
summary: Retrieves service health check info.
tags:
- health
security: []
responses:
"200":
$ref: "#/components/responses/HealthRes"
"500":
$ref: "#/components/responses/ServiceError"
components:
schemas:
RulesListRes:
type: object
properties:
total:
type: integer
description: Total number of results
minimum: 0
offset:
type: integer
description: Number of items to skip during retrieval
minimum: 0
default: 0
limit:
type: integer
description: Size of the subset to retrieve
maximum: 100
default: 10
rules:
type: array
minItems: 0
uniqueItems: true
items:
$ref: '#/components/schemas/Rule'
required:
- rules
Rule:
type: object
properties:
id:
type: string
description: Unique rule identifier
name:
type: string
description: Rule name
domain:
type: string
description: Domain ID this rule belongs to
metadata:
type: object
description: Custom metadata
additionalProperties:
type: string
input_channel:
type: string
description: Input channel for receiving messages
input_topic:
type: string
description: Input topic for receiving messages
logic:
type: object
description: Rule processing logic script
properties:
script:
type: string
description: Script content
output_channel:
type: string
description: Output channel for processed messages
output_topic:
type: string
description: Output topic for processed messages
schedule:
type: object
description: Rule execution schedule
properties:
start_datetime:
type: string
format: date-time
description: When the schedule becomes active
time:
type: string
format: date-time
description: Specific time for the rule to run
recurring:
type: string
description: Schedule recurrence pattern
enum: [None, Daily, Weekly, Monthly]
recurring_period:
type: integer
minimum: 1
description: Controls how many intervals to skip between executions (1 = every interval, 2 = every second interval, etc.)
status:
type: string
description: Rule status
enum: [enabled, disabled]
created_at:
type: string
format: date-time
description: Creation timestamp
readOnly: true
created_by:
type: string
description: User who created the rule
updated_at:
type: string
format: date-time
description: Last update timestamp
readOnly: true
updated_by:
type: string
description: User who last updated the rule
required:
- name
- domain
- input_channel
- input_topic
- logic
- status
parameters:
DomainID:
name: domainID
description: Domain ID
in: path
required: true
schema:
type: string
RuleID:
name: ruleID
description: Rule ID
in: path
required: true
schema:
type: string
Offset:
name: offset
description: Number of items to skip
in: query
required: false
schema:
type: integer
default: 0
minimum: 0
Limit:
name: limit
description: Size of the subset
in: query
required: false
schema:
type: integer
default: 10
minimum: 1
InputChannel:
name: input_channel
description: Filter by input channel
in: query
required: false
schema:
type: string
OutputChannel:
name: output_channel
description: Filter by output channel
in: query
required: false
schema:
type: string
Status:
name: status
description: Filter by rule status
in: query
required: false
schema:
type: string
enum: [enabled, disabled]
default: enabled
requestBodies:
RuleCreateReq:
description: JSON-formatted document describing the new rule
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: Rule name
domain:
type: string
description: Domain ID this rule belongs to
metadata:
type: object
description: Custom metadata
additionalProperties:
type: string
input_channel:
type: string
description: Input channel for receiving messages
input_topic:
type: string
description: Input topic for receiving messages
logic:
type: object
description: Rule processing logic script
properties:
script:
type: string
description: Script content
output_channel:
type: string
description: Output channel for processed messages
output_topic:
type: string
description: Output topic for processed messages
schedule:
type: object
description: Rule execution schedule
properties:
start_datetime:
type: string
format: date-time
description: When the schedule becomes active
time:
type: string
format: date-time
description: Specific time for the rule to run
recurring:
type: string
description: Schedule recurrence pattern
enum: [None, Daily, Weekly, Monthly]
recurring_period:
type: integer
minimum: 1
description: Controls how many intervals to skip between executions
status:
type: string
description: Rule status
enum: [enabled, disabled]
required:
- name
- domain
- input_channel
- input_topic
- logic
- schedule
RuleUpdateReq:
description: JSON-formatted document describing the rule update
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: Rule name
metadata:
type: object
description: Custom metadata
additionalProperties:
type: string
input_channel:
type: string
description: Input channel for receiving messages
input_topic:
type: string
description: Input topic for receiving messages
logic:
type: object
description: Rule processing logic script
properties:
script:
type: string
description: Script content
output_channel:
type: string
description: Output channel for processed messages
output_topic:
type: string
description: Output topic for processed messages
schedule:
type: object
description: Rule execution schedule
properties:
start_datetime:
type: string
format: date-time
description: When the schedule becomes active
time:
type: string
format: date-time
description: Specific time for the rule to run
recurring:
type: string
description: Schedule recurrence pattern
enum: [None, Daily, Weekly, Monthly]
recurring_period:
type: integer
minimum: 1
description: Controls how many intervals to skip between executions
status:
type: string
description: Rule status
enum: [enabled, disabled]
responses:
RuleCreateRes:
description: Rule registered
headers:
Location:
content:
text/plain:
schema:
type: string
description: Created rule's relative URL (i.e. /rules/{ruleID})
RuleListRes:
description: Data retrieved
content:
application/json:
schema:
$ref: '#/components/schemas/RulesListRes'
RuleRes:
description: Data retrieved
content:
application/json:
schema:
$ref: '#/components/schemas/Rule'
links:
update:
operationId: updateRule
parameters:
ruleID: $response.body#/id
enable:
operationId: enableRule
parameters:
ruleID: $response.body#/id
disable:
operationId: disableRule
parameters:
ruleID: $response.body#/id
delete:
operationId: removeRule
parameters:
ruleID: $response.body#/id
ServiceError:
description: Unexpected server-side error occurred
HealthRes:
description: Service Health Check
content:
application/health+json:
schema:
$ref: "./schemas/health_info.yaml"
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: |
* Users access: "Authorization: Bearer <user_token>"
+174 -40
View File
@@ -3,16 +3,16 @@
openapi: 3.0.3
info:
title: SuperMQ Users Service
title: Magistrala Users Service
description: |
This is the Users Server based on the OpenAPI 3.0 specification. It is the HTTP API for managing platform users. You can now help us improve the API whether it's by making changes to the definition itself or to the code.
Some useful links:
- [The SuperMQ repository](https://github.com/absmach/supermq)
- [The Magistrala repository](https://github.com/absmach/magistrala)
contact:
email: info@absmach.eu
license:
name: Apache 2.0
url: https://github.com/absmach/supermq/blob/main/LICENSE
url: https://github.com/absmach/magistrala/blob/main/LICENSE
version: 0.18.0
servers:
@@ -24,12 +24,12 @@ tags:
description: Everything about your Users
externalDocs:
description: Find out more about users
url: https://docs.supermq.absmach.eu/
url: https://magistrala.absmach.eu/docs/
- name: Health
description: Health check operations
externalDocs:
description: Find out more about health checks
url: https://docs.supermq.absmach.eu/
url: https://magistrala.absmach.eu/docs/
paths:
/users:
@@ -83,8 +83,10 @@ paths:
- $ref: "#/components/parameters/LastName"
- $ref: "#/components/parameters/Username"
- $ref: "#/components/parameters/Email"
- $ref: "#/components/parameters/Tag"
- $ref: "#/components/parameters/Tags"
- $ref: "#/components/parameters/OnlyTotal"
- $ref: "#/components/parameters/CreatedFrom"
- $ref: "#/components/parameters/CreatedTo"
security:
- bearerAuth: []
responses:
@@ -116,7 +118,7 @@ paths:
- bearerAuth: []
responses:
"200":
$ref: "#/components/responses/UserRes"
$ref: "#/components/responses/UserProfileRes"
"400":
description: Failed due to malformed query parameters.
"401":
@@ -154,10 +156,10 @@ paths:
patch:
operationId: updateUser
summary: Updates first, last name and metadata of the user.
summary: Updates first, last name, metadata, and private metadata of the user.
description: |
Updates name and metadata of the user with provided ID. Name and metadata
is updated using authorization token and the new received info.
Updates name, metadata and private metadata of the user with provided ID. Name, metadata
and private metadata are updated using authorization token and the new received info.
tags:
- Users
parameters:
@@ -461,7 +463,7 @@ paths:
- bearerAuth: []
responses:
"200":
$ref: "#/components/responses/UserRes"
$ref: "#/components/responses/UserProfileRes"
"400":
description: Failed due to malformed JSON.
"401":
@@ -569,7 +571,7 @@ paths:
requestBody:
$ref: "#/components/requestBodies/IssueTokenReq"
responses:
"200":
"201":
$ref: "#/components/responses/TokenRes"
"400":
description: Failed due to malformed JSON.
@@ -610,6 +612,57 @@ paths:
"500":
$ref: "#/components/responses/ServiceError"
/users/tokens/revoke:
post:
operationId: revokeRefreshToken
summary: Revoke Refresh Token
description: |
Revokes a specific refresh token by its ID. This invalidates the
refresh token so it can no longer be used to obtain new access tokens.
tags:
- Users
security:
- bearerAuth: []
requestBody:
$ref: "#/components/requestBodies/RevokeRefreshTokenReq"
responses:
"204":
description: Refresh token revoked successfully.
"400":
description: Failed due to malformed JSON.
"401":
description: Missing or invalid access token provided.
"404":
description: A non-existent entity request.
"415":
description: Missing or invalid content type.
"422":
description: Database can't process request.
"500":
$ref: "#/components/responses/ServiceError"
/users/tokens/refresh-tokens:
get:
operationId: listActiveRefreshTokens
summary: List Active Refresh Tokens
description: |
Lists all active refresh token sessions for the currently authenticated user.
tags:
- Users
security:
- bearerAuth: []
responses:
"200":
$ref: "#/components/responses/RefreshTokensPageRes"
"400":
description: Failed due to malformed JSON.
"401":
description: Missing or invalid access token provided.
"404":
description: A non-existent entity request.
"500":
$ref: "#/components/responses/ServiceError"
/users/send-verification:
post:
operationId: sendVerification
@@ -706,7 +759,7 @@ components:
type: string
format: password
example: password
minimum: 8
minLength: 8
description: Free-form account secret used for acquiring auth token(s).
required:
- username
@@ -714,7 +767,11 @@ components:
metadata:
type: object
example: { "domain": "example.com" }
description: Arbitrary, object-encoded user's data.
description: Arbitrary, object-encoded user's data visible to other users.
private_metadata:
type: object
example: { "domain": "example.com" }
description: Arbitrary, object-encoded user's data private to the user.
profile_picture:
type: string
example: "https://example.com/profile.jpg"
@@ -758,7 +815,7 @@ components:
description: User tags.
email:
type: string
example: "john.doe@supermq.com"
example: "john.doe@magistrala.com"
description: User email for example email address.
credentials:
type: object
@@ -770,7 +827,11 @@ components:
metadata:
type: object
example: { "address": "example" }
description: Arbitrary, object-encoded user's data.
description: Arbitrary, object-encoded user's data visible to other users.
private_metadata:
type: object
example: { "address": "example" }
description: Arbitrary, object-encoded user's data private to the user.
profile_picture:
type: string
example: "https://example.com/profile.jpg"
@@ -811,7 +872,7 @@ components:
description: User's last name.
email:
type: string
example: user@supermq.com
example: user@magistrala.com
description: User's email address.
tags:
type: array
@@ -830,12 +891,12 @@ components:
secret:
type: string
example: password
minimum: 8
minLength: 8
description: User secret password.
metadata:
type: object
example: { "role": "general" }
description: Arbitrary, object-encoded user's data.
description: Arbitrary, object-encoded user's data visible to other users.
status:
type: string
description: User Status
@@ -894,11 +955,11 @@ components:
metadata:
type: object
example: { "role": "general" }
description: Arbitrary, object-encoded user's data.
required:
- first_name
- last_name
- metadata
description: Arbitrary, object-encoded user's data visible to other users.
private_metadata:
type: object
example: { "role": "general" }
description: Arbitrary, object-encoded user's data private to the user.
UserTags:
type: object
@@ -908,7 +969,6 @@ components:
example: ["yello", "orange"]
description: User tags.
minItems: 0
uniqueItems: true
items:
type: string
@@ -927,7 +987,7 @@ components:
properties:
email:
type: string
example: user@supermq.com
example: user@magistrala.com
description: User email address.
required:
- email
@@ -938,12 +998,12 @@ components:
old_secret:
type: string
example: oldpassword
minimum: 8
minLength: 8
description: Old user secret password.
new_secret:
type: string
example: newpassword
minimum: 8
minLength: 8
description: New user secret password.
required:
- old_secret
@@ -1029,12 +1089,36 @@ components:
password:
type: string
example: password
minimum: 8
minLength: 8
description: User secret password.
required:
- username
- password
RefreshToken:
type: object
properties:
id:
type: string
format: uuid
example: "bb7edb32-2eac-4aad-aebe-ed96fe073879"
description: Unique identifier of the refresh token.
description:
type: string
example: "Chrome browser session"
description: Description of the refresh token session.
RefreshTokensPage:
type: object
properties:
refresh_tokens:
type: array
items:
$ref: "#/components/schemas/RefreshToken"
description: List of active refresh tokens.
required:
- refresh_tokens
Error:
type: object
properties:
@@ -1138,14 +1222,14 @@ components:
required: false
example: enabled
Tag:
name: tag
description: User tag.
Tags:
name: tags
description: User tags. Multiple tags can be specified separated by comma for OR condition and plus for AND condition.
in: query
schema:
type: string
required: false
example: "orange"
example: "orange,yellow"
GroupName:
name: name
@@ -1278,7 +1362,7 @@ components:
maximum: 100
minimum: 1
required: false
example: "100"
example: 100
Offset:
name: offset
@@ -1289,7 +1373,7 @@ components:
default: 0
minimum: 0
required: false
example: "0"
example: 0
Order:
name: order
@@ -1321,6 +1405,26 @@ components:
default: false
required: false
CreatedFrom:
name: created_from
description: Filter users created from this date (inclusive).
in: query
schema:
type: string
format: date-time
required: false
example: "2023-01-01T00:00:00Z"
CreatedTo:
name: created_to
description: Filter users created up to this date (inclusive).
in: query
schema:
type: string
format: date-time
required: false
example: "2023-12-31T23:59:59Z"
VerificationToken:
name: token
description: Verification token.
@@ -1339,7 +1443,7 @@ components:
$ref: "#/components/schemas/UserReqObj"
UserUpdateReq:
description: JSON-formated document describing the metadata and name of user to be update
description: JSON-formated document describing the name, metadata and private_metadata of user to be update
required: true
content:
application/json:
@@ -1444,18 +1548,34 @@ components:
format: password
description: New password.
example: "12345678"
minimum: 8
minLength: 8
confirm_password:
type: string
format: password
description: New confirmation password.
example: "12345678"
minimum: 8
minLength: 8
token:
type: string
format: jwt
description: Reset token generated and sent in email.
RevokeRefreshTokenReq:
description: JSON-formatted document describing the refresh token to revoke.
required: true
content:
application/json:
schema:
type: object
properties:
token_id:
type: string
format: uuid
example: "bb7edb32-2eac-4aad-aebe-ed96fe073879"
description: The unique identifier of the refresh token to revoke.
required:
- token_id
PasswordChange:
description: Password change data. User can change its password.
required: true
@@ -1467,11 +1587,11 @@ components:
password:
type: string
format: password
minimum: 8
minLength: 8
description: New password.
old_password:
type: string
minimum: 8
minLength: 8
format: password
description: Old password.
@@ -1533,6 +1653,13 @@ components:
schema:
$ref: "#/components/schemas/User"
UserProfileRes:
description: Data retrieved for current user profile.
content:
application/json:
schema:
$ref: "#/components/schemas/User"
UserPageRes:
description: Data retrieved.
content:
@@ -1560,6 +1687,13 @@ components:
example: access
description: User access token type.
RefreshTokensPageRes:
description: List of active refresh tokens for the authenticated user.
content:
application/json:
schema:
$ref: "#/components/schemas/RefreshTokensPage"
HealthRes:
description: Service Health Check.
content:
+92 -92
View File
@@ -8,7 +8,7 @@ User service is using Auth service gRPC API to obtain login token or password re
- ID - key ID
- Type - one of the three types described below
- IssuerID - an ID of the SuperMQ User who issued the key
- IssuerID - an ID of the Magistrala User who issued the key
- Subject - user ID for which the key is issued
- IssuedAt - the timestamp when the key is issued
- ExpiresAt - the timestamp after which the key is invalid
@@ -29,7 +29,7 @@ API keys are similar to the User keys. The main difference is that API keys have
Recovery key is the password recovery key. It's short-lived token used for password recovery process.
For in-depth explanation of the aforementioned scenarios, as well as thorough understanding of SuperMQ, please check out the [official documentation][doc].
For in-depth explanation of the aforementioned scenarios, as well as thorough understanding of Magistrala, please check out the [official documentation][doc].
The following actions are supported:
@@ -59,63 +59,63 @@ 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 |
| :--- | :--- | :--- |
| `SMQ_AUTH_LOG_LEVEL` | Log level for the Auth service (debug, info, warn, error) | info |
| `SMQ_AUTH_DB_HOST` | Database host address | localhost |
| `SMQ_AUTH_DB_PORT` | Database host port | 5432 |
| `SMQ_AUTH_DB_USER` | Database user | supermq |
| `SMQ_AUTH_DB_PASSWORD` | Database password | supermq |
| `SMQ_AUTH_DB_NAME` | Name of the database used by the service | auth |
| `SMQ_AUTH_DB_SSL_MODE` | Database connection SSL mode (disable, require, verify-ca, verify-full) | disable |
| `SMQ_AUTH_DB_SSL_CERT` | Path to the PEM encoded certificate file | "" |
| `SMQ_AUTH_DB_SSL_KEY` | Path to the PEM encoded key file | "" |
| `SMQ_AUTH_DB_SSL_ROOT_CERT` | Path to the PEM encoded root certificate file | "" |
| `SMQ_AUTH_HTTP_HOST` | Auth service HTTP host | "" |
| `SMQ_AUTH_HTTP_PORT` | Auth service HTTP port | 8189 |
| `SMQ_AUTH_HTTP_SERVER_CERT` | Path to the PEM encoded HTTP server certificate file | "" |
| `SMQ_AUTH_HTTP_SERVER_KEY` | Path to the PEM encoded HTTP server key file | "" |
| `SMQ_AUTH_GRPC_HOST` | Auth service gRPC host | "" |
| `SMQ_AUTH_GRPC_PORT` | Auth service gRPC port | 8181 |
| `SMQ_AUTH_GRPC_SERVER_CERT` | Path to the PEM encoded gRPC server certificate file | "" |
| `SMQ_AUTH_GRPC_SERVER_KEY` | Path to the PEM encoded gRPC server key file | "" |
| `SMQ_AUTH_GRPC_SERVER_CA_CERTS` | Path to the PEM encoded gRPC server CA certificate file | "" |
| `SMQ_AUTH_GRPC_CLIENT_CA_CERTS` | Path to the PEM encoded gRPC client CA certificate file | "" |
| `SMQ_AUTH_SECRET_KEY` | String used for signing tokens | secret |
| `SMQ_AUTH_ACCESS_TOKEN_DURATION` | The access token expiration period | 1h |
| `SMQ_AUTH_REFRESH_TOKEN_DURATION` | The refresh token expiration period | 24h |
| `SMQ_AUTH_INVITATION_DURATION` | The invitation token expiration period | 168h |
| `SMQ_AUTH_CACHE_URL` | Redis URL for caching PAT scopes | redis://localhost:6379/0 |
| `SMQ_AUTH_CACHE_KEY_DURATION` | Duration for which PAT scope cache keys are valid | 10m |
| `SMQ_SPICEDB_HOST` | SpiceDB host address | localhost |
| `SMQ_SPICEDB_PORT` | SpiceDB host port | 50051 |
| `SMQ_SPICEDB_PRE_SHARED_KEY` | SpiceDB pre-shared key | 12345678 |
| `SMQ_SPICEDB_SCHEMA_FILE` | Path to SpiceDB schema file | ./docker/spicedb/schema.zed |
| `SMQ_JAEGER_URL` | Jaeger server URL | <http://jaeger:4318/v1/traces> |
| `SMQ_JAEGER_TRACE_RATIO` | Jaeger sampling ratio | 1.0 |
| `SMQ_SEND_TELEMETRY` | Send telemetry to supermq call home server | true |
| `SMQ_ADAPTER_INSTANCE_ID` | Adapter instance ID | "" |
| `SMQ_CALLOUT_URLS` | Comma-separated list of callout URLs | "" |
| `SMQ_CALLOUT_METHOD` | Callout method | POST |
| `SMQ_CALLOUT_TLS_VERIFICATION` | Enable TLS verification for callouts | true |
| `SMQ_CALLOUT_TIMEOUT` | Callout timeout | 10s |
| `SMQ_CALLOUT_CA_CERT` | Path to CA certificate file | "" |
| `SMQ_CALLOUT_CERT` | Path to client certificate file | "" |
| `SMQ_CALLOUT_KEY` | Path to client key file | "" |
| `SMQ_CALLOUT_OPERATIONS` | Invoke callout if the authorization permission matches any of the given permissions. | "" |
| 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_AUTH_CACHE_URL` | Redis URL for caching PAT scopes | redis://localhost:6379/0 |
| `MG_AUTH_CACHE_KEY_DURATION` | Duration for which PAT scope cache keys are valid | 10m |
| `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:4318/v1/traces> |
| `MG_JAEGER_TRACE_RATIO` | Jaeger sampling ratio | 1.0 |
| `MG_SEND_TELEMETRY` | Send telemetry to magistrala call home server | true |
| `MG_ADAPTER_INSTANCE_ID` | Adapter instance ID | "" |
| `MG_CALLOUT_URLS` | Comma-separated list of callout URLs | "" |
| `MG_CALLOUT_METHOD` | Callout method | POST |
| `MG_CALLOUT_TLS_VERIFICATION` | Enable TLS verification for callouts | true |
| `MG_CALLOUT_TIMEOUT` | Callout timeout | 10s |
| `MG_CALLOUT_CA_CERT` | Path to CA certificate file | "" |
| `MG_CALLOUT_CERT` | Path to client certificate file | "" |
| `MG_CALLOUT_KEY` | Path to client key file | "" |
| `MG_CALLOUT_OPERATIONS` | Invoke callout if the authorization permission matches any of the given permissions. | "" |
## Deployment
The service itself is distributed as Docker container. Check the [`auth`](https://github.com/absmach/supermq/blob/main/docker/docker-compose.yaml) service section in docker-compose file to see how service is deployed.
The service itself is distributed as Docker container. Check the [`auth`](https://github.com/absmach/magistrala/blob/main/docker/docker-compose.yaml) service section in docker-compose file to see how service is deployed.
Running this service outside of container requires working instance of the postgres database, SpiceDB, and Jaeger server.
To start the service outside of the container, execute the following shell script:
```bash
# download the latest version of the service
git clone https://github.com/absmach/supermq
git clone https://github.com/absmach/magistrala
cd supermq
cd magistrala
# compile the service
make auth
@@ -124,54 +124,54 @@ make auth
make install
# set the environment variables and run the service
SMQ_AUTH_LOG_LEVEL=info \
SMQ_AUTH_DB_HOST=localhost \
SMQ_AUTH_DB_PORT=5432 \
SMQ_AUTH_DB_USER=supermq \
SMQ_AUTH_DB_PASSWORD=supermq \
SMQ_AUTH_DB_NAME=auth \
SMQ_AUTH_DB_SSL_MODE=disable \
SMQ_AUTH_DB_SSL_CERT="" \
SMQ_AUTH_DB_SSL_KEY="" \
SMQ_AUTH_DB_SSL_ROOT_CERT="" \
SMQ_AUTH_HTTP_HOST=localhost \
SMQ_AUTH_HTTP_PORT=8189 \
SMQ_AUTH_HTTP_SERVER_CERT="" \
SMQ_AUTH_HTTP_SERVER_KEY="" \
SMQ_AUTH_GRPC_HOST=localhost \
SMQ_AUTH_GRPC_PORT=8181 \
SMQ_AUTH_GRPC_SERVER_CERT="" \
SMQ_AUTH_GRPC_SERVER_KEY="" \
SMQ_AUTH_GRPC_SERVER_CA_CERTS="" \
SMQ_AUTH_GRPC_CLIENT_CA_CERTS="" \
SMQ_AUTH_SECRET_KEY=secret \
SMQ_AUTH_ACCESS_TOKEN_DURATION=1h \
SMQ_AUTH_REFRESH_TOKEN_DURATION=24h \
SMQ_AUTH_INVITATION_DURATION=168h \
SMQ_SPICEDB_HOST=localhost \
SMQ_SPICEDB_PORT=50051 \
SMQ_SPICEDB_PRE_SHARED_KEY=12345678 \
SMQ_SPICEDB_SCHEMA_FILE=./docker/spicedb/schema.zed \
SMQ_JAEGER_URL=http://localhost:14268/api/traces \
SMQ_JAEGER_TRACE_RATIO=1.0 \
SMQ_SEND_TELEMETRY=true \
SMQ_AUTH_ADAPTER_INSTANCE_ID="" \
SMQ_CALLOUT_URLS="" \
SMQ_CALLOUT_METHOD="POST" \
SMQ_CALLOUT_TLS_VERIFICATION=true \
$GOBIN/supermq-auth
MG_AUTH_LOG_LEVEL=info \
MG_AUTH_DB_HOST=localhost \
MG_AUTH_DB_PORT=5432 \
MG_AUTH_DB_USER=magistrala \
MG_AUTH_DB_PASSWORD=magistrala \
MG_AUTH_DB_NAME=auth \
MG_AUTH_DB_SSL_MODE=disable \
MG_AUTH_DB_SSL_CERT="" \
MG_AUTH_DB_SSL_KEY="" \
MG_AUTH_DB_SSL_ROOT_CERT="" \
MG_AUTH_HTTP_HOST=localhost \
MG_AUTH_HTTP_PORT=8189 \
MG_AUTH_HTTP_SERVER_CERT="" \
MG_AUTH_HTTP_SERVER_KEY="" \
MG_AUTH_GRPC_HOST=localhost \
MG_AUTH_GRPC_PORT=8181 \
MG_AUTH_GRPC_SERVER_CERT="" \
MG_AUTH_GRPC_SERVER_KEY="" \
MG_AUTH_GRPC_SERVER_CA_CERTS="" \
MG_AUTH_GRPC_CLIENT_CA_CERTS="" \
MG_AUTH_SECRET_KEY=secret \
MG_AUTH_ACCESS_TOKEN_DURATION=1h \
MG_AUTH_REFRESH_TOKEN_DURATION=24h \
MG_AUTH_INVITATION_DURATION=168h \
MG_SPICEDB_HOST=localhost \
MG_SPICEDB_PORT=50051 \
MG_SPICEDB_PRE_SHARED_KEY=12345678 \
MG_SPICEDB_SCHEMA_FILE=./docker/spicedb/schema.zed \
MG_JAEGER_URL=http://localhost:14268/api/traces \
MG_JAEGER_TRACE_RATIO=1.0 \
MG_SEND_TELEMETRY=true \
MG_AUTH_ADAPTER_INSTANCE_ID="" \
MG_CALLOUT_URLS="" \
MG_CALLOUT_METHOD="POST" \
MG_CALLOUT_TLS_VERIFICATION=true \
$GOBIN/magistrala-auth
```
Setting `SMQ_AUTH_HTTP_SERVER_CERT` and `SMQ_AUTH_HTTP_SERVER_KEY` will enable TLS against the service. The service expects a file in PEM format for both the certificate and the key.
Setting `SMQ_AUTH_GRPC_SERVER_CERT` and `SMQ_AUTH_GRPC_SERVER_KEY` will enable TLS against the service. The service expects a file in PEM format for both the certificate and the key. Setting `SMQ_AUTH_GRPC_SERVER_CA_CERTS` will enable TLS against the service trusting only those CAs that are provided. The service expects a file in PEM format of trusted CAs. Setting `SMQ_AUTH_GRPC_CLIENT_CA_CERTS` will enable TLS against the service trusting only those CAs that are provided. The service expects a file in PEM format of trusted CAs.
Setting `MG_AUTH_HTTP_SERVER_CERT` and `MG_AUTH_HTTP_SERVER_KEY` will enable TLS against the service. The service expects a file in PEM format for both the certificate and the key.
Setting `MG_AUTH_GRPC_SERVER_CERT` and `MG_AUTH_GRPC_SERVER_KEY` will enable TLS against the service. The service expects a file in PEM format for both the certificate and the key. Setting `MG_AUTH_GRPC_SERVER_CA_CERTS` will enable TLS against the service trusting only those CAs that are provided. The service expects a file in PEM format of trusted CAs. Setting `MG_AUTH_GRPC_CLIENT_CA_CERTS` will enable TLS against the service trusting only those CAs that are provided. The service expects a file in PEM format of trusted CAs.
## Personal Access Tokens (PATs)
Personal Access Tokens (PATs) provide a secure way to authenticate with SuperMQ APIs without using your primary credentials. They are particularly useful for automation, CI/CD pipelines, and integrating with third-party services.
Personal Access Tokens (PATs) provide a secure way to authenticate with Magistrala APIs without using your primary credentials. They are particularly useful for automation, CI/CD pipelines, and integrating with third-party services.
### Overview
PATs in SuperMQ are designed with the following features:
PATs in Magistrala are designed with the following features:
- **Scoped Access**: Each token can be limited to specific operations on specific resources
- **Expiration Control**: Set custom expiration times for tokens
@@ -195,7 +195,7 @@ Where:
### PAT Operations
SuperMQ supports the following operations for PATs:
Magistrala supports the following operations for PATs:
| Operation | Description |
| ----------- | ------------------------------------ |
@@ -444,6 +444,6 @@ When a PAT is used for authentication:
## Usage
For more information about service capabilities and its usage, please check out the [API documentation](https://docs.api.supermq.absmach.eu/?urls.primaryName=auth.yaml).
For more information about service capabilities and its usage, please check out the [API documentation](https://docs.api.magistrala.absmach.eu/?urls.primaryName=auth.yaml).
[doc]: https://docs.supermq.absmach.eu/
[doc]: https://magistrala.absmach.eu/docs/
+53 -54
View File
@@ -7,9 +7,9 @@ import (
"context"
"time"
grpcAuthV1 "github.com/absmach/supermq/api/grpc/auth/v1"
"github.com/absmach/supermq/auth"
grpcapi "github.com/absmach/supermq/auth/api/grpc"
grpcAuthV1 "github.com/absmach/magistrala/api/grpc/auth/v1"
"github.com/absmach/magistrala/auth"
grpcapi "github.com/absmach/magistrala/auth/api/grpc"
"github.com/go-kit/kit/endpoint"
kitgrpc "github.com/go-kit/kit/transport/grpc"
"google.golang.org/grpc"
@@ -57,7 +57,7 @@ func (client authGrpcClient) Authenticate(ctx context.Context, token *grpcAuthV1
return &grpcAuthV1.AuthNRes{}, grpcapi.DecodeError(err)
}
ir := res.(authenticateRes)
return &grpcAuthV1.AuthNRes{Id: ir.id, UserId: ir.userID, UserRole: uint32(ir.userRole), Verified: ir.verified}, nil
return &grpcAuthV1.AuthNRes{Id: ir.id, UserId: ir.userID, UserRole: uint32(ir.userRole), Verified: ir.verified, TokenType: uint32(ir.tokenType)}, nil
}
func encodeIdentifyRequest(_ context.Context, grpcReq any) (any, error) {
@@ -67,7 +67,7 @@ func encodeIdentifyRequest(_ context.Context, grpcReq any) (any, error) {
func decodeIdentifyResponse(_ context.Context, grpcRes any) (any, error) {
res := grpcRes.(*grpcAuthV1.AuthNRes)
return authenticateRes{id: res.GetId(), userID: res.GetUserId(), userRole: auth.Role(res.UserRole), verified: res.GetVerified()}, nil
return authenticateRes{id: res.GetId(), userID: res.GetUserId(), userRole: auth.Role(res.UserRole), verified: res.GetVerified(), tokenType: auth.KeyType(res.GetTokenType())}, nil
}
func (client authGrpcClient) Authorize(ctx context.Context, req *grpcAuthV1.AuthZReq, _ ...grpc.CallOption) (r *grpcAuthV1.AuthZRes, err error) {
@@ -76,26 +76,32 @@ func (client authGrpcClient) Authorize(ctx context.Context, req *grpcAuthV1.Auth
var authReqData authReq
if policy := req.GetPolicy(); policy != nil {
authReqData = authReq{
TokenType: policy.GetTokenType(),
Domain: policy.GetDomain(),
SubjectType: policy.GetSubjectType(),
Subject: policy.GetSubject(),
SubjectKind: policy.GetSubjectKind(),
Relation: policy.GetRelation(),
Permission: policy.GetPermission(),
ObjectType: policy.GetObjectType(),
Object: policy.GetObject(),
if req != nil {
policyReq := req.GetPolicyReq()
patReq := req.GetPatReq()
if policyReq != nil {
authReqData = authReq{
Domain: policyReq.GetDomain(),
SubjectType: policyReq.GetSubjectType(),
Subject: policyReq.GetSubject(),
SubjectKind: policyReq.GetSubjectKind(),
Relation: policyReq.GetRelation(),
Permission: policyReq.GetPermission(),
ObjectType: policyReq.GetObjectType(),
Object: policyReq.GetObject(),
}
}
} else if pat := req.GetPat(); pat != nil {
authReqData = authReq{
UserID: pat.GetUserId(),
PatID: pat.GetPatId(),
EntityType: auth.EntityType(pat.GetEntityType()),
OptionalDomainID: pat.GetOptionalDomainId(),
Operation: auth.Operation(pat.GetOperation()),
EntityID: pat.GetEntityId(),
if patReq != nil {
if patReq.GetDomain() != "" {
authReqData.Domain = patReq.GetDomain()
}
authReqData.UserID = patReq.GetUserId()
authReqData.PatID = patReq.GetPatId()
authReqData.EntityType = patReq.GetEntityType()
authReqData.Operation = patReq.GetOperation()
authReqData.EntityID = patReq.GetEntityId()
}
}
@@ -116,36 +122,29 @@ func decodeAuthorizeResponse(_ context.Context, grpcRes any) (any, error) {
func encodeAuthorizeRequest(_ context.Context, grpcReq any) (any, error) {
req := grpcReq.(authReq)
// Check if this is a PAT request (has PatID) or policy request
if req.PatID != "" {
return &grpcAuthV1.AuthZReq{
AuthType: &grpcAuthV1.AuthZReq_Pat{
Pat: &grpcAuthV1.PATReq{
UserId: req.UserID,
PatId: req.PatID,
EntityType: uint32(req.EntityType),
OptionalDomainId: req.OptionalDomainID,
Operation: uint32(req.Operation),
EntityId: req.EntityID,
},
},
}, nil
authZReq := &grpcAuthV1.AuthZReq{
PolicyReq: &grpcAuthV1.PolicyReq{
Domain: req.Domain,
SubjectType: req.SubjectType,
Subject: req.Subject,
SubjectKind: req.SubjectKind,
Relation: req.Relation,
Permission: req.Permission,
ObjectType: req.ObjectType,
Object: req.Object,
},
}
// Otherwise, it's a policy request
return &grpcAuthV1.AuthZReq{
AuthType: &grpcAuthV1.AuthZReq_Policy{
Policy: &grpcAuthV1.PolicyReq{
TokenType: req.TokenType,
Domain: req.Domain,
SubjectType: req.SubjectType,
Subject: req.Subject,
SubjectKind: req.SubjectKind,
Relation: req.Relation,
Permission: req.Permission,
ObjectType: req.ObjectType,
Object: req.Object,
},
},
}, nil
if req.PatID != "" {
authZReq.PatReq = &grpcAuthV1.PATReq{
PatId: req.PatID,
Domain: req.Domain,
Operation: req.Operation,
UserId: req.UserID,
EntityId: req.EntityID,
EntityType: req.EntityType,
}
}
return authZReq, nil
}
+28 -19
View File
@@ -6,8 +6,8 @@ package auth
import (
"context"
"github.com/absmach/supermq/auth"
"github.com/absmach/supermq/pkg/policies"
"github.com/absmach/magistrala/auth"
"github.com/absmach/magistrala/pkg/policies"
"github.com/go-kit/kit/endpoint"
)
@@ -23,7 +23,7 @@ func authenticateEndpoint(svc auth.Service) endpoint.Endpoint {
return authenticateRes{}, err
}
return authenticateRes{id: key.ID, userID: key.Subject, userRole: key.Role, verified: key.Verified}, nil
return authenticateRes{id: key.ID, userID: key.Subject, userRole: key.Role, verified: key.Verified, tokenType: key.Type}, nil
}
}
@@ -35,23 +35,32 @@ func authorizeEndpoint(svc auth.Service) endpoint.Endpoint {
return authorizeRes{}, err
}
var pat *auth.PATAuthz
if req.PatID != "" {
entityType, err := auth.ParseEntityType(req.EntityType)
if err != nil {
return authorizeRes{authorized: false}, err
}
pat = &auth.PATAuthz{
PatID: req.PatID,
UserID: req.UserID,
EntityType: entityType,
EntityID: req.EntityID,
Operation: req.Operation,
Domain: req.Domain,
}
}
err := svc.Authorize(ctx, policies.Policy{
TokenType: req.TokenType,
Domain: req.Domain,
SubjectType: req.SubjectType,
SubjectKind: req.SubjectKind,
Subject: req.Subject,
Relation: req.Relation,
Permission: req.Permission,
ObjectType: req.ObjectType,
Object: req.Object,
UserID: req.UserID,
PatID: req.PatID,
EntityType: uint32(req.EntityType),
OptionalDomainID: req.OptionalDomainID,
Operation: uint32(req.Operation),
EntityID: req.EntityID,
})
Domain: req.Domain,
SubjectType: req.SubjectType,
SubjectKind: req.SubjectKind,
Subject: req.Subject,
Relation: req.Relation,
Permission: req.Permission,
ObjectType: req.ObjectType,
Object: req.Object,
}, pat)
if err != nil {
return authorizeRes{authorized: false}, err
}
-343
View File
@@ -1,343 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package auth_test
import (
"context"
"fmt"
"net"
"testing"
"time"
grpcAuthV1 "github.com/absmach/supermq/api/grpc/auth/v1"
apiutil "github.com/absmach/supermq/api/http/util"
"github.com/absmach/supermq/auth"
grpcapi "github.com/absmach/supermq/auth/api/grpc/auth"
"github.com/absmach/supermq/internal/testsutil"
"github.com/absmach/supermq/pkg/errors"
svcerr "github.com/absmach/supermq/pkg/errors/service"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
const (
port = 8081
id = "testID"
usersType = "users"
adminPermission = "admin"
authoritiesObj = "authorities"
memberRelation = "member"
validToken = "valid"
inValidToken = "invalid"
validPATToken = "valid"
)
var (
domainID = testsutil.GenerateUUID(&testing.T{})
authAddr = fmt.Sprintf("localhost:%d", port)
clientID = testsutil.GenerateUUID(&testing.T{})
)
func startGRPCServer(svc auth.Service, port int) *grpc.Server {
listener, _ := net.Listen("tcp", fmt.Sprintf(":%d", port))
server := grpc.NewServer()
grpcAuthV1.RegisterAuthServiceServer(server, grpcapi.NewAuthServer(svc))
go func() {
err := server.Serve(listener)
assert.Nil(&testing.T{}, err, fmt.Sprintf(`"Unexpected error creating auth server %s"`, err))
}()
return server
}
func TestIdentify(t *testing.T) {
conn, err := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err))
defer conn.Close()
grpcClient := grpcapi.NewAuthClient(conn, time.Second)
cases := []struct {
desc string
token string
key auth.Key
idt *grpcAuthV1.AuthNRes
svcErr error
err error
}{
{
desc: "authenticate user with valid user token",
token: validToken,
key: auth.Key{ID: "", Subject: id, Role: auth.UserRole},
idt: &grpcAuthV1.AuthNRes{UserId: id, UserRole: uint32(auth.UserRole)},
err: nil,
},
{
desc: "authenticate user with invalid user token",
token: "invalid",
key: auth.Key{},
idt: &grpcAuthV1.AuthNRes{},
svcErr: svcerr.ErrAuthentication,
err: svcerr.ErrAuthentication,
},
{
desc: "authenticate user with empty token",
token: "",
idt: &grpcAuthV1.AuthNRes{},
err: apiutil.ErrBearerToken,
},
{
desc: "authenticate user with valid PAT token",
token: "pat_" + validPATToken,
key: auth.Key{ID: id, Type: auth.PersonalAccessToken, Subject: clientID, Role: auth.UserRole},
idt: &grpcAuthV1.AuthNRes{Id: id, UserId: clientID, UserRole: uint32(auth.UserRole)},
err: nil,
},
{
desc: "authenticate user with invalid PAT token",
token: "pat_invalid",
key: auth.Key{},
idt: &grpcAuthV1.AuthNRes{},
svcErr: svcerr.ErrAuthentication,
err: svcerr.ErrAuthentication,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
svcCall := svc.On("Identify", mock.Anything, tc.token).Return(tc.key, tc.svcErr)
idt, err := grpcClient.Authenticate(context.Background(), &grpcAuthV1.AuthNReq{Token: tc.token})
if idt != nil {
assert.Equal(t, tc.idt, idt, fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.idt, idt))
}
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
svcCall.Unset()
})
}
}
func TestAuthorize(t *testing.T) {
conn, err := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err))
defer conn.Close()
grpcClient := grpcapi.NewAuthClient(conn, time.Second)
cases := []struct {
desc string
token string
authRequest *grpcAuthV1.AuthZReq
authResponse *grpcAuthV1.AuthZRes
err error
}{
{
desc: "authorize user with authorized token",
token: validToken,
authRequest: &grpcAuthV1.AuthZReq{
AuthType: &grpcAuthV1.AuthZReq_Policy{
Policy: &grpcAuthV1.PolicyReq{
Subject: id,
SubjectType: usersType,
Object: authoritiesObj,
ObjectType: usersType,
Relation: memberRelation,
Permission: adminPermission,
},
},
},
authResponse: &grpcAuthV1.AuthZRes{Authorized: true},
err: nil,
},
{
desc: "authorize user with unauthorized token",
token: inValidToken,
authRequest: &grpcAuthV1.AuthZReq{
AuthType: &grpcAuthV1.AuthZReq_Policy{
Policy: &grpcAuthV1.PolicyReq{
Subject: id,
SubjectType: usersType,
Object: authoritiesObj,
ObjectType: usersType,
Relation: memberRelation,
Permission: adminPermission,
},
},
},
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
err: svcerr.ErrAuthorization,
},
{
desc: "authorize user with empty subject",
token: validToken,
authRequest: &grpcAuthV1.AuthZReq{
AuthType: &grpcAuthV1.AuthZReq_Policy{
Policy: &grpcAuthV1.PolicyReq{
Subject: "",
SubjectType: usersType,
Object: authoritiesObj,
ObjectType: usersType,
Relation: memberRelation,
Permission: adminPermission,
},
},
},
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
err: apiutil.ErrMissingPolicySub,
},
{
desc: "authorize user with empty subject type",
token: validToken,
authRequest: &grpcAuthV1.AuthZReq{
AuthType: &grpcAuthV1.AuthZReq_Policy{
Policy: &grpcAuthV1.PolicyReq{
Subject: id,
SubjectType: "",
Object: authoritiesObj,
ObjectType: usersType,
Relation: memberRelation,
Permission: adminPermission,
},
},
},
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
err: apiutil.ErrMissingPolicySub,
},
{
desc: "authorize user with empty object",
token: validToken,
authRequest: &grpcAuthV1.AuthZReq{
AuthType: &grpcAuthV1.AuthZReq_Policy{
Policy: &grpcAuthV1.PolicyReq{
Subject: id,
SubjectType: usersType,
Object: "",
ObjectType: usersType,
Relation: memberRelation,
Permission: adminPermission,
},
},
},
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
err: apiutil.ErrMissingPolicyObj,
},
{
desc: "authorize user with empty object type",
token: validToken,
authRequest: &grpcAuthV1.AuthZReq{
AuthType: &grpcAuthV1.AuthZReq_Policy{
Policy: &grpcAuthV1.PolicyReq{
Subject: id,
SubjectType: usersType,
Object: authoritiesObj,
ObjectType: "",
Relation: memberRelation,
Permission: adminPermission,
},
},
},
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
err: apiutil.ErrMissingPolicyObj,
},
{
desc: "authorize user with empty permission",
token: validToken,
authRequest: &grpcAuthV1.AuthZReq{
AuthType: &grpcAuthV1.AuthZReq_Policy{
Policy: &grpcAuthV1.PolicyReq{
Subject: id,
SubjectType: usersType,
Object: authoritiesObj,
ObjectType: usersType,
Relation: memberRelation,
Permission: "",
},
},
},
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
err: apiutil.ErrMalformedPolicyPer,
},
{
desc: "authorize user with valid PAT token",
token: validPATToken,
authRequest: &grpcAuthV1.AuthZReq{
AuthType: &grpcAuthV1.AuthZReq_Pat{
Pat: &grpcAuthV1.PATReq{
UserId: id,
PatId: id,
EntityType: uint32(auth.ClientsType),
OptionalDomainId: domainID,
Operation: uint32(auth.CreateOp),
EntityId: clientID,
},
},
},
authResponse: &grpcAuthV1.AuthZRes{Authorized: true},
err: nil,
},
{
desc: "authorize user with unauthorized PAT token",
token: inValidToken,
authRequest: &grpcAuthV1.AuthZReq{
AuthType: &grpcAuthV1.AuthZReq_Pat{
Pat: &grpcAuthV1.PATReq{
UserId: id,
PatId: id,
EntityType: uint32(auth.ClientsType),
OptionalDomainId: domainID,
Operation: uint32(auth.CreateOp),
EntityId: clientID,
},
},
},
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
err: svcerr.ErrAuthorization,
},
{
desc: "authorize PAT with missing user id",
token: validPATToken,
authRequest: &grpcAuthV1.AuthZReq{
AuthType: &grpcAuthV1.AuthZReq_Pat{
Pat: &grpcAuthV1.PATReq{
PatId: id,
EntityType: uint32(auth.ClientsType),
OptionalDomainId: domainID,
Operation: uint32(auth.CreateOp),
EntityId: clientID,
},
},
},
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
err: apiutil.ErrMissingUserID,
},
{
desc: "authorize PAT with missing entity id",
token: validPATToken,
authRequest: &grpcAuthV1.AuthZReq{
AuthType: &grpcAuthV1.AuthZReq_Pat{
Pat: &grpcAuthV1.PATReq{
UserId: id,
PatId: id,
EntityType: uint32(auth.ClientsType),
OptionalDomainId: domainID,
Operation: uint32(auth.CreateOp),
},
},
},
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
err: apiutil.ErrMissingID,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
svcCall := svc.On("Authorize", mock.Anything, mock.Anything).Return(tc.err)
ar, err := grpcClient.Authorize(context.Background(), tc.authRequest)
if ar != nil {
assert.Equal(t, tc.authResponse, ar, fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.authResponse, ar))
}
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
svcCall.Unset()
})
}
}
+9 -10
View File
@@ -4,8 +4,7 @@
package auth
import (
apiutil "github.com/absmach/supermq/api/http/util"
"github.com/absmach/supermq/auth"
apiutil "github.com/absmach/magistrala/api/http/util"
)
type authenticateReq struct {
@@ -25,7 +24,6 @@ func (req authenticateReq) validate() error {
// 2. object - an entity over which action will be executed
// 3. action - type of action that will be executed (read/write).
type authReq struct {
TokenType uint32
Domain string
SubjectType string
SubjectKind string
@@ -36,12 +34,11 @@ type authReq struct {
Object string
// PAT authorization fields
UserID string
PatID string
EntityType auth.EntityType
OptionalDomainID string
Operation auth.Operation
EntityID string
UserID string
PatID string
EntityType string
Operation string
EntityID string
}
func (req authReq) validate() error {
@@ -52,7 +49,9 @@ func (req authReq) validate() error {
if req.EntityID == "" {
return apiutil.ErrMissingID
}
return nil
if req.EntityType == "" {
return apiutil.ErrMissingPolicyObj
}
}
if req.Subject == "" || req.SubjectType == "" {
+6 -5
View File
@@ -3,13 +3,14 @@
package auth
import smqauth "github.com/absmach/supermq/auth"
import "github.com/absmach/magistrala/auth"
type authenticateRes struct {
id string
userID string
userRole smqauth.Role
verified bool
id string
userID string
userRole auth.Role
verified bool
tokenType auth.KeyType
}
type authorizeRes struct {
+36 -27
View File
@@ -6,9 +6,9 @@ package auth
import (
"context"
grpcAuthV1 "github.com/absmach/supermq/api/grpc/auth/v1"
"github.com/absmach/supermq/auth"
grpcapi "github.com/absmach/supermq/auth/api/grpc"
grpcAuthV1 "github.com/absmach/magistrala/api/grpc/auth/v1"
"github.com/absmach/magistrala/auth"
grpcapi "github.com/absmach/magistrala/auth/api/grpc"
kitgrpc "github.com/go-kit/kit/transport/grpc"
)
@@ -60,36 +60,45 @@ func decodeAuthenticateRequest(_ context.Context, grpcReq any) (any, error) {
func encodeAuthenticateResponse(_ context.Context, grpcRes any) (any, error) {
res := grpcRes.(authenticateRes)
return &grpcAuthV1.AuthNRes{Id: res.id, UserId: res.userID, UserRole: uint32(res.userRole), Verified: res.verified}, nil
return &grpcAuthV1.AuthNRes{Id: res.id, UserId: res.userID, UserRole: uint32(res.userRole), Verified: res.verified, TokenType: uint32(res.tokenType)}, nil
}
func decodeAuthorizeRequest(_ context.Context, grpcReq any) (any, error) {
req := grpcReq.(*grpcAuthV1.AuthZReq)
if policy := req.GetPolicy(); policy != nil {
return authReq{
TokenType: policy.GetTokenType(),
Domain: policy.GetDomain(),
SubjectType: policy.GetSubjectType(),
SubjectKind: policy.GetSubjectKind(),
Subject: policy.GetSubject(),
Relation: policy.GetRelation(),
Permission: policy.GetPermission(),
ObjectType: policy.GetObjectType(),
Object: policy.GetObject(),
}, nil
}
if pat := req.GetPat(); pat != nil {
return authReq{
UserID: pat.GetUserId(),
PatID: pat.GetPatId(),
EntityType: auth.EntityType(pat.GetEntityType()),
OptionalDomainID: pat.GetOptionalDomainId(),
Operation: auth.Operation(pat.GetOperation()),
EntityID: pat.GetEntityId(),
}, nil
if req == nil {
return authReq{}, nil
}
return authReq{}, nil
policyReq := req.GetPolicyReq()
patReq := req.GetPatReq()
if policyReq == nil {
return authReq{}, nil
}
authRequest := authReq{
Domain: policyReq.GetDomain(),
SubjectType: policyReq.GetSubjectType(),
SubjectKind: policyReq.GetSubjectKind(),
Subject: policyReq.GetSubject(),
Relation: policyReq.GetRelation(),
Permission: policyReq.GetPermission(),
ObjectType: policyReq.GetObjectType(),
Object: policyReq.GetObject(),
}
if patReq != nil {
if patReq.GetDomain() != "" {
authRequest.Domain = patReq.GetDomain()
}
authRequest.UserID = patReq.GetUserId()
authRequest.PatID = patReq.GetPatId()
authRequest.EntityType = patReq.GetEntityType()
authRequest.Operation = patReq.GetOperation()
authRequest.EntityID = patReq.GetEntityId()
}
return authRequest, nil
}
func encodeAuthorizeResponse(_ context.Context, grpcRes any) (any, error) {
-24
View File
@@ -1,24 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package auth_test
import (
"os"
"testing"
"github.com/absmach/supermq/auth/mocks"
)
var svc *mocks.Service
func TestMain(m *testing.M) {
svc = new(mocks.Service)
server := startGRPCServer(svc, port)
code := m.Run()
server.GracefulStop()
os.Exit(code)
}
+75 -15
View File
@@ -7,9 +7,9 @@ import (
"context"
"time"
grpcTokenV1 "github.com/absmach/supermq/api/grpc/token/v1"
"github.com/absmach/supermq/auth"
grpcapi "github.com/absmach/supermq/auth/api/grpc"
grpcTokenV1 "github.com/absmach/magistrala/api/grpc/token/v1"
"github.com/absmach/magistrala/auth"
grpcapi "github.com/absmach/magistrala/auth/api/grpc"
"github.com/go-kit/kit/endpoint"
kitgrpc "github.com/go-kit/kit/transport/grpc"
"google.golang.org/grpc"
@@ -18,14 +18,16 @@ import (
const tokenSvcName = "token.v1.TokenService"
type tokenGrpcClient struct {
issue endpoint.Endpoint
refresh endpoint.Endpoint
timeout time.Duration
issue endpoint.Endpoint
refresh endpoint.Endpoint
revoke endpoint.Endpoint
listUserRefreshTokens endpoint.Endpoint
timeout time.Duration
}
var _ grpcTokenV1.TokenServiceClient = (*tokenGrpcClient)(nil)
// NewAuthClient returns new auth gRPC client instance.
// NewTokenClient returns new token gRPC client instance.
func NewTokenClient(conn *grpc.ClientConn, timeout time.Duration) grpcTokenV1.TokenServiceClient {
return &tokenGrpcClient{
issue: kitgrpc.NewClient(
@@ -44,6 +46,22 @@ func NewTokenClient(conn *grpc.ClientConn, timeout time.Duration) grpcTokenV1.To
decodeRefreshResponse,
grpcTokenV1.Token{},
).Endpoint(),
revoke: kitgrpc.NewClient(
conn,
tokenSvcName,
"Revoke",
encodeRevokeRequest,
decodeRevokeResponse,
grpcTokenV1.RevokeRes{},
).Endpoint(),
listUserRefreshTokens: kitgrpc.NewClient(
conn,
tokenSvcName,
"ListUserRefreshTokens",
encodeListUserRefreshTokensRequest,
decodeListUserRefreshTokensResponse,
grpcTokenV1.ListUserRefreshTokensRes{},
).Endpoint(),
timeout: timeout,
}
}
@@ -53,10 +71,11 @@ func (client tokenGrpcClient) Issue(ctx context.Context, req *grpcTokenV1.IssueR
defer cancel()
res, err := client.issue(ctx, issueReq{
userID: req.GetUserId(),
userRole: auth.Role(req.GetUserRole()),
keyType: auth.KeyType(req.GetType()),
verified: req.GetVerified(),
userID: req.GetUserId(),
userRole: auth.Role(req.GetUserRole()),
keyType: auth.KeyType(req.GetType()),
verified: req.GetVerified(),
description: req.GetDescription(),
})
if err != nil {
return &grpcTokenV1.Token{}, grpcapi.DecodeError(err)
@@ -67,10 +86,11 @@ func (client tokenGrpcClient) Issue(ctx context.Context, req *grpcTokenV1.IssueR
func encodeIssueRequest(_ context.Context, grpcReq any) (any, error) {
req := grpcReq.(issueReq)
return &grpcTokenV1.IssueReq{
UserId: req.userID,
UserRole: uint32(req.userRole),
Type: uint32(req.keyType),
Verified: req.verified,
UserId: req.userID,
UserRole: uint32(req.userRole),
Type: uint32(req.keyType),
Verified: req.verified,
Description: req.description,
}, nil
}
@@ -97,3 +117,43 @@ func encodeRefreshRequest(_ context.Context, grpcReq any) (any, error) {
func decodeRefreshResponse(_ context.Context, grpcRes any) (any, error) {
return grpcRes, nil
}
func (client tokenGrpcClient) Revoke(ctx context.Context, req *grpcTokenV1.RevokeReq, _ ...grpc.CallOption) (*grpcTokenV1.RevokeRes, error) {
ctx, cancel := context.WithTimeout(ctx, client.timeout)
defer cancel()
res, err := client.revoke(ctx, revokeReq{userID: req.GetUserId(), tokenID: req.GetTokenId()})
if err != nil {
return &grpcTokenV1.RevokeRes{}, grpcapi.DecodeError(err)
}
return res.(*grpcTokenV1.RevokeRes), nil
}
func encodeRevokeRequest(_ context.Context, grpcReq any) (any, error) {
req := grpcReq.(revokeReq)
return &grpcTokenV1.RevokeReq{UserId: req.userID, TokenId: req.tokenID}, nil
}
func decodeRevokeResponse(_ context.Context, grpcRes any) (any, error) {
return grpcRes, nil
}
func (client tokenGrpcClient) ListUserRefreshTokens(ctx context.Context, req *grpcTokenV1.ListUserRefreshTokensReq, _ ...grpc.CallOption) (*grpcTokenV1.ListUserRefreshTokensRes, error) {
ctx, cancel := context.WithTimeout(ctx, client.timeout)
defer cancel()
res, err := client.listUserRefreshTokens(ctx, listUserRefreshTokensReq{userID: req.GetUserId()})
if err != nil {
return &grpcTokenV1.ListUserRefreshTokensRes{}, grpcapi.DecodeError(err)
}
return res.(*grpcTokenV1.ListUserRefreshTokensRes), nil
}
func encodeListUserRefreshTokensRequest(_ context.Context, grpcReq any) (any, error) {
req := grpcReq.(listUserRefreshTokensReq)
return &grpcTokenV1.ListUserRefreshTokensReq{UserId: req.userID}, nil
}
func decodeListUserRefreshTokensResponse(_ context.Context, grpcRes any) (any, error) {
return grpcRes, nil
}
+37 -5
View File
@@ -6,7 +6,7 @@ package token
import (
"context"
"github.com/absmach/supermq/auth"
"github.com/absmach/magistrala/auth"
"github.com/go-kit/kit/endpoint"
)
@@ -18,10 +18,11 @@ func issueEndpoint(svc auth.Service) endpoint.Endpoint {
}
key := auth.Key{
Type: req.keyType,
Subject: req.userID,
Role: req.userRole,
Verified: req.verified,
Type: req.keyType,
Subject: req.userID,
Role: req.userRole,
Verified: req.verified,
Description: req.description,
}
tkn, err := svc.Issue(ctx, "", key)
if err != nil {
@@ -56,3 +57,34 @@ func refreshEndpoint(svc auth.Service) endpoint.Endpoint {
return ret, nil
}
}
func revokeEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request any) (any, error) {
req := request.(revokeReq)
if err := req.validate(); err != nil {
return nil, err
}
err := svc.RevokeToken(ctx, req.userID, req.tokenID)
if err != nil {
return nil, err
}
return nil, nil
}
}
func listUserRefreshTokensEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request any) (any, error) {
req := request.(listUserRefreshTokensReq)
if err := req.validate(); err != nil {
return listUserRefreshTokensRes{}, err
}
refreshTokens, err := svc.ListUserRefreshTokens(ctx, req.userID)
if err != nil {
return listUserRefreshTokensRes{}, err
}
return listUserRefreshTokensRes{refreshTokens: refreshTokens}, nil
}
}
-169
View File
@@ -1,169 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package token_test
import (
"context"
"fmt"
"net"
"testing"
"time"
grpcTokenV1 "github.com/absmach/supermq/api/grpc/token/v1"
apiutil "github.com/absmach/supermq/api/http/util"
"github.com/absmach/supermq/auth"
grpcapi "github.com/absmach/supermq/auth/api/grpc/token"
"github.com/absmach/supermq/internal/testsutil"
"github.com/absmach/supermq/pkg/errors"
svcerr "github.com/absmach/supermq/pkg/errors/service"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
const (
port = 8082
secret = "secret"
email = "test@example.com"
id = "testID"
clientsType = "clients"
usersType = "users"
description = "Description"
groupName = "smqx"
adminPermission = "admin"
authoritiesObj = "authorities"
memberRelation = "member"
loginDuration = 30 * time.Minute
refreshDuration = 24 * time.Hour
invalidDuration = 7 * 24 * time.Hour
validToken = "valid"
inValidToken = "invalid"
validPolicy = "valid"
)
var (
validID = testsutil.GenerateUUID(&testing.T{})
authAddr = fmt.Sprintf("localhost:%d", port)
)
func startGRPCServer(svc auth.Service, port int) *grpc.Server {
listener, _ := net.Listen("tcp", fmt.Sprintf(":%d", port))
server := grpc.NewServer()
grpcTokenV1.RegisterTokenServiceServer(server, grpcapi.NewTokenServer(svc))
go func() {
err := server.Serve(listener)
assert.Nil(&testing.T{}, err, fmt.Sprintf(`"Unexpected error creating auth server %s"`, err))
}()
return server
}
func TestIssue(t *testing.T) {
conn, err := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
defer conn.Close()
assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err))
grpcClient := grpcapi.NewTokenClient(conn, time.Second)
cases := []struct {
desc string
userId string
kind auth.KeyType
issueResponse auth.Token
err error
}{
{
desc: "issue for user with valid token",
userId: validID,
kind: auth.AccessKey,
issueResponse: auth.Token{
AccessToken: validToken,
RefreshToken: validToken,
},
err: nil,
},
{
desc: "issue recovery key",
userId: validID,
kind: auth.RecoveryKey,
issueResponse: auth.Token{
AccessToken: validToken,
RefreshToken: validToken,
},
err: nil,
},
{
desc: "issue API key unauthenticated",
userId: validID,
kind: auth.APIKey,
issueResponse: auth.Token{},
err: svcerr.ErrAuthentication,
},
{
desc: "issue for invalid key type",
userId: validID,
kind: 32,
issueResponse: auth.Token{},
err: errors.ErrMalformedEntity,
},
{
desc: "issue for user that does notexist",
userId: "",
kind: auth.APIKey,
issueResponse: auth.Token{},
err: svcerr.ErrAuthentication,
},
}
for _, tc := range cases {
svcCall := svc.On("Issue", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.issueResponse, tc.err)
_, err := grpcClient.Issue(context.Background(), &grpcTokenV1.IssueReq{UserId: tc.userId, Type: uint32(tc.kind)})
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
svcCall.Unset()
}
}
func TestRefresh(t *testing.T) {
conn, err := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
defer conn.Close()
assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err))
grpcClient := grpcapi.NewTokenClient(conn, time.Second)
cases := []struct {
desc string
token string
issueResponse auth.Token
err error
}{
{
desc: "refresh token with valid token",
token: validToken,
issueResponse: auth.Token{
AccessToken: validToken,
RefreshToken: validToken,
},
err: nil,
},
{
desc: "refresh token with invalid token",
token: inValidToken,
issueResponse: auth.Token{},
err: svcerr.ErrAuthentication,
},
{
desc: "refresh token with empty token",
token: "",
issueResponse: auth.Token{},
err: apiutil.ErrMissingSecret,
},
}
for _, tc := range cases {
svcCall := svc.On("Issue", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.issueResponse, tc.err)
_, err := grpcClient.Refresh(context.Background(), &grpcTokenV1.RefreshReq{RefreshToken: tc.token})
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
svcCall.Unset()
}
}
+32 -6
View File
@@ -4,15 +4,16 @@
package token
import (
apiutil "github.com/absmach/supermq/api/http/util"
"github.com/absmach/supermq/auth"
apiutil "github.com/absmach/magistrala/api/http/util"
"github.com/absmach/magistrala/auth"
)
type issueReq struct {
userID string
userRole auth.Role
keyType auth.KeyType
verified bool
userID string
userRole auth.Role
keyType auth.KeyType
verified bool
description string
}
func (req issueReq) validate() error {
@@ -38,3 +39,28 @@ func (req refreshReq) validate() error {
return nil
}
type revokeReq struct {
userID string
tokenID string
}
func (req revokeReq) validate() error {
if req.tokenID == "" {
return apiutil.ErrMissingID
}
return nil
}
type listUserRefreshTokensReq struct {
userID string
}
func (req listUserRefreshTokensReq) validate() error {
if req.userID == "" {
return apiutil.ErrMissingID
}
return nil
}
+6
View File
@@ -3,8 +3,14 @@
package token
import "github.com/absmach/magistrala/auth"
type issueRes struct {
accessToken string
refreshToken string
accessType string
}
type listUserRefreshTokensRes struct {
refreshTokens []auth.TokenInfo
}
+69 -10
View File
@@ -6,9 +6,9 @@ package token
import (
"context"
grpcTokenV1 "github.com/absmach/supermq/api/grpc/token/v1"
"github.com/absmach/supermq/auth"
grpcapi "github.com/absmach/supermq/auth/api/grpc"
grpcTokenV1 "github.com/absmach/magistrala/api/grpc/token/v1"
"github.com/absmach/magistrala/auth"
grpcapi "github.com/absmach/magistrala/auth/api/grpc"
kitgrpc "github.com/go-kit/kit/transport/grpc"
)
@@ -16,11 +16,13 @@ var _ grpcTokenV1.TokenServiceServer = (*tokenGrpcServer)(nil)
type tokenGrpcServer struct {
grpcTokenV1.UnimplementedTokenServiceServer
issue kitgrpc.Handler
refresh kitgrpc.Handler
issue kitgrpc.Handler
refresh kitgrpc.Handler
revoke kitgrpc.Handler
listUserRefreshTokens kitgrpc.Handler
}
// NewAuthServer returns new AuthnServiceServer instance.
// NewTokenServer returns new TokenServiceServer instance.
func NewTokenServer(svc auth.Service) grpcTokenV1.TokenServiceServer {
return &tokenGrpcServer{
issue: kitgrpc.NewServer(
@@ -33,6 +35,16 @@ func NewTokenServer(svc auth.Service) grpcTokenV1.TokenServiceServer {
decodeRefreshRequest,
encodeIssueResponse,
),
revoke: kitgrpc.NewServer(
(revokeEndpoint(svc)),
decodeRevokeRequest,
encodeRevokeResponse,
),
listUserRefreshTokens: kitgrpc.NewServer(
(listUserRefreshTokensEndpoint(svc)),
decodeListUserRefreshTokensRequest,
encodeListUserRefreshTokensResponse,
),
}
}
@@ -55,10 +67,11 @@ func (s *tokenGrpcServer) Refresh(ctx context.Context, req *grpcTokenV1.RefreshR
func decodeIssueRequest(_ context.Context, grpcReq any) (any, error) {
req := grpcReq.(*grpcTokenV1.IssueReq)
return issueReq{
userID: req.GetUserId(),
userRole: auth.Role(req.GetUserRole()),
keyType: auth.KeyType(req.GetType()),
verified: req.Verified,
userID: req.GetUserId(),
userRole: auth.Role(req.GetUserRole()),
keyType: auth.KeyType(req.GetType()),
verified: req.Verified,
description: req.GetDescription(),
}, nil
}
@@ -76,3 +89,49 @@ func encodeIssueResponse(_ context.Context, grpcRes any) (any, error) {
AccessType: res.accessType,
}, nil
}
func (s *tokenGrpcServer) Revoke(ctx context.Context, req *grpcTokenV1.RevokeReq) (*grpcTokenV1.RevokeRes, error) {
_, res, err := s.revoke.ServeGRPC(ctx, req)
if err != nil {
return nil, grpcapi.EncodeError(err)
}
return res.(*grpcTokenV1.RevokeRes), nil
}
func decodeRevokeRequest(_ context.Context, grpcReq any) (any, error) {
req := grpcReq.(*grpcTokenV1.RevokeReq)
return revokeReq{userID: req.GetUserId(), tokenID: req.GetTokenId()}, nil
}
func encodeRevokeResponse(_ context.Context, grpcRes any) (any, error) {
return &grpcTokenV1.RevokeRes{}, nil
}
func (s *tokenGrpcServer) ListUserRefreshTokens(ctx context.Context, req *grpcTokenV1.ListUserRefreshTokensReq) (*grpcTokenV1.ListUserRefreshTokensRes, error) {
_, res, err := s.listUserRefreshTokens.ServeGRPC(ctx, req)
if err != nil {
return nil, grpcapi.EncodeError(err)
}
return res.(*grpcTokenV1.ListUserRefreshTokensRes), nil
}
func decodeListUserRefreshTokensRequest(_ context.Context, grpcReq any) (any, error) {
req := grpcReq.(*grpcTokenV1.ListUserRefreshTokensReq)
return listUserRefreshTokensReq{userID: req.GetUserId()}, nil
}
func encodeListUserRefreshTokensResponse(_ context.Context, grpcRes any) (any, error) {
res := grpcRes.(listUserRefreshTokensRes)
refreshTokens := make([]*grpcTokenV1.RefreshToken, len(res.refreshTokens))
for i, refreshToken := range res.refreshTokens {
refreshTokens[i] = &grpcTokenV1.RefreshToken{
Id: refreshToken.ID,
Description: refreshToken.Description,
}
}
return &grpcTokenV1.ListUserRefreshTokensRes{
RefreshTokens: refreshTokens,
}, nil
}
-24
View File
@@ -1,24 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package token_test
import (
"os"
"testing"
"github.com/absmach/supermq/auth/mocks"
)
var svc *mocks.Service
func TestMain(m *testing.M) {
svc = new(mocks.Service)
server := startGRPCServer(svc, port)
code := m.Run()
server.GracefulStop()
os.Exit(code)
}
+5 -4
View File
@@ -6,10 +6,10 @@ package grpc
import (
"fmt"
apiutil "github.com/absmach/supermq/api/http/util"
"github.com/absmach/supermq/auth"
"github.com/absmach/supermq/pkg/errors"
svcerr "github.com/absmach/supermq/pkg/errors/service"
apiutil "github.com/absmach/magistrala/api/http/util"
"github.com/absmach/magistrala/auth"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
@@ -31,6 +31,7 @@ func EncodeError(err error) error {
return status.Error(codes.InvalidArgument, err.Error())
case errors.Contains(err, svcerr.ErrAuthentication),
errors.Contains(err, auth.ErrKeyExpired),
errors.Contains(err, auth.ErrRevokedToken),
err == apiutil.ErrMissingEmail,
err == apiutil.ErrBearerToken:
return status.Error(codes.Unauthenticated, err.Error())
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"context"
"time"
"github.com/absmach/supermq/auth"
"github.com/absmach/magistrala/auth"
"github.com/go-kit/kit/endpoint"
)
+7 -7
View File
@@ -13,12 +13,12 @@ import (
"testing"
"time"
apiutil "github.com/absmach/supermq/api/http/util"
"github.com/absmach/supermq/auth"
httpapi "github.com/absmach/supermq/auth/api/http"
"github.com/absmach/supermq/auth/mocks"
smqlog "github.com/absmach/supermq/logger"
svcerr "github.com/absmach/supermq/pkg/errors/service"
apiutil "github.com/absmach/magistrala/api/http/util"
"github.com/absmach/magistrala/auth"
httpapi "github.com/absmach/magistrala/auth/api/http"
"github.com/absmach/magistrala/auth/mocks"
mglog "github.com/absmach/magistrala/logger"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
@@ -66,7 +66,7 @@ func (tr testRequest) make() (*http.Response, error) {
func newServer() (*httptest.Server, *mocks.Service) {
svc := new(mocks.Service)
mux := httpapi.MakeHandler(svc, smqlog.NewMock(), "", 900, 60)
mux := httpapi.MakeHandler(svc, mglog.NewMock(), "", 900, 60)
return httptest.NewServer(mux), svc
}
+2 -2
View File
@@ -6,8 +6,8 @@ package keys
import (
"time"
apiutil "github.com/absmach/supermq/api/http/util"
"github.com/absmach/supermq/auth"
apiutil "github.com/absmach/magistrala/api/http/util"
"github.com/absmach/magistrala/auth"
)
type issueKeyReq struct {
+2 -2
View File
@@ -6,8 +6,8 @@ package keys
import (
"testing"
apiutil "github.com/absmach/supermq/api/http/util"
"github.com/absmach/supermq/auth"
apiutil "github.com/absmach/magistrala/api/http/util"
"github.com/absmach/magistrala/auth"
"github.com/stretchr/testify/assert"
)
+6 -6
View File
@@ -9,15 +9,15 @@ import (
"net/http"
"time"
"github.com/absmach/supermq"
"github.com/absmach/supermq/auth"
"github.com/absmach/magistrala"
"github.com/absmach/magistrala/auth"
)
var (
_ supermq.Response = (*issueKeyRes)(nil)
_ supermq.Response = (*revokeKeyRes)(nil)
_ supermq.Response = (*retrieveKeyRes)(nil)
_ supermq.Response = (*retrieveJWKSRes)(nil)
_ magistrala.Response = (*issueKeyRes)(nil)
_ magistrala.Response = (*revokeKeyRes)(nil)
_ magistrala.Response = (*retrieveKeyRes)(nil)
_ magistrala.Response = (*retrieveJWKSRes)(nil)
)
type issueKeyRes struct {
+4 -4
View File
@@ -10,10 +10,10 @@ import (
"net/http"
"strings"
api "github.com/absmach/supermq/api/http"
apiutil "github.com/absmach/supermq/api/http/util"
"github.com/absmach/supermq/auth"
"github.com/absmach/supermq/pkg/errors"
api "github.com/absmach/magistrala/api/http"
apiutil "github.com/absmach/magistrala/api/http/util"
"github.com/absmach/magistrala/auth"
"github.com/absmach/magistrala/pkg/errors"
"github.com/go-chi/chi/v5"
kithttp "github.com/go-kit/kit/transport/http"
)
+1 -1
View File
@@ -6,7 +6,7 @@ package pats
import (
"context"
"github.com/absmach/supermq/auth"
"github.com/absmach/magistrala/auth"
"github.com/go-kit/kit/endpoint"
)
+3 -3
View File
@@ -8,9 +8,9 @@ import (
"strings"
"time"
apiutil "github.com/absmach/supermq/api/http/util"
"github.com/absmach/supermq/auth"
"github.com/absmach/supermq/pkg/errors"
apiutil "github.com/absmach/magistrala/api/http/util"
"github.com/absmach/magistrala/auth"
"github.com/absmach/magistrala/pkg/errors"
)
type createPatReq struct {
+10 -10
View File
@@ -8,8 +8,8 @@ import (
"testing"
"time"
apiutil "github.com/absmach/supermq/api/http/util"
"github.com/absmach/supermq/auth"
apiutil "github.com/absmach/magistrala/api/http/util"
"github.com/absmach/magistrala/auth"
"github.com/stretchr/testify/assert"
)
@@ -508,17 +508,17 @@ func TestClearAllPATReqValidate(t *testing.T) {
func TestAddScopeReqValidate(t *testing.T) {
validScope := auth.Scope{
OptionalDomainID: "domain1",
EntityType: auth.GroupsType,
EntityID: "entity1",
Operation: auth.CreateOp,
DomainID: "domain1",
EntityType: auth.GroupsType,
EntityID: "entity1",
Operation: "create",
}
invalidScope := auth.Scope{
OptionalDomainID: "",
EntityType: auth.GroupsType,
EntityID: "",
Operation: auth.CreateOp,
DomainID: "",
EntityType: auth.GroupsType,
EntityID: "",
Operation: "view",
}
cases := []struct {
+11 -11
View File
@@ -6,20 +6,20 @@ package pats
import (
"net/http"
"github.com/absmach/supermq"
"github.com/absmach/supermq/auth"
"github.com/absmach/magistrala"
"github.com/absmach/magistrala/auth"
)
var (
_ supermq.Response = (*createPatRes)(nil)
_ supermq.Response = (*retrievePatRes)(nil)
_ supermq.Response = (*updatePatNameRes)(nil)
_ supermq.Response = (*updatePatDescriptionRes)(nil)
_ supermq.Response = (*deletePatRes)(nil)
_ supermq.Response = (*resetPatSecretRes)(nil)
_ supermq.Response = (*revokePatSecretRes)(nil)
_ supermq.Response = (*scopeRes)(nil)
_ supermq.Response = (*clearAllRes)(nil)
_ magistrala.Response = (*createPatRes)(nil)
_ magistrala.Response = (*retrievePatRes)(nil)
_ magistrala.Response = (*updatePatNameRes)(nil)
_ magistrala.Response = (*updatePatDescriptionRes)(nil)
_ magistrala.Response = (*deletePatRes)(nil)
_ magistrala.Response = (*resetPatSecretRes)(nil)
_ magistrala.Response = (*revokePatSecretRes)(nil)
_ magistrala.Response = (*scopeRes)(nil)
_ magistrala.Response = (*clearAllRes)(nil)
)
type createPatRes struct {
+4 -4
View File
@@ -10,10 +10,10 @@ import (
"net/http"
"strings"
api "github.com/absmach/supermq/api/http"
apiutil "github.com/absmach/supermq/api/http/util"
"github.com/absmach/supermq/auth"
"github.com/absmach/supermq/pkg/errors"
api "github.com/absmach/magistrala/api/http"
apiutil "github.com/absmach/magistrala/api/http/util"
"github.com/absmach/magistrala/auth"
"github.com/absmach/magistrala/pkg/errors"
"github.com/go-chi/chi/v5"
kithttp "github.com/go-kit/kit/transport/http"
)
+5 -5
View File
@@ -6,10 +6,10 @@ import (
"log/slog"
"net/http"
"github.com/absmach/supermq"
"github.com/absmach/supermq/auth"
"github.com/absmach/supermq/auth/api/http/keys"
"github.com/absmach/supermq/auth/api/http/pats"
"github.com/absmach/magistrala"
"github.com/absmach/magistrala/auth"
"github.com/absmach/magistrala/auth/api/http/keys"
"github.com/absmach/magistrala/auth/api/http/pats"
"github.com/go-chi/chi/v5"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
@@ -21,7 +21,7 @@ func MakeHandler(svc auth.Service, logger *slog.Logger, instanceID string, jwksC
mux = keys.MakeHandler(svc, mux, logger, jwksCacheMaxAge, jwksCacheStaleWhileRevalidate)
mux = pats.MakeHandler(svc, mux, logger)
mux.Get("/health", supermq.Health("auth", instanceID))
mux.Get("/health", magistrala.Health("auth", instanceID))
mux.Handle("/metrics", promhttp.Handler())
return mux
+2
View File
@@ -1,4 +1,6 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
// Package cache contains the domain concept definitions needed to
// support Magistrala auth cache service functionality.
package cache
+9 -9
View File
@@ -8,9 +8,9 @@ import (
"fmt"
"time"
"github.com/absmach/supermq/auth"
"github.com/absmach/supermq/pkg/errors"
repoerr "github.com/absmach/supermq/pkg/errors/repository"
"github.com/absmach/magistrala/auth"
"github.com/absmach/magistrala/pkg/errors"
repoerr "github.com/absmach/magistrala/pkg/errors/repository"
"github.com/redis/go-redis/v9"
)
@@ -28,7 +28,7 @@ func NewPatsCache(client *redis.Client, duration time.Duration) auth.Cache {
func (pc *patCache) Save(ctx context.Context, userID string, scopes []auth.Scope) error {
for _, sc := range scopes {
key := generateKey(userID, sc.PatID, sc.OptionalDomainID, sc.EntityType, sc.Operation, sc.EntityID)
key := generateKey(userID, sc.PatID, sc.DomainID, sc.EntityType, sc.Operation, sc.EntityID)
if err := pc.client.Set(ctx, key, sc.ID, pc.duration).Err(); err != nil {
return errors.Wrap(repoerr.ErrCreateEntity, err)
}
@@ -37,9 +37,9 @@ func (pc *patCache) Save(ctx context.Context, userID string, scopes []auth.Scope
return nil
}
func (pc *patCache) CheckScope(ctx context.Context, userID, patID, optionalDomainID string, entityType auth.EntityType, operation auth.Operation, entityID string) bool {
exactKey := fmt.Sprintf("pat:%s:%s:%s:%s:%s:%s", userID, patID, entityType, optionalDomainID, operation, entityID)
wildcardKey := fmt.Sprintf("pat:%s:%s:%s:%s:%s:*", userID, patID, entityType, operation, operation)
func (pc *patCache) CheckScope(ctx context.Context, userID, patID, domainID string, entityType auth.EntityType, operation string, entityID string) bool {
exactKey := fmt.Sprintf("pat:%s:%s:%s:%s:%s:%s", userID, patID, entityType, domainID, operation, entityID)
wildcardKey := fmt.Sprintf("pat:%s:%s:%s:%s:%s:*", userID, patID, entityType, domainID, operation)
res, err := pc.client.Exists(ctx, exactKey, wildcardKey).Result()
if err != nil {
@@ -115,6 +115,6 @@ func (pc *patCache) RemoveAllScope(ctx context.Context, userID, patID string) er
return nil
}
func generateKey(userID, patID, optionalDomainId string, entityType auth.EntityType, operation auth.Operation, entityID string) string {
return fmt.Sprintf("pat:%s:%s:%s:%s:%s:%s", userID, patID, entityType, optionalDomainId, operation, entityID)
func generateKey(userID, patID, domainId string, entityType auth.EntityType, operation string, entityID string) string {
return fmt.Sprintf("pat:%s:%s:%s:%s:%s:%s", userID, patID, entityType, domainId, operation, entityID)
}
+124
View File
@@ -0,0 +1,124 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cache
import (
"context"
"strconv"
"time"
"github.com/absmach/magistrala/auth"
"github.com/redis/go-redis/v9"
)
const (
refreshPrefix = "refresh_tokens:"
scoreNegInf = "-inf"
scorePosInf = "+inf"
)
var _ auth.UserActiveTokensCache = (*tokensCache)(nil)
type tokensCache struct {
client *redis.Client
}
// NewUserActiveTokensCache returns redis auth cache implementation.
func NewUserActiveTokensCache(client *redis.Client) (auth.UserActiveTokensCache, error) {
return &tokensCache{client: client}, nil
}
// SaveActive saves an active refresh token ID for a user with optional description.
func (tc *tokensCache) SaveActive(ctx context.Context, userID, tokenID, description string, expiry time.Time) error {
ttl := time.Until(expiry)
pipe := tc.client.TxPipeline()
pipe.Set(ctx, tokenKey(tokenID), description, ttl)
pipe.ZAdd(ctx, userTokensKey(userID), redis.Z{
Score: float64(expiry.Unix()),
Member: tokenID,
})
_, err := pipe.Exec(ctx)
return err
}
// IsActive checks if the token ID is active for the given user.
func (tc *tokensCache) IsActive(ctx context.Context, tokenID string) (bool, error) {
count, err := tc.client.Exists(ctx, tokenKey(tokenID)).Result()
if err != nil {
return false, err
}
return count > 0, nil
}
// ListUserTokens lists all active refresh token IDs with descriptions for a user.
func (tc *tokensCache) ListUserTokens(ctx context.Context, userID string) ([]auth.TokenInfo, error) {
key := userTokensKey(userID)
now := strconv.FormatInt(time.Now().Unix(), 10)
pipe := tc.client.TxPipeline()
pipe.ZRemRangeByScore(ctx, key, scoreNegInf, now)
zrangeCmd := pipe.ZRangeByScore(ctx, key, &redis.ZRangeBy{Min: "(" + now, Max: scorePosInf})
if _, err := pipe.Exec(ctx); err != nil && err != redis.Nil {
return nil, err
}
tokenIDs, err := zrangeCmd.Result()
if err != nil {
return nil, err
}
if len(tokenIDs) == 0 {
return nil, nil
}
getPipe := tc.client.Pipeline()
getCmds := make([]*redis.StringCmd, len(tokenIDs))
for i, tokenID := range tokenIDs {
getCmds[i] = getPipe.Get(ctx, tokenKey(tokenID))
}
if _, err = getPipe.Exec(ctx); err != nil && err != redis.Nil {
return nil, err
}
valid := make([]auth.TokenInfo, 0, len(tokenIDs))
for i, cmd := range getCmds {
description, err := cmd.Result()
if err == redis.Nil {
continue
}
if err != nil {
return nil, err
}
valid = append(valid, auth.TokenInfo{
ID: tokenIDs[i],
Description: description,
})
}
return valid, nil
}
// RemoveActive removes an active refresh token ID for a user.
func (tc *tokensCache) RemoveActive(ctx context.Context, userID, tokenID string) error {
pipe := tc.client.TxPipeline()
pipe.Del(ctx, tokenKey(tokenID))
pipe.ZRem(ctx, userTokensKey(userID), tokenID)
_, err := pipe.Exec(ctx)
return err
}
func tokenKey(tokenID string) string {
return refreshPrefix + "token:" + tokenID
}
func userTokensKey(userID string) string {
return refreshPrefix + "user_tokens:" + userID
}
+288
View File
@@ -0,0 +1,288 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cache_test
import (
"context"
"fmt"
"os"
"testing"
"time"
"github.com/absmach/magistrala/auth"
"github.com/absmach/magistrala/auth/cache"
"github.com/absmach/magistrala/pkg/errors"
"github.com/absmach/magistrala/pkg/testsutil"
"github.com/redis/go-redis/v9"
"github.com/stretchr/testify/assert"
)
var (
storeClient *redis.Client
storeURL string
)
func TestMain(m *testing.M) {
code := testsutil.RunRedisTest(m, &storeClient, &storeURL)
os.Exit(code)
}
func setupRedisTokensClient() auth.UserActiveTokensCache {
tc, err := cache.NewUserActiveTokensCache(storeClient)
if err != nil {
panic(err)
}
return tc
}
func TestTokenSave(t *testing.T) {
storeClient.FlushAll(context.Background())
tokensCache := setupRedisTokensClient()
userID := testsutil.GenerateUUID(t)
tokenID := testsutil.GenerateUUID(t)
cases := []struct {
desc string
userID string
tokenID string
description string
expiry time.Time
err error
}{
{
desc: "Save active token",
userID: userID,
tokenID: tokenID,
description: "Test token",
expiry: time.Now().Add(10 * time.Minute),
err: nil,
},
{
desc: "Save already cached token",
userID: userID,
tokenID: tokenID,
description: "Updated token",
expiry: time.Now().Add(10 * time.Minute),
err: nil,
},
{
desc: "Save another token for same user",
userID: userID,
tokenID: testsutil.GenerateUUID(t),
description: "Another token",
expiry: time.Now().Add(10 * time.Minute),
err: nil,
},
{
desc: "Save token with empty id",
userID: userID,
tokenID: "",
description: "Empty ID token",
expiry: time.Now().Add(10 * time.Minute),
err: nil,
},
{
desc: "Save token with empty description",
userID: userID,
tokenID: testsutil.GenerateUUID(t),
description: "",
expiry: time.Now().Add(10 * time.Minute),
err: nil,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
err := tokensCache.SaveActive(context.Background(), tc.userID, tc.tokenID, tc.description, tc.expiry)
if err == nil {
ok, err := tokensCache.IsActive(context.Background(), tc.tokenID)
assert.NoError(t, err)
assert.True(t, ok)
}
assert.True(t, errors.Contains(err, tc.err))
})
}
}
func TestTokenContains(t *testing.T) {
storeClient.FlushAll(context.Background())
tokensCache := setupRedisTokensClient()
userID := testsutil.GenerateUUID(t)
tokenID := testsutil.GenerateUUID(t)
err := tokensCache.SaveActive(context.Background(), userID, tokenID, "Test token", time.Now().Add(10*time.Minute))
assert.Nil(t, err, fmt.Sprintf("Unexpected error while trying to save: %s", err))
cases := []struct {
desc string
userID string
tokenID string
ok bool
}{
{
desc: "IsActive for existing token",
userID: userID,
tokenID: tokenID,
ok: true,
},
{
desc: "IsActive for non existing token",
userID: userID,
tokenID: testsutil.GenerateUUID(t),
},
{
desc: "IsActive with empty token id",
userID: userID,
tokenID: "",
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
ok, err := tokensCache.IsActive(context.Background(), tc.tokenID)
if tc.ok {
assert.NoError(t, err)
}
assert.Equal(t, tc.ok, ok)
})
}
}
func TestTokenRemove(t *testing.T) {
storeClient.FlushAll(context.Background())
tokensCache := setupRedisTokensClient()
userID := testsutil.GenerateUUID(t)
num := 10
var tokenIDs []string
for i := range num {
tokenID := testsutil.GenerateUUID(t)
err := tokensCache.SaveActive(context.Background(), userID, tokenID, fmt.Sprintf("Token %d", i), time.Now().Add(10*time.Minute))
assert.Nil(t, err, fmt.Sprintf("Unexpected error while trying to save: %s", err))
tokenIDs = append(tokenIDs, tokenID)
}
cases := []struct {
desc string
userID string
tokenID string
err error
}{
{
desc: "Remove an existing token from cache",
userID: userID,
tokenID: tokenIDs[0],
err: nil,
},
{
desc: "Remove token with empty id from cache",
userID: userID,
tokenID: "",
err: nil,
},
{
desc: "Remove non existing id from cache",
userID: userID,
tokenID: testsutil.GenerateUUID(t),
err: nil,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
err := tokensCache.RemoveActive(context.Background(), tc.userID, tc.tokenID)
assert.True(t, errors.Contains(err, tc.err))
if err == nil {
ok, err := tokensCache.IsActive(context.Background(), tc.tokenID)
assert.NoError(t, err)
assert.False(t, ok)
}
})
}
}
func TestListUserTokens(t *testing.T) {
storeClient.FlushAll(context.Background())
tokensCache := setupRedisTokensClient()
userID := testsutil.GenerateUUID(t)
userID2 := testsutil.GenerateUUID(t)
num := 5
var expectedTokens []auth.TokenInfo
for i := range num {
tokenID := testsutil.GenerateUUID(t)
description := fmt.Sprintf("Token %d", i)
err := tokensCache.SaveActive(context.Background(), userID, tokenID, description, time.Now().Add(10*time.Minute))
assert.Nil(t, err, fmt.Sprintf("Unexpected error while trying to save: %s", err))
expectedTokens = append(expectedTokens, auth.TokenInfo{
ID: tokenID,
Description: description,
})
}
tokenID2 := testsutil.GenerateUUID(t)
desc2 := "User 2 token"
err := tokensCache.SaveActive(context.Background(), userID2, tokenID2, desc2, time.Now().Add(10*time.Minute))
assert.Nil(t, err, fmt.Sprintf("Unexpected error while trying to save: %s", err))
cases := []struct {
desc string
userID string
expectedCount int
expectedTokens []auth.TokenInfo
err error
}{
{
desc: "List all tokens for user with multiple tokens",
userID: userID,
expectedCount: num,
expectedTokens: expectedTokens,
err: nil,
},
{
desc: "List tokens for user with single token",
userID: userID2,
expectedCount: 1,
expectedTokens: []auth.TokenInfo{{ID: tokenID2, Description: desc2}},
err: nil,
},
{
desc: "List tokens for user with no tokens",
userID: testsutil.GenerateUUID(t),
expectedCount: 0,
expectedTokens: nil,
err: nil,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
tokens, err := tokensCache.ListUserTokens(context.Background(), tc.userID)
assert.True(t, errors.Contains(err, tc.err))
assert.Equal(t, tc.expectedCount, len(tokens))
if tc.expectedTokens != nil {
assert.ElementsMatch(t, tc.expectedTokens, tokens)
}
})
}
t.Run("Cleanup expired tokens from list", func(t *testing.T) {
// Remove one token directly from Redis to simulate expiration
err := tokensCache.RemoveActive(context.Background(), userID, expectedTokens[0].ID)
assert.NoError(t, err)
// List should now return only valid tokens
tokens, err := tokensCache.ListUserTokens(context.Background(), userID)
assert.NoError(t, err)
assert.Equal(t, num-1, len(tokens))
// Check that the removed token is not in the list
for _, token := range tokens {
assert.NotEqual(t, expectedTokens[0].ID, token.ID)
}
})
}
+1 -1
View File
@@ -2,5 +2,5 @@
// SPDX-License-Identifier: Apache-2.0
// Package hasher contains the domain concept definitions needed to
// support Supermq users password hasher sub-service functionality.
// support Magistrala users password hasher sub-service functionality.
package hasher
+2 -2
View File
@@ -9,8 +9,8 @@ import (
"fmt"
"strings"
"github.com/absmach/supermq/auth"
"github.com/absmach/supermq/pkg/errors"
"github.com/absmach/magistrala/auth"
"github.com/absmach/magistrala/pkg/errors"
"golang.org/x/crypto/scrypt"
)
+26 -1
View File
@@ -5,13 +5,16 @@ package auth
import (
"context"
"errors"
"time"
"github.com/absmach/magistrala/pkg/errors"
)
var (
ErrUnsupportedKeyAlgorithm = errors.New("unsupported key algorithm")
ErrInvalidSymmetricKey = errors.New("invalid symmetric key")
ErrPublicKeysNotSupported = errors.New("public keys not supported for symmetric algorithm")
ErrRevokedToken = errors.NewAuthNError("token is revoked")
)
// PublicKeyInfo represents a public key for external distribution via JWKS.
@@ -33,6 +36,7 @@ type PublicKeyInfo struct {
// Implementations manage underlying cryptographic operations and key distribution.
type Tokenizer interface {
// Issue creates a signed token string from the given key claims.
// For RefreshKey types, the token ID is stored as active in the cache.
Issue(key Key) (token string, err error)
// Parse verifies and parses a token string (JWT or PAT), returning the extracted claims.
@@ -45,6 +49,27 @@ type Tokenizer interface {
RetrieveJWKS() ([]PublicKeyInfo, error)
}
// UserActiveTokensCache represents a cache repository for managing active refresh tokens per user.
type UserActiveTokensCache interface {
// SaveActive saves an active refresh token ID for a user with optional description.
SaveActive(ctx context.Context, userID, tokenID, description string, expiry time.Time) error
// IsActive checks if the token ID is active.
IsActive(ctx context.Context, tokenID string) (bool, error)
// ListUserTokens lists all active token IDs with descriptions for a given user.
ListUserTokens(ctx context.Context, userID string) ([]TokenInfo, error)
// RemoveActive removes an active refresh token ID.
RemoveActive(ctx context.Context, userID, tokenID string) error
}
// TokenInfo represents information about an active refresh token.
type TokenInfo struct {
ID string `json:"id"`
Description string `json:"description,omitempty"`
}
// IsSymmetricAlgorithm determines if the given algorithm is symmetric (HMAC-based).
// Returns true for HMAC algorithms (HS256, HS384, HS512).
// Returns false for asymmetric algorithms (EdDSA).
+9 -8
View File
@@ -81,14 +81,15 @@ func (r Role) Validate() bool {
// 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
Role Role `json:"role,omitempty"`
IssuedAt time.Time `json:"issued_at,omitempty"`
ExpiresAt time.Time `json:"expires_at,omitempty"`
Verified bool `json:"verified,omitempty"`
ID string `json:"id,omitempty"`
Type KeyType `json:"type,omitempty"`
Issuer string `json:"issuer,omitempty"`
Subject string `json:"subject,omitempty"` // user ID
Role Role `json:"role,omitempty"`
IssuedAt time.Time `json:"issued_at,omitempty"`
ExpiresAt time.Time `json:"expires_at,omitempty"`
Verified bool `json:"verified,omitempty"`
Description string `json:"description,omitempty"` // Optional description for refresh tokens
}
func (key Key) String() string {

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