Compare commits

...

380 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
dusan bf7a965195 NOISSUE - Update license file
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-12-31 10:52:10 +01:00
Felix Gateru 67c28ff134 SMQ-2800 - Add WebSocket support to HTTP adapter (#2937)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
Signed-off-by: Arvindh <arvindh91@gmail.com>
Co-authored-by: Arvindh <arvindh91@gmail.com>
2025-12-31 10:43:52 +01:00
Arvindh a526a2ccd5 NOISSUE - Add internal type to find NestError and Add Auth key algorithm to journal docker compose (#3304)
Signed-off-by: Arvindh <arvindh91@gmail.com>
2025-12-30 16:20:35 +01:00
dependabot[bot] c679224596 NOISSUE - Bump google.golang.org/grpc from 1.77.0 to 1.78.0 (#3306)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-29 12:11:18 +01:00
dependabot[bot] e1c881d2ad NOISSUE - Bump github.com/jackc/pgx/v5 from 5.7.6 to 5.8.0 (#3305)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-29 11:38:25 +01:00
dusan 9a0d8062be NOISSUE - Add make_stable target
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-12-29 10:40:08 +01:00
dusan 25d8b86f2b Revert "NOISSUE - Use fixed version in default Docker config"
This reverts commit 24ca513eff.

We are going to stick with the latest for dev env.
2025-12-29 09:40:56 +01:00
dusan 24ca513eff NOISSUE - Use fixed version in default Docker config
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-12-29 09:32:55 +01:00
Dušan Borovčanin 52510d8c62 NOISSUE - Improve JWKS (#3301)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-12-26 18:15:12 +01:00
Dušan Borovčanin 6b6bab79c6 NOISSUE - Update Auth service tests (#3300)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-12-24 18:44:26 +01:00
Felix Gateru 6a5d28c65a SMQ-1672 - Add asymmetric key authentication (#3228)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-12-23 21:16:06 +01:00
Felix Gateru 59f8d4e4d7 NOISSUE : Revert removal of errors Unwrap function (#3299)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-12-23 15:37:51 +01:00
Felix Gateru e23555ee2a SMQ-3036 - Add events tests for channels,clients, domains and groups (#3279)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-12-23 12:18:39 +01:00
Felix Gateru cb337a38fd SMQ-3036 - Add nested mocks and generated proto files to ignore in codecov.yaml (#3280)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-12-23 12:17:38 +01:00
Felix Gateru f9b503f1d6 SMQ-3125 - Add ordering tests (#3297)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-12-22 15:01:57 +01:00
Steve Munene 0fe5a6d6e8 SMQ-2632 - Remove PAT logics from middleware (#3291)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2025-12-22 11:10:16 +01:00
dependabot[bot] f612109f24 NOISSUE - Bump github.com/nats-io/nats.go from 1.47.0 to 1.48.0 (#3296)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-22 08:48:27 +01:00
Arvindh 3fcf2e5369 SMQ-1744 - Error handling with TypedError created on top existing Error (#3170)
Signed-off-by: Arvindh <arvindh91@gmail.com>
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
Co-authored-by: Felix Gateru <felix.gateru@gmail.com>
2025-12-22 08:31:52 +01:00
Steve Munene 1355bc8bb7 SMQ-2757 - Combine Authorization and AuthorizationPAT to single gRPC endpoint and combine service functions (#3292)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2025-12-19 17:51:06 +01:00
Veddy 1e7e65d642 SMQ-3290 - Fix the bug that groups queries too slowly at multiple levels (#3293)
Signed-off-by: Veddy <veddy@qq.com>
Co-authored-by: veddy <veddy@qq.com>
2025-12-18 09:47:36 +01:00
Steve Munene 3a5c1e12df NOISSUE - New operation permission (#3281)
Signed-off-by: Arvindh <arvindh91@gmail.com>
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
Co-authored-by: Arvindh <arvindh91@gmail.com>
2025-12-17 14:29:28 +01:00
dependabot[bot] 61b95a28c2 NOISSUE - Bump google.golang.org/protobuf from 1.36.10 to 1.36.11 (#3288)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-17 13:10:41 +01:00
dependabot[bot] 4c40b8b82c NOISSUE - Bump github.com/authzed/spicedb from 1.47.1 to 1.48.0 (#3289)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-17 13:10:05 +01:00
dependabot[bot] 955c556fe6 NOISSUE - Bump go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp from 0.63.0 to 0.64.0 (#3283)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 18:40:45 +01:00
dependabot[bot] dc437a8296 NOISSUE - Bump go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp from 1.38.0 to 1.39.0 (#3284)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 18:38:18 +01:00
dependabot[bot] 314537f7c5 NOISSUE - Bump go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc from 0.63.0 to 0.64.0 (#3286)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 18:36:43 +01:00
dependabot[bot] 7e5fd0cfa8 NOISSUE - Bump github.com/pion/dtls/v3 from 3.0.8 to 3.0.9 (#3287)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 17:25:45 +01:00
dependabot[bot] 6a2c8a3ca6 NOISSUE - Bump the gh-dependency group in /.github/workflows with 2 updates (#3285)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 17:21:26 +01:00
dependabot[bot] 2bea4412d8 NOISSUE - Bump golang.org/x/crypto from 0.45.0 to 0.46.0 (#3282)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 17:20:51 +01:00
dusan c8cb0daa6c NOISSUE - Update Go version detection
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-12-09 12:28:25 +01:00
dusan f8017c8b9f NOISSUE - Update Go version
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-12-09 12:18:01 +01:00
dependabot[bot] 27fc32c153 NOISSUE - Bump golang from 1.25.4-alpine3.22 to 1.25.5-alpine3.22 in /docker in the docker-dependency group (#3271)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-09 12:11:37 +01:00
dependabot[bot] 9aa9487207 NOISSUE - Bump golang.org/x/oauth2 from 0.33.0 to 0.34.0 (#3276)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-09 12:11:08 +01:00
dependabot[bot] 1292095cdb NOISSUE - Bump github.com/pion/dtls/v3 from 3.0.7 to 3.0.8 (#3273)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-09 12:06:04 +01:00
dependabot[bot] 856ef1ba49 NOISSUE - Bump github.com/spf13/cobra from 1.10.1 to 1.10.2 (#3272)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-09 12:04:25 +01:00
dependabot[bot] 146028fb98 NOISSUE - Bump golang.org/x/sync from 0.18.0 to 0.19.0 (#3277)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-09 12:01:20 +01:00
dependabot[bot] 6cb3e635c9 NOISSUE - Bump go.opentelemetry.io/otel/exporters/otlp/otlptrace from 1.38.0 to 1.39.0 (#3278)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-08 22:02:00 +01:00
dependabot[bot] 175d27c4b6 NOISSUE - Bump the gh-dependency group in /.github/workflows with 2 updates (#3274)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-08 18:44:39 +01:00
Arvindh eec6b8be07 NOISSUE - Fix migrations error (#3275)
Signed-off-by: Arvindh <arvindh91@gmail.com>
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
Co-authored-by: Felix Gateru <felix.gateru@gmail.com>
2025-12-08 18:43:51 +01:00
Dušan Borovčanin e48e5dee1f NOISSUE - Improve CI (#3270)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-12-08 10:12:12 +01:00
Dušan Borovčanin 0df8e8451c NOISSUE - Make CI scripts run in parallel (#3269)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-12-02 22:58:23 +01:00
dependabot[bot] e77e3a3bb6 NOISSUE - Bump github.com/redis/go-redis/v9 from 9.17.1 to 9.17.2 (#3268)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-02 01:37:53 +01:00
Dušan Borovčanin 3e6b771850 NOISSUE - Improve Swagger GH actions (#3267)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-12-02 00:13:42 +01:00
Nataly Musilah 15e756a5a3 SMQ-3026 - Update READMEs and make them use the same l&f (#3239)
Signed-off-by: Musilah <nataleigh.nk@gmail.com>
2025-12-01 18:52:53 +01:00
Steve Munene c5a4336d43 SMQ-3094 - Improve test coverage in channels and journals (#3238)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2025-12-01 18:15:57 +01:00
Felix Gateru b05ae65e24 SMQ-3095 - Improve test coverage in clients repository (#3156)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-12-01 17:57:43 +01:00
Felix Gateru 1a8d11acdd SMQ-3095 - Add users events tests (#3240)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-12-01 17:51:24 +01:00
Steve Munene 27b72db52e SMQ-3233 - Move callout to seperate middleware (#3244)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2025-12-01 17:40:49 +01:00
dependabot[bot] e75ce59998 NOISSUE - Bump github.com/redis/go-redis/v9 from 9.17.0 to 9.17.1 (#3263)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 17:13:36 +01:00
Felix Gateru cd281c2589 SMQ-2799 - Add support for basic auth for HTTP and WS adapters (#3049)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-12-01 16:51:49 +01:00
Felix Gateru 9d13d5b528 SMQ-3224 - Add consistent error for assigning channel and client with parent group to parent group (#3225)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-12-01 16:32:58 +01:00
Felix Gateru f7dcaa949b SMQ-2997 - Allow listing root groups with groups that the user has access to (#3226)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-12-01 14:15:31 +01:00
dusan fa080ab0f8 NOISSUE - Add DeepWiki link
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-11-29 14:08:35 +01:00
dusan 5807cf1754 NOISSUE - Add HTTP server timeouts
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-11-28 18:21:25 +01:00
dusan f96ddab9dd NOISSUE - Update Abstract Machines link
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-11-28 15:34:19 +01:00
Steve Munene 914d491a13 NOISSUE - Update search in CLI (#3261)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2025-11-28 15:31:21 +01:00
Washington Kigani Kamadi 843a0cae1f SMQ-3234 - Add notifications service (#3254)
Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>
Signed-off-by: dusan <borovcanindusan1@gmail.com>
Signed-off-by: Arvindh <arvindh91@gmail.com>
Co-authored-by: Arvindh <arvindh91@gmail.com>
Co-authored-by: dusan <borovcanindusan1@gmail.com>
2025-11-28 15:26:55 +01:00
Arvindh 9ba9a12084 NOISSUE - Enable oAuth users to change and reset password (#3259)
Signed-off-by: Arvindh <arvindh91@gmail.com>
2025-11-27 18:02:57 +01:00
Steve Munene 5ed6b258a0 NOISSUE - Update health sdk (#3256)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2025-11-26 15:39:34 +01:00
Steve Munene eb83edbcde SMQ-3253 - Update CLI usage (#3252)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2025-11-25 20:02:23 +01:00
dependabot[bot] 5c12bc8c91 NOISSUE - Bump github.com/plgd-dev/go-coap/v3 from 3.4.0 to 3.4.1 (#3246)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-25 12:44:33 +01:00
dependabot[bot] 589209eae2 NOISSUE - Bump github.com/redis/go-redis/v9 from 9.16.0 to 9.17.0 (#3247)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-25 12:44:00 +01:00
dependabot[bot] a2e660b8a1 NOISSUE - Bump google.golang.org/grpc from 1.76.0 to 1.77.0 (#3249)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-25 12:42:43 +01:00
dependabot[bot] 21731aef37 NOISSUE - Bump github.com/rubenv/sql-migrate from 1.8.0 to 1.8.1 (#3248)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-25 12:42:11 +01:00
dependabot[bot] 2f55947305 NOISSUE - Bump actions/checkout from 5 to 6 in /.github/workflows in the gh-dependency group (#3251)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-25 11:42:34 +01:00
dependabot[bot] 80806c4745 NOISSUE - Bump github.com/authzed/authzed-go from 1.6.0 to 1.7.0 (#3250)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-25 11:20:29 +01:00
dependabot[bot] 1947f6e78e NOISSUE - Bump github.com/authzed/spicedb from 1.47.0 to 1.47.1 (#3245)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-23 22:29:55 +01:00
Dušan Borovčanin 5b0c556b60 NOISSUE - Security fixes (#3243)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-11-20 23:51:23 +01:00
dependabot[bot] 5891e4bb75 NOISSUE - Bump golang.org/x/crypto from 0.44.0 to 0.45.0 (#3242)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-20 10:19:46 +01:00
dependabot[bot] 299742096a NOISSUE - Bump golang.org/x/crypto from 0.43.0 to 0.44.0 (#3236)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-19 09:20:17 +01:00
dependabot[bot] 27c57b192b NOISSUE - Bump golang from 1.25.3-alpine to 1.25.4-alpine in /docker in the docker-dependency group (#3229)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-11 22:06:12 +01:00
dependabot[bot] 8083cec373 NOISSUE - Bump golang.org/x/oauth2 from 0.32.0 to 0.33.0 (#3231)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-11 21:49:12 +01:00
dependabot[bot] e2d9b1ddf9 NOISSUe - Bump golangci/golangci-lint-action from 8 to 9 in /.github/workflows in the gh-dependency group (#3232)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-10 13:56:39 +01:00
dependabot[bot] 6092bc2cf0 NOISSUE - Bump golang.org/x/sync from 0.17.0 to 0.18.0 (#3230)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-10 13:55:45 +01:00
b1ackd0t 071d23a5f0 SMQ-3173 - Use buildx for Multi-Platform Docker Image Support (#3181)
Signed-off-by: Rodney Osodo <socials@rodneyosodo.com>
2025-11-10 13:42:42 +01:00
dependabot[bot] 7bb4b298c5 NOISSUE - Bump github.com/opencontainers/runc from 1.2.3 to 1.2.8 (#3227)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-07 16:09:41 +01:00
dependabot[bot] cac6c648d3 NOISSUE - Bump github.com/gofrs/uuid/v5 from 5.3.2 to 5.4.0 (#3223)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-04 11:07:32 +01:00
dependabot[bot] 4ee7736b32 NOISSUE - Bump github.com/redis/go-redis/v9 from 9.14.1 to 9.16.0 (#3206)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-03 15:18:05 +01:00
dependabot[bot] 8ed8915e4f NOISSUE - Bump github.com/authzed/spicedb from 1.46.0 to 1.47.0 (#3208)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-03 12:40:48 +01:00
Dušan Borovčanin 65c6a4d8f4 NOISSUE - Update mGate version (#3217)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-10-31 16:21:25 +01:00
Sammy Kerata Oina ec223e7467 NOISSUE - Update dependencies in go.mod and go.sum (#3215)
Signed-off-by: Sammy Oina <sammyoina@gmail.com>
2025-10-31 12:47:47 +01:00
Dušan Borovčanin aa3cc3d7ee NOISSUE - Fix API docs (#3212)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-10-30 18:16:29 +01:00
Steve Munene 9650dde716 NOISSUE - Update API docs (#3211)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2025-10-30 17:37:01 +01:00
Arvindh d02747a56f NOISSUE - Fix mqtt adapter target ws server protcol and update mgate version (#3209)
Signed-off-by: Arvindh <arvindh91@gmail.com>
2025-10-29 14:30:23 +01:00
Felix Gateru dc0df1c955 SMQ-3137 - Proxy CoAP using mgate (#2222)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-10-24 17:55:02 +02:00
Steve Munene 64b4497ad4 NOISSUE - Increase NGINX client body size (#3204)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2025-10-22 15:55:37 +02:00
Dušan Borovčanin 1b26264495 NOISSUE - Fix SSO User metadata update (#3203)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-10-22 15:32:55 +02:00
Felix Gateru 69366d77cc SMQ-3171 - Add domain ID to channel authorization request (#3179)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-10-22 12:53:37 +02:00
Washington Kigani Kamadi fa8862cbc8 NOISSUE - Add auth_provider field to sdk (#3202)
Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>
2025-10-22 12:51:38 +02:00
Dušan Borovčanin 15b8901853 NOISSUE - Fix password reset (#3200)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-10-21 19:44:41 +02:00
Dušan Borovčanin 9258237cb6 NOISSUE - Add domain field in domains callouts (#3199)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-10-21 14:31:11 +02:00
Dušan Borovčanin 2adeecd9ec NOISSUE - Update call-home (#3198)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-10-20 20:44:46 +02:00
Dušan Borovčanin c5eee6d8fd NOISSUE - Update dependencies (#3197)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-10-20 16:54:01 +02:00
dependabot[bot] 648edbd386 NOISSUE - Bump github.com/nats-io/nats.go from 1.46.1 to 1.47.0 (#3195)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-20 12:45:33 +02:00
dependabot[bot] 35fb296318 NOISSUE - Bump github.com/redis/go-redis/v9 from 9.14.0 to 9.14.1 (#3196)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-20 12:44:21 +02:00
dependabot[bot] a98777b191 NOISSUE - Bump golang from 1.25.1-alpine to 1.25.3-alpine in /docker in the docker-dependency group (#3194)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-20 12:07:32 +02:00
Dušan Borovčanin 3c693a7b41 NOISSUE - Fix key logging (#3193)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-10-17 15:24:24 +02:00
Dušan Borovčanin c230a24b7d NOISSUE - Use structured requests in callouts (#3191)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-10-17 13:11:20 +02:00
Steve Munene 42b2a8c166 NOISSUE - Close PATs sql rows (#3190)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2025-10-16 16:32:54 +02:00
Dušan Borovčanin 6468ebe749 NOISSUE - Fix Domain creation callout (#3189)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-10-16 15:38:51 +02:00
b1ackd0t 1adbe1ff24 NOISSUE - Enhance docker-compose and Makefile configurations (#3153)
Signed-off-by: Rodney Osodo <socials@rodneyosodo.com>
2025-10-15 14:41:16 +02:00
Arvindh 27995cb093 NOISSUE - Add Auth provider in profile view response (#3187)
Signed-off-by: Arvindh <arvindh91@gmail.com>
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
Co-authored-by: nyagamunene <stevenyaga2014@gmail.com>
2025-10-15 14:17:37 +02:00
dependabot[bot] 5833bafbee NOISSUE - Bump golang.org/x/oauth2 from 0.31.0 to 0.32.0 (#3183)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-15 14:09:44 +02:00
dependabot[bot] 6394908b2c NOISSUE - Bump golang.org/x/crypto from 0.42.0 to 0.43.0 (#3182)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-15 10:27:49 +02:00
dependabot[bot] 0e0598c6d8 NOISSUE - Bump github.com/authzed/spicedb from 1.45.4 to 1.46.0 (#3184)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-15 10:26:21 +02:00
dependabot[bot] 3e400da5ad NOISSUE - Bump google.golang.org/grpc from 1.75.1 to 1.76.0 (#3185)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-15 10:25:56 +02:00
Arvindh 2112281171 NOISSUE - Auto generation username for oauth user during singup (#3178)
Signed-off-by: Arvindh <arvindh91@gmail.com>
2025-10-09 15:19:46 +02:00
Arvindh 6f40c7fa1e NOISSUE - Handle Domain & Channel Route not available error during creation (#3180)
Signed-off-by: Arvindh <arvindh91@gmail.com>
2025-10-09 15:06:06 +02:00
Arvindh b0e9e43b9e NOISSUE - Handle user registration errors (#3177)
Signed-off-by: Arvindh <arvindh91@gmail.com>
2025-10-08 19:56:54 +02:00
Felix Gateru bc7727c275 SMQ-3175 - Fix clearing domain metadata on domain name and tags update (#3176)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-10-08 17:36:03 +02:00
Arvindh 8d1c3c41b5 NOISSUE - Fix OAuth auto verification on register (#3174)
Signed-off-by: Arvindh <arvindh91@gmail.com>
2025-10-07 18:24:23 +02:00
dependabot[bot] d84df8604f NOISSUE - Bump github.com/authzed/authzed-go from 1.5.1-0.20250909211335-16b58d03994c to 1.6.0 (#3168)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-06 11:04:55 +02:00
dependabot[bot] d4d8bc5351 NOISSUE - Bump google.golang.org/protobuf from 1.36.9 to 1.36.10 (#3167)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-06 10:55:26 +02:00
dependabot[bot] ac9bc9aad6 NOISSUE - Bump github.com/nats-io/nats.go from 1.46.0 to 1.46.1 (#3166)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-06 10:48:52 +02:00
dependabot[bot] 4b83301f69 NOISSUE - Bump peter-evans/repository-dispatch from 3 to 4 in /.github/workflows in the gh-dependency group (#3161)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-02 13:18:19 +02:00
Arvindh b746a8679f NOISSUE - Fixing auto verification unverified users flow (#3163)
Signed-off-by: Arvindh <arvindh91@gmail.com>
2025-10-02 13:17:32 +02:00
Arvindh e6022542b9 NOISSUE - Auto verify OAuth user during OAuth Callback (#3162)
Signed-off-by: Arvindh <arvindh91@gmail.com>
2025-10-02 11:14:06 +02:00
Arvindh 6c77e1b738 SMQ-3159 - Return specific error on non-existent user during login (#3160)
Signed-off-by: Arvindh <arvindh91@gmail.com>
2025-10-01 18:51:50 +02:00
Steve Munene 04774ae972 NOISSUE - Remove empty file (#3157)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2025-10-01 11:44:26 +02:00
Steve Munene ae7c93020a SMQ-3028 - Unify SMQ certs with Absmach Certs (#3146)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2025-10-01 11:08:33 +02:00
Felix Gateru b031dc08b8 NOISSUE - Group service middleware into single folder (#2472)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-09-26 13:55:00 +02:00
dependabot[bot] 0465ceb7a3 NOISSUE - Bump github.com/nats-io/nats.go from 1.45.0 to 1.46.0 (#3152)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-25 16:47:52 +02:00
dependabot[bot] af424ee2cb NOISSUE - Bump github.com/authzed/spicedb from 1.45.3 to 1.45.4 (#3150)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-21 19:43:31 +03:00
dependabot[bot] 96a15b32dd NOISSUE - Bump github.com/eclipse/paho.mqtt.golang from 1.5.0 to 1.5.1 (#3151)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-21 19:20:37 +03:00
Felix Gateru 61f1e9aca2 MG-314 - Update API docs related for listing entities (#3149)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-09-18 12:18:00 +02:00
Nataly Musilah 29f7063c15 NOISSUE - Fix Groups and Channels Users Listing (#3138)
Signed-off-by: musilah <nataleigh.nk@gmail.com>
2025-09-18 11:28:40 +02:00
Felix Gateru 1f48a73677 SMQ-2945 - Add channels events consumer (#2951)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-09-16 17:23:01 +02:00
Felix Gateru cd9cb9e1d5 SMQ-2944 - Add client events consumer (#2947)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-09-16 17:21:39 +02:00
dependabot[bot] 8d9e92f228 NOISSUE - Bump google.golang.org/protobuf from 1.36.8 to 1.36.9 (#3142)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-15 12:41:24 +02:00
dependabot[bot] ad685c27ad NOISSUE - Bump github.com/redis/go-redis/v9 from 9.13.0 to 9.14.0 (#3141)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-15 12:24:53 +02:00
dependabot[bot] 44485cacec NOISSUE - Bump google.golang.org/grpc from 1.75.0 to 1.75.1 (#3143)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-15 12:24:13 +02:00
Felix Gateru 7fac6ff4c4 SMQ-2801 - Add health check endpoint with client authentication to CoAP adapter (#3139)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-09-15 12:23:36 +02:00
Felix Gateru 1930a0c8f2 SMQ-2801 - Add health check endpoint to WS adapter (#3144)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-09-15 10:33:39 +02:00
Felix Gateru 9eac9366ba SMQ-2801 - Add health check endpoint to HTTP adapter (#3140)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-09-12 12:14:14 +02:00
Felix Gateru ad191c4609 SMQ-2801 - Add health check endpoint for MQTT adapter (#3024)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-09-12 11:37:29 +02:00
dependabot[bot] 1d935f0519 NOISSUE - Bump golang.org/x/crypto from 0.41.0 to 0.42.0 (#3133)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-09 08:54:25 +02:00
dependabot[bot] bc1ccace4a NOISSUE - Bump github.com/absmach/callhome from 0.14.0 to 0.18.1 (#3134)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-09 08:53:53 +02:00
dependabot[bot] 89fdb4e6c7 NOISSUE - Bump golang.org/x/oauth2 from 0.30.0 to 0.31.0 (#3135)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-09 08:52:42 +02:00
dependabot[bot] 44e44639aa NOISSUE - Bump github.com/jackc/pgx/v5 from 5.7.5 to 5.7.6 (#3136)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-09 08:52:08 +02:00
dependabot[bot] d31c66174e NOISSUE - Bump actions/setup-go from 5 to 6 in /.github/workflows in the gh-dependency group (#3131)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-06 18:05:13 +02:00
dependabot[bot] e6d7a07277 NOISSUE - Bump golang from 1.25.0-alpine to 1.25.1-alpine in /docker in the docker-dependency group (#3127)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-06 18:03:18 +02:00
dependabot[bot] a2ea92a5ba NOISSUE - Bump github.com/prometheus/client_golang from 1.23.0 to 1.23.2 (#3130)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-06 18:01:27 +02:00
dependabot[bot] 3320a716f3 NOISSUE - Bump github.com/redis/go-redis/v9 from 9.12.1 to 9.13.0 (#3128)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-06 18:00:49 +02:00
Felix Gateru a70b838f1c SMQ-2924 - Allow bulk deleting of invitations from repository (#2942)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-09-05 19:26:45 +02:00
Nataly Musilah c50221a042 NOISSUE - Update entity sorting (#3076)
Signed-off-by: Musilah <nataleigh.nk@gmail.com>
Signed-off-by: musilah <nataleigh.nk@gmail.com>
2025-09-05 15:58:03 +02:00
Arvindh 1efa8b5bce NOISSUE - Allow unverified users by default in docker compose (#3124)
Signed-off-by: Arvindh <arvindh91@gmail.com>
2025-09-05 15:40:47 +02:00
Arvindh e57ad79cd4 SMQ-3093 - User email verification (#3101)
Signed-off-by: Arvindh <arvindh91@gmail.com>
2025-09-05 15:23:58 +02:00
Sammy Kerata Oina 22616911d2 NOISSUE - Change email body format from plain text to HTML in Send method (#3118)
Signed-off-by: Sammy Oina <sammyoina@gmail.com>
2025-09-04 19:54:01 +02:00
Steve Munene 766bb5519a SMQ-2275 - Update SDK godocs (#3119)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2025-09-04 11:35:12 +02:00
Steve Munene fbcdef9693 SMQ-3061 - Separate CLI command for Domain and User Invitations (#3117)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2025-09-03 13:00:23 +02:00
dependabot[bot] 9aacde7c5b NOISSUE - Bump go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp from 0.62.0 to 0.63.0 (#3115)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-03 10:43:14 +02:00
dependabot[bot] cdf26051f6 NOISSUE - Bump github.com/openbao/openbao/api/v2 from 2.3.1 to 2.4.0 (#3112)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-03 10:30:12 +02:00
dependabot[bot] a9a412e909 NOISSUE - Bump github.com/spf13/cobra from 1.9.1 to 1.10.1 (#3111)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-03 10:28:43 +02:00
dependabot[bot] 0754fa1126 NOISSUE - Bump go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc from 0.62.0 to 0.63.0 (#3116)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-03 10:28:20 +02:00
Steve Munene ec75f4eadb SMQ-3062 - Update Domain Invitation Deletion Endpoint (#3110)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2025-09-02 10:16:49 +02:00
Washington Kigani Kamadi af35396601 NOISSUE - Obtain email host from env (#3098)
Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>
2025-09-01 15:21:01 +02:00
dependabot[bot] 6a27594751 NOISSUE - Bump go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp from 1.37.0 to 1.38.0 (#3105)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-01 14:52:42 +02:00
dependabot[bot] 555d89d358 NOISSUE - Bump go.opentelemetry.io/otel/exporters/otlp/otlptrace from 1.37.0 to 1.38.0 (#3103)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-01 10:41:50 +02:00
dependabot[bot] c3c9dcf318 NOISSUE - Bump github.com/go-chi/chi/v5 from 5.2.2 to 5.2.3 (#3104)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-01 10:35:19 +02:00
dependabot[bot] 5a75772f62 NOISSUE - Bump go.opentelemetry.io/otel from 1.37.0 to 1.38.0 (#3107)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-01 10:35:01 +02:00
Steve Munene b9ac94f058 SMQ-2495 - Refactor CLI to use entity IDs (#3100)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2025-09-01 10:22:14 +02:00
Felix Gateru 8ab1f4c408 SMQ-2836 - Skip checking super admin if the role in JWT is not super admin (#3099)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-08-29 12:09:31 +02:00
Dušan Borovčanin e842bfaab6 NOISSUE - Update Protobufs (#3091)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-08-26 13:31:08 +02:00
dependabot[bot] 886cd63415 NOISSUE - Bump github.com/stretchr/testify from 1.10.0 to 1.11.0 (#3089)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-26 12:29:54 +02:00
dependabot[bot] 9cd22910d8 NOISSUE - Bump github.com/dgraph-io/ristretto/v2 from 2.2.0 to 2.3.0 (#3090)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-26 12:27:28 +02:00
Felix Gateru 906e365adf NOISSUE - Fix clients listing repository tests (#3088)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-08-26 12:25:57 +02:00
dependabot[bot] 8e7e897906 NOISSUE - Bump github.com/authzed/authzed-go from 1.4.1 to 1.5.0 (#3084)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-26 00:13:39 +02:00
dependabot[bot] 4b50ef93a2 NOISSUE - Bump actions/checkout from 4 to 5 in /.github/workflows in the gh-dependency group (#3080)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-25 23:54:33 +02:00
dependabot[bot] 73c2d76b58 NOISSUE - Bump google.golang.org/grpc from 1.74.2 to 1.75.0 (#3083)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-25 23:53:02 +02:00
dependabot[bot] 473338527a NOISSUE - Bump google.golang.org/protobuf from 1.36.7 to 1.36.8 (#3082)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-25 23:29:09 +02:00
dependabot[bot] 12d1a0de32 NOISSUE - Bump github.com/authzed/spicedb from 1.45.1 to 1.45.3 (#3085)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-25 23:27:48 +02:00
dependabot[bot] b4e0e89c38 NOISSUE - Bump github.com/nats-io/nats.go from 1.44.0 to 1.45.0 (#3086)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-25 23:20:39 +02:00
dependabot[bot] 6f5e535b30 NOISSUE - Bump golang from 1.24.5-alpine to 1.25.0-alpine in /docker in the docker-dependency group (#3081)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-25 23:19:09 +02:00
Dušan Borovčanin fb1062a98a NOISSUE - Fix linters and Mockery (#3087)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-08-25 23:15:38 +02:00
dusan c56a5ae577 NOISSUE - Update Go version
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-08-25 18:37:56 +02:00
Dušan Borovčanin a19cd9c97b NOISSUE - Replace interface{} with any (#3079)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2025-08-25 18:06:41 +02:00
Felix Gateru 0e1a090f16 SMQ-3070 - Fix property based tests (#3078)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-08-25 16:17:19 +02:00
dependabot[bot] ef712443e1 NOISSUE - Bump github.com/go-viper/mapstructure/v2 from 2.3.0 to 2.4.0 (#3077)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-25 13:24:09 +02:00
Smith Jilks 248b708909 NOISSUE - Update callouts client tls config (#3068)
Signed-off-by: Jilks Smith <smithjilks@gmail.com>
2025-08-21 16:44:11 +02:00
Felix Gateru c63c936b36 SMQ-3073 - Enable user messaging through WS and HTTP protocols (#3075)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-08-21 16:10:34 +02:00
Felix Gateru 4927333691 NOISSUE - Update SMQ version in docs (#3072)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-08-20 15:56:54 +02:00
dependabot[bot] 5acc8f96a6 NOISSUE - Bump golang.org/x/crypto from 0.40.0 to 0.41.0 (#3059)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-19 18:28:33 +02:00
dependabot[bot] 9d91740063 NOISSUE - Bump google.golang.org/protobuf from 1.36.6 to 1.36.7 (#3060)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-19 14:06:20 +02:00
dependabot[bot] 1951f206cb NOISSUE - Bump github.com/docker/docker from 27.1.1+incompatible to 28.0.0+incompatible (#3067)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-19 14:00:08 +02:00
dependabot[bot] 441feb8578 NOISSUE - Bump github.com/redis/go-redis/v9 from 9.11.0 to 9.12.1 (#3058)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-19 13:57:48 +02:00
dependabot[bot] 7d11f16988 NOISSUE - Bump github.com/absmach/certs from 0.0.0-20250602111612-89538302ad6a to 0.17.0 (#3057)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-19 13:56:36 +02:00
Nataly Musilah 2e3f52fdbf NOISSUE - Allow sorting (#3052)
Signed-off-by: Musilah <nataleigh.nk@gmail.com>
2025-08-18 14:54:26 +02:00
Felix Gateru b942a42271 SMQ-3053 - Fix listing subgroups for users with subgroup related actions (#3066)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-08-18 09:24:23 +02:00
Steve Munene 0178594c25 SMQ-3056 - Fix exposed secret in MQTT (#3065)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2025-08-18 09:23:01 +02:00
Steve Munene 3dbd617ed0 SMQ-3050 - Fix PAT redis connection (#3051)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2025-08-13 14:50:20 +02:00
Felix Gateru 8188da16b3 NOISSUE - Update removal of view invitation endpoint in sdk and cli (#3055)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-08-13 14:48:12 +02:00
Smith Jilks bc7b988098 NOISSUE - Add ability to handle both tls cert file and raw cert data (#2871)
Signed-off-by: Jilks Smith <smithjilks@gmail.com>
2025-08-08 15:48:36 +02:00
Felix Gateru a0b3970ad6 SMQ-3032 - Remove view invitations endpoint (#3042)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-08-07 20:31:15 +02:00
Felix Gateru 0f20663cfb SMQ-2704 - Update listing of group hierarchy (#2710)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-08-07 11:53:23 +02:00
Felix Gateru 4dc98763a6 SMQ-3044 - Fix listing channel logs with operation query parameter (#3043)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-08-05 20:55:09 +02:00
Filip Bugarski 230be1d13b NOISSUE - Fix typos (#2927)
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2025-08-03 15:56:45 +02:00
Arvindh 99493d86ff NOISSUE - Fix callout test (#3041)
Signed-off-by: Arvindh <arvindh91@gmail.com>
2025-08-01 14:28:49 +02:00
Arvindh 4ffb1fe422 NOISSUE - Handle callout error (#3039)
Signed-off-by: Arvindh <arvindh91@gmail.com>
2025-08-01 13:53:21 +02:00
Washington Kigani Kamadi f4417ecb78 NOISSUE - List domain invitations on SDK (#3038)
Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>
2025-08-01 09:48:32 +02:00
Dušan Borovčanin 9b77130f6e SMQ-2866 - MQTT auth fails with identical secrets across different domains (#3030)
Signed-off-by: Dusan Borovcanin <borovcanindusan1@gmail.com>
2025-07-31 14:55:37 +02:00
dependabot[bot] 71ea84c3ec NOISSUE - Bump github.com/prometheus/client_golang from 1.22.0 to 1.23.0 (#3033)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-31 13:04:23 +02:00
dependabot[bot] 36c138688d NOISSUE - Bump github.com/nats-io/nats.go from 1.43.0 to 1.44.0 (#3034)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-31 13:00:20 +02:00
Washington Kigani Kamadi 86afe1736f NOISSUE - Add domain name to invitation (#3031)
Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>
2025-07-30 18:32:49 +02:00
Steve Munene 8e70e1113e SMQ-3201 - Replace Vault with openbao (#3019)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2025-07-28 12:03:50 +02:00
b1ackd0t a379d11035 NOISSUE - Fix mTLS setup (#3029)
Signed-off-by: Rodney Osodo <socials@rodneyosodo.com>
2025-07-23 12:58:15 +02:00
dependabot[bot] 45a5c42ea4 NOISSUE - Bump google.golang.org/grpc from 1.73.0 to 1.74.2 (#3027)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-23 10:08:17 +02:00
Felix Gateru 99a55a6e24 SMQ-2801 - Add health check endpoint for CoAP adapter (#3022)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-07-21 18:14:55 +02:00
Felix Gateru 6e404caa32 NOISSUE - Move codecov yaml file (#3020)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
2025-07-17 11:18:01 +02:00
1077 changed files with 72026 additions and 161059 deletions
@@ -5,9 +5,10 @@
coverage:
ignore:
- "tools/*"
- "api/grpc/**"
- "cmd/*"
- "coap/*"
- "*/mocks/*"
- "coap/**"
- "**/mocks/*"
- "*/middleware/*"
- "pkg/sid/mock.go"
- "pkg/tracing/utils.go"
+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:
+181
View File
@@ -0,0 +1,181 @@
<!--
Copyright (c) Abstract Machines
SPDX-License-Identifier: Apache-2.0
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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 {
margin: 0;
padding: 0;
}
.topbar {
display: none;
}
.service-selector {
background: #1b1b1b;
padding: 20px;
text-align: center;
}
.service-selector h1 {
color: #fff;
margin: 0 0 15px 0;
font-family: sans-serif;
}
.service-dropdown-container {
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
}
.service-dropdown-container label {
color: #fff;
font-family: sans-serif;
font-size: 14px;
font-weight: 500;
}
.service-dropdown {
background: #2d2d2d;
color: white;
border: 1px solid #4990e2;
padding: 10px 40px 10px 15px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
min-width: 200px;
appearance: none;
background-image: url('data:image/svg+xml;charset=UTF-8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><path fill="%23ffffff" d="M6 9L1 4h10z"/></svg>');
background-repeat: no-repeat;
background-position: right 12px center;
}
.service-dropdown:hover {
background-color: #3a3a3a;
border-color: #357abd;
}
.service-dropdown:focus {
outline: none;
border-color: #4990e2;
box-shadow: 0 0 0 2px rgba(73, 144, 226, 0.3);
}
/* Responsive styles for mobile */
@media (max-width: 768px) {
.service-selector {
padding: 15px 10px;
}
.service-selector h1 {
font-size: 1.5rem;
margin: 0 0 12px 0;
}
.service-dropdown-container {
flex-direction: column;
gap: 8px;
}
.service-dropdown-container label {
font-size: 13px;
}
.service-dropdown {
width: 100%;
max-width: 300px;
min-width: auto;
font-size: 13px;
padding: 8px 35px 8px 12px;
}
}
@media (max-width: 480px) {
.service-selector h1 {
font-size: 1.25rem;
}
.service-dropdown {
max-width: 250px;
}
}
</style>
</head>
<body>
<div class="service-selector">
<h1>Magistrala API Documentation</h1>
<div class="service-dropdown-container">
<label for="serviceDropdown">Select Service:</label>
<select id="serviceDropdown" class="service-dropdown"></select>
</div>
</div>
<div id="swagger-ui"></div>
<script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.30.3/swagger-ui-bundle.js"></script>
<script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.30.3/swagger-ui-standalone-preset.js"></script>
<script>
// Available API specifications
const APIs = APIS_PLACEHOLDER;
// Get the service from URL query parameter, default to first service
function getServiceFromURL() {
const params = new URLSearchParams(window.location.search);
const service = params.get('service');
return service && APIs.includes(service) ? service : APIs[0];
}
// Update URL with selected service
function updateURL(service) {
const url = new URL(window.location);
url.searchParams.set('service', service);
window.history.pushState({}, '', url);
}
// Create service selector dropdown
function createServiceDropdown() {
const dropdown = document.getElementById('serviceDropdown');
const currentService = getServiceFromURL();
APIs.forEach(api => {
const option = document.createElement('option');
option.value = api;
let serviceName = api.replace('.yaml', '').replace(/^\w/, c => c.toUpperCase());
if (serviceName.toLowerCase() === 'http') {
serviceName = 'HTTP';
}
option.textContent = serviceName;
if (api === currentService) {
option.selected = true;
}
dropdown.appendChild(option);
});
// Handle dropdown change
dropdown.addEventListener('change', (e) => {
const selectedApi = e.target.value;
loadSwaggerUI(selectedApi);
updateURL(selectedApi);
});
}
// Load Swagger UI with specified API spec
function loadSwaggerUI(apiSpec) {
SwaggerUIBundle({
url: apiSpec,
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
});
}
// Initialize
createServiceDropdown();
loadSwaggerUI(getServiceFromURL());
</script>
</body>
</html>
+155 -110
View File
@@ -4,196 +4,241 @@
name: Property Based Tests
on:
push:
branches:
- main
paths:
- ".github/workflows/api-tests.yaml"
- "api/**"
- "internal/atom/**"
- "channels/api/http/**"
- "clients/api/http/**"
- "domains/api/http/**"
- "groups/api/http/**"
- "users/api/**"
- "bootstrap/api/**"
- "certs/api/http/**"
- "readers/api/http/**"
- "apidocs/openapi/**"
pull_request:
branches:
- main
paths:
- ".github/workflows/api-tests.yaml"
- "api/**"
- "auth/api/http/**"
- "certs/api/**"
- "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:
group: ${{ github.workflow }}-${{ github.ref }}
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
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
JOURNAL_URL: http://localhost:9021
READERS_URL: http://localhost:9011
jobs:
api-test:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Install Go
uses: actions/setup-go@v5
uses: actions/setup-go@v7
with:
go-version: 1.24.x
go-version-file: go.mod
cache-dependency-path: "go.sum"
- name: Check for changes in specific paths
uses: dorny/paths-filter@v4
id: changes
with:
filters: |
workflow:
- ".github/workflows/api-tests.yaml"
domains:
- "apidocs/openapi/domains.yaml"
- "internal/atom/**"
- "domains/api/http/**"
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 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: |
echo "Waiting for services to start..."
sleep 15
# Check if services are responding
for i in {1..30}; do
if curl -f -s http://localhost/health > /dev/null 2>&1; then
echo "Services are ready!"
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: Check for changes in specific paths
uses: dorny/paths-filter@v3
id: changes
with:
filters: |
journal:
- ".github/workflows/api-tests.yaml"
- "apidocs/openapi/journal.yaml"
- "journal/api/**"
auth:
- ".github/workflows/api-tests.yaml"
- "apidocs/openapi/auth.yaml"
- "auth/api/http/**"
certs:
- ".github/workflows/api-tests.yaml"
- "apidocs/openapi/certs.yaml"
- "certs/api/**"
domains:
- ".github/workflows/api-tests.yaml"
- "apidocs/openapi/domains.yaml"
- "domains/api/http/**"
http:
- ".github/workflows/api-tests.yaml"
- "apidocs/openapi/http.yaml"
- "http/api/**"
clients:
- ".github/workflows/api-tests.yaml"
- "apidocs/openapi/clients.yaml"
- "clients/api/http/**"
channels:
- ".github/workflows/api-tests.yaml"
- "apidocs/openapi/channels.yaml"
- "channels/api/http/**"
groups:
- ".github/workflows/api-tests.yaml"
- "apidocs/openapi/groups.yaml"
- "groups/api/http/**"
users:
- ".github/workflows/api-tests.yaml"
- "apidocs/openapi/users.yaml"
- "users/api/**"
- name: Run Users API tests
if: steps.changes.outputs.users == '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 --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'
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'
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'
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'
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'
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'
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'
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'
uses: schemathesis/action@v2.1.0
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 down args="-v" && make run_addons down args="-v"
run: make run_latest_ci down args="-v" && make run_addons down args="-v"
+31 -44
View File
@@ -7,66 +7,53 @@ on:
push:
branches:
- main
paths-ignore:
- "**/*.md"
- "docs/**"
- ".github/workflows/**"
- "LICENSE"
- "MAINTAINERS"
- "CODEOWNERS"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
jobs:
lint-and-build:
uses: ./.github/workflows/lint-and-build.yaml
build-and-push:
name: Build and Push
name: Build and Push Docker Images
runs-on: ubuntu-latest
needs: [lint-and-build]
permissions:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Fetch tags for the build
run: |
git fetch --prune --unshallow --tags
- name: Install Go
uses: actions/setup-go@v5
uses: actions/checkout@v7
with:
go-version: 1.24.x
fetch-depth: 0
fetch-tags: true
- name: Setup Go
uses: actions/setup-go@v7
with:
go-version-file: go.mod
cache-dependency-path: "go.sum"
- name: Run tests
run: |
make test
- name: Upload coverage
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV }}
files: ./coverage/*.out
codecov_yml_path: tools/config/.codecov.yaml
verbose: true
- 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 }}
- name: Compile check for rabbitmq
run: |
SMQ_MESSAGE_BROKER_TYPE=msg_rabbitmq make mqtt
- name: Compile check for redis
run: |
SMQ_ES_TYPE=es_redis make mqtt
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Docker images
run: |
make latest -j $(nproc)
- name: Trigger Helm Chart Deployment
if: success() && github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.REPO_DISPATCH_TOKEN }}
repository: absmach/amdm
event-type: deploy-latest-smq-images
+26 -36
View File
@@ -4,9 +4,6 @@
name: Check the consistency of generated files
on:
push:
branches:
- main
pull_request:
branches:
- main
@@ -14,23 +11,33 @@ on:
jobs:
check-generated-files:
runs-on: ubuntu-latest
env:
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@v4
uses: actions/checkout@v7
- name: Install Go
uses: actions/setup-go@v5
uses: actions/setup-go@v7
with:
go-version: 1.24.x
go-version-file: go.mod
cache-dependency-path: "go.sum"
- name: Set GOBIN
run: echo "GOBIN=$HOME/.local/bin" >> $GITHUB_ENV
- name: Add GOBIN to PATH
run: echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Check for changes in go.mod
run: |
go mod tidy
git diff --exit-code
- name: Check for changes in specific paths
uses: dorny/paths-filter@v3
uses: dorny/paths-filter@v4
id: changes
with:
base: main
@@ -43,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"
@@ -60,38 +68,20 @@ jobs:
- "pkg/groups/groups.go"
- "users/emailer.go"
- "users/hasher.go"
- "certs/certs.go"
- "certs/pki/vault.go"
- "certs/service.go"
- "journal/journal.go"
- "consumers/notifier.go"
- name: Set up protoc
- name: Install Protoc
if: steps.changes.outputs.proto == 'true'
uses: arduino/setup-protoc@v3
with:
version: ${{ env.PROTOC_VERSION }}
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Go Protobuf Plugins
if: steps.changes.outputs.proto == 'true'
run: |
PROTOC_VERSION=30.2
PROTOC_GEN_VERSION=v1.36.6
PROTOC_GRPC_VERSION=v1.5.1
# Export the variables so they are available in future steps
echo "PROTOC_VERSION=$PROTOC_VERSION" >> $GITHUB_ENV
echo "PROTOC_GEN_VERSION=$PROTOC_GEN_VERSION" >> $GITHUB_ENV
echo "PROTOC_GRPC_VERSION=$PROTOC_GRPC_VERSION" >> $GITHUB_ENV
# Download and install protoc
PROTOC_ZIP=protoc-$PROTOC_VERSION-linux-x86_64.zip
curl -0L -o $PROTOC_ZIP https://github.com/protocolbuffers/protobuf/releases/download/v$PROTOC_VERSION/$PROTOC_ZIP
unzip -o $PROTOC_ZIP -d protoc3
sudo mv protoc3/bin/* /usr/local/bin/
sudo mv protoc3/include/* /usr/local/include/
rm -rf $PROTOC_ZIP protoc3
# Install protoc-gen-go and protoc-gen-go-grpc
go install google.golang.org/protobuf/cmd/protoc-gen-go@$PROTOC_GEN_VERSION
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@$PROTOC_GRPC_VERSION
# Add protoc to the PATH
export PATH=$PATH:/usr/local/bin/protoc
go install google.golang.org/protobuf/cmd/protoc-gen-go@$PROTOC_GEN_GO_VERSION
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@$PROTOC_GEN_GO_GRPC_VERSION
- name: Check Protobuf is up to Date
if: steps.changes.outputs.proto == 'true'
@@ -107,7 +97,7 @@ jobs:
echo "Error: Proto file and generated Go file $p are out of sync!"
echo "Here is the difference:"
diff $p $p.tmp || true
echo "Please run 'make proto' with protoc version $PROTOC_VERSION, protoc-gen-go version $PROTOC_GEN_VERSION and protoc-gen-go-grpc version $PROTOC_GRPC_VERSION and commit the changes."
echo "Please run 'make proto' with protoc version $PROTOC_VERSION, protoc-gen-go version $PROTOC_GEN_GO_VERSION and protoc-gen-go-grpc version $PROTOC_GEN_GO_GRPC_VERSION and commit the changes."
exit 1
fi
done
+1 -4
View File
@@ -4,9 +4,6 @@
name: Check License Header
on:
push:
branches:
- main
pull_request:
branches:
- main
@@ -16,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v7
- name: Check License Header
run: |
+63
View File
@@ -0,0 +1,63 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
name: Lint and Build
on:
workflow_call:
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Setup Go
uses: actions/setup-go@v7
with:
go-version-file: go.mod
cache-dependency-path: "go.sum"
- name: Run linters
uses: golangci/golangci-lint-action@v9.3.0
with:
version: v2.10.1
args: --config ./tools/config/.golangci.yaml
build:
name: Build All Binaries
runs-on: ubuntu-latest
needs: lint
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Setup Go
uses: actions/setup-go@v7
with:
go-version-file: go.mod
cache-dependency-path: "go.sum"
- name: Build all binaries
run: |
make all -j $(nproc)
compile-check:
name: Compile Check Redis Event Store
runs-on: ubuntu-latest
needs: lint
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Setup Go
uses: actions/setup-go@v7
with:
go-version-file: go.mod
cache-dependency-path: "go.sum"
- name: Compile check
run: |
MG_ES_TYPE=es_redis make all -j $(nproc)
+24 -10
View File
@@ -8,24 +8,38 @@ on:
branches:
- main
permissions:
contents: write
jobs:
swagger-ui:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v7
- name: Swagger UI action
id: swagger-ui-action
uses: blokovi/swagger-ui-action@main
with:
dir: "./apidocs/openapi"
pattern: "*.yaml"
debug: "true"
- name: Build Swagger UI
run: |
# Create output directory
mkdir -p swagger-ui
# Copy OpenAPI YAML files and schemas directory
cp apidocs/openapi/*.yaml swagger-ui/
cp -r apidocs/openapi/schemas swagger-ui/
# Get list of YAML files
cd apidocs/openapi
YAML_FILES=$(ls *.yaml | jq -R -s -c 'split("\n")[:-1]')
cd ../..
# Generate index.html from template
sed "s|APIS_PLACEHOLDER|$YAML_FILES|g" .github/swagger-ui-template.html > swagger-ui/index.html
echo "Generated Swagger UI with APIs: $YAML_FILES"
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: swagger-ui
cname: docs.api.supermq.abstractmachines.fr
publish_dir: ./swagger-ui
cname: docs.api.magistrala.absmach.eu
+166 -228
View File
@@ -4,23 +4,35 @@
name: CI Pipeline
on:
push:
branches:
- main
paths-ignore:
- '**/*.md'
- 'docs/**'
- 'LICENSE'
- 'MAINTAINERS'
- 'CODEOWNERS'
pull_request:
branches:
- main
jobs:
lint-and-build: # Linting and building are combined to save time for setting up Go
name: Lint and Build
runs-on: ubuntu-latest
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
lint-proto:
name: Lint Proto
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
uses: actions/checkout@v7
- name: Setup Go
uses: actions/setup-go@v5
uses: actions/setup-go@v7
with:
go-version: 1.24.x
go-version-file: go.mod
cache-dependency-path: "go.sum"
- name: Install protolint
@@ -31,73 +43,31 @@ jobs:
run: |
protolint .
- name: Run linters
uses: golangci/golangci-lint-action@v8
with:
version: v2.1.6
args: --config ./tools/config/.golangci.yaml
lint-and-build:
needs: [lint-proto]
uses: ./.github/workflows/lint-and-build.yaml
- name: Build all Binaries
run: |
make all -j $(nproc)
- name: Compile check for rabbitmq
run: |
SMQ_MESSAGE_BROKER_TYPE=msg_rabbitmq make mqtt
- name: Compile check for redis
run: |
SMQ_ES_TYPE=es_redis make mqtt
run-tests:
name: Run tests
detect-changes:
name: Detect Changes
runs-on: ubuntu-latest
needs: lint-and-build
outputs:
modules: ${{ steps.set-matrix.outputs.modules }}
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: 1.24.x
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:
base: main
filters: |
workflow:
- ".github/workflows/tests.yaml"
auth:
- "auth/**"
- "cmd/auth/**"
- "auth.proto"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "pkg/ulid/**"
- "pkg/uuid/**"
certs:
- "certs/**"
- "cmd/certs/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "auth/**"
- "pkg/sdk/**"
channels:
- "channels/**"
- "cmd/channels/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "auth/**"
- "pkg/sdk/**"
- "clients/api/grpc/**"
- "groups/api/grpc/**"
@@ -111,10 +81,6 @@ jobs:
clients:
- "clients/**"
- "cmd/clients/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "auth/**"
- "pkg/ulid/**"
- "pkg/uuid/**"
- "pkg/events/**"
@@ -123,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/**"
@@ -152,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/**"
@@ -202,16 +138,13 @@ jobs:
- "pkg/sdk/**"
- "pkg/errors/**"
- "pkg/groups/**"
- "auth/**"
- "certs/**"
- "http/**"
- "internal/*"
- "internal/api/**"
- "internal/apiutil/**"
- "internal/groups/**"
- "invitations/**"
- "clients/**"
- "users/**"
- "channels/**"
- "domains/**"
- "groups/**"
- "api/http/**"
pkg-transformers:
- "pkg/transformers/**"
@@ -224,145 +157,150 @@ jobs:
users:
- "users/**"
- "cmd/users/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "auth/**"
- "pkg/ulid/**"
- "pkg/uuid/**"
- "pkg/events/**"
ws:
- "ws/**"
- "cmd/ws/**"
- "auth.pb.go"
- "auth_grpc.pb.go"
- "clients/**"
- "pkg/messaging/**"
api:
- "api/**"
- name: Create coverage directory
run: |
mkdir coverage
consumers:
- "consumers/**"
- "cmd/postgres-writer/**"
- "cmd/timescale-writer/**"
- "cmd/smpp-notifier/**"
- "cmd/smtp-notifier/**"
- name: Run journal tests
if: steps.changes.outputs.journal == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/journal.out ./journal/...
readers:
- "readers/**"
- "cmd/postgres-reader/**"
- "cmd/timescale-reader/**"
- name: Run auth tests
if: steps.changes.outputs.auth == 'true' || steps.changes.outputs.workflow == 'true'
- name: Set matrix for changed modules
id: set-matrix
run: |
go test --race -v -count=1 -coverprofile=coverage/auth.out ./auth/...
modules=()
- name: Run domains tests
if: steps.changes.outputs.domains == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/domains.out ./domains/...
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.domains }}" == "true" ]] && modules+=("domains")
[[ "${{ steps.changes.outputs.groups }}" == "true" ]] && modules+=("groups")
[[ "${{ steps.changes.outputs.internal }}" == "true" ]] && modules+=("internal")
[[ "${{ steps.changes.outputs.logger }}" == "true" ]] && modules+=("logger")
[[ "${{ 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.api }}" == "true" ]] && modules+=("api")
[[ "${{ steps.changes.outputs.consumers }}" == "true" ]] && modules+=("consumers")
[[ "${{ steps.changes.outputs.readers }}" == "true" ]] && modules+=("readers")
fi
- name: Run certs tests
if: steps.changes.outputs.certs == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/certs.out ./certs/...
# Convert to JSON array
json_modules=$(printf '%s\n' "${modules[@]}" | jq -R . | jq -s -c .)
echo "modules=$json_modules" >> $GITHUB_OUTPUT
echo "Testing modules: $json_modules"
- name: Run cli tests
if: steps.changes.outputs.cli == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/cli.out ./cli/...
run-tests:
name: Test ${{ matrix.module }}
runs-on: ubuntu-latest
needs: [lint-and-build, detect-changes]
if: needs.detect-changes.outputs.modules != '[]'
strategy:
fail-fast: true
max-parallel: 20
matrix:
module: ${{ fromJSON(needs.detect-changes.outputs.modules) }}
- name: Run CoAP tests
if: steps.changes.outputs.coap == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/coap.out ./coap/...
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Run HTTP tests
if: steps.changes.outputs.http == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/http.out ./http/...
- name: Setup Go
uses: actions/setup-go@v7
with:
go-version-file: go.mod
cache-dependency-path: "go.sum"
- name: Run internal tests
if: steps.changes.outputs.internal == 'true' || steps.changes.outputs.workflow == 'true'
- name: Verify dependencies
run: |
go test --race -v -count=1 -coverprofile=coverage/internal.out ./internal/...
go mod download
go mod verify
- name: Run logger tests
if: steps.changes.outputs.logger == 'true' || steps.changes.outputs.workflow == 'true'
- name: Run ${{ matrix.module }} tests
run: |
go test --race -v -count=1 -coverprofile=coverage/logger.out ./logger/...
# 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
- name: Run MQTT tests
if: steps.changes.outputs.mqtt == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/mqtt.out ./mqtt/...
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
- name: Run pkg errors tests
if: steps.changes.outputs.pkg-errors == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/pkg-errors.out ./pkg/errors/...
- name: Run pkg events tests
if: steps.changes.outputs.pkg-events == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/pkg-events.out ./pkg/events/...
- name: Run pkg grpcclient tests
if: steps.changes.outputs.pkg-grpcclient == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/pkg-grpcclient.out ./pkg/grpcclient/...
- name: Run pkg messaging tests
if: steps.changes.outputs.pkg-messaging == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/pkg-messaging.out ./pkg/messaging/...
- name: Run pkg sdk tests
if: steps.changes.outputs.pkg-sdk == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/pkg-sdk.out ./pkg/sdk/...
- name: Run pkg transformers tests
if: steps.changes.outputs.pkg-transformers == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/pkg-transformers.out ./pkg/transformers/...
- name: Run pkg ulid tests
if: steps.changes.outputs.pkg-ulid == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/pkg-ulid.out ./pkg/ulid/...
- name: Run pkg uuid tests
if: steps.changes.outputs.pkg-uuid == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/pkg-uuid.out ./pkg/uuid/...
- name: Run clients tests
if: steps.changes.outputs.clients == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/clients.out ./clients/...
- name: Run channels tests
if: steps.changes.outputs.channels == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/channels.out ./channels/...
- name: Run users tests
if: steps.changes.outputs.users == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/users.out ./users/...
- name: Run groups tests
if: steps.changes.outputs.groups == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/groups.out ./groups/...
- name: Run WebSocket tests
if: steps.changes.outputs.ws == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/ws.out ./ws/...
go test -mod=readonly --race -v -count=1 -failfast -coverprofile=coverage-${{ matrix.module }}.out ./$dir/...
- name: Upload coverage
uses: codecov/codecov-action@v5
uses: actions/upload-artifact@v7
with:
name: coverage-${{ matrix.module }}
path: coverage-${{ matrix.module }}.out
retention-days: 1
upload-coverage:
name: Upload Coverage
runs-on: ubuntu-latest
needs: run-tests
if: always() && needs.run-tests.result != 'cancelled'
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Download all coverage artifacts
uses: actions/download-artifact@v8
with:
pattern: coverage-*
path: coverage
merge-multiple: true
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v7
with:
token: ${{ secrets.CODECOV }}
directory: ./coverage
files: ./coverage/*.out
codecov_yml_path: tools/config/.codecov.yaml
fail_ci_if_error: false
verbose: true
+11 -2
View File
@@ -16,5 +16,14 @@ coverage
# Schemathesis
.hypothesis
# Ignore Vault data directory as it contains runtime-generated data
docker/addons/vault/data/
# 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.
+10 -10
View File
@@ -1,11 +1,11 @@
# 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).
By participating, you are expected to uphold this code. Please report unacceptable behavior to
[abuse@abstractmachines.fr](mailto:abuse@abstractmachines.fr).
[abuse@absmach.eu](mailto:abuse@absmach.eu).
## Reporting issues
@@ -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-2020 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.
+11 -26
View File
@@ -1,30 +1,15 @@
# SuperMQ follows the timeless, highly efficient and totally unfair system
# known as [Benevolent dictator for
# life](https://en.wikipedia.org/wiki/Benevolent_Dictator_for_Life), with
# Drasko DRASKOVIC in the role of BDFL.
# Magistrala Maintainers
[bdfl]
[[drasko]]
Name = "Drasko Draskovic"
Email = "drasko@abstractmachines.fr"
GitHub = "drasko"
Magistrala follows a BDFL model for dead-lock situations; day-to-day decisions happen through discussion and pull requests.
# However, this role serves only in dead-lock events, or in a special and very rare cases
# when BDFL completely disagrees with the decisions made.
# In the normal flow of events, decisions on the project design are made through discussions,
# most often on the Pull Requests.
#
# Maintainers have the special role in the project in managing and accepting PRs,
# overall leading the project and making design decisions on the maintained subsystems.
#
# A reference list of all maintainers of the SuperMQ project.
## BDFL
# ADD YOURSELF HERE IN ALPHABETICAL ORDER
- **Drasko Draskovic** — [drasko@absmach.eu](mailto:drasko@absmach.eu) — [GitHub: drasko](https://github.com/drasko)
[maintainers]
[[dusan]]
Name = "Dusan Borovcanin"
Email = "dusan.borovcanin@abstractmachines.fr"
GitHub = "dborovcanin"
## Maintainers
Add yourself below in alphabetical order.
| Name | Email | GitHub |
| --- | --- | --- |
| Dusan Borovcanin | [dusan.borovcanin@absmach.eu](mailto:dusan.borovcanin@absmach.eu) | [dborovcanin](https://github.com/dborovcanin) |
+247 -68
View File
@@ -1,15 +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 ws cli mqtt certs journal
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)
@@ -20,30 +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_VERSION=v3.5.0
MOCKERY = $(GOBIN)/mockery
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
@@ -58,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
@@ -68,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
EXTERNAL_SERVICES = vault prometheus
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
@@ -98,7 +197,14 @@ FILTERED_SERVICES = $(filter-out $(RUN_ADDON_ARGS), $(SERVICES))
all: $(SERVICES)
.PHONY: all $(SERVICES) dockers dockers_dev latest release run 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}
@@ -109,19 +215,21 @@ 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:
@which mockery > /dev/null || go install github.com/vektra/mockery/v3@$(MOCKERY_VERSION)
@unset MOCKERY_VERSION
mockery --config ./tools/config/.mockery.yaml
mocks: $(MOCKERY)
@$(MOCKERY) --config ./tools/config/.mockery.yaml
$(MOCKERY):
@mkdir -p $(GOBIN)
@echo ">> installing mockery $(MOCKERY_VERSION)..."
@go install github.com/vektra/mockery/v3@v$(MOCKERY_VERSION)
DIRS = consumers readers postgres internal
test: mocks
@@ -133,48 +241,30 @@ test: mocks
define test_api_service
$(eval svc=$(subst test_api_,,$(1)))
@which st > /dev/null || (echo "schemathesis not found, please install it from https://github.com/schemathesis/schemathesis#getting-started" && exit 1)
@which uv > /dev/null || (echo "uv not found, please install it from https://github.com/astral-sh/uv" && exit 1)
@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 \
st 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 \
st 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 \
--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))
@@ -198,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
@@ -208,12 +298,21 @@ changelog:
latest: dockers
$(call docker_push,latest)
publish_arch:
$(MAKE) dockers GOOS=$(GOOS) GOARCH=$(GOARCH) GOARM=$(GOARM)
for svc in $(SERVICES); do \
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:
$(eval version = $(shell git describe --abbrev=0 --tags))
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))
@@ -221,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)
@@ -239,23 +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
run: check_certs
docker compose -f docker/docker-compose.yaml --env-file docker/.env -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args)
run_latest: check_certs
$(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_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_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 \
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) & \
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)
+383 -89
View File
@@ -1,118 +1,412 @@
<div align="center">
# SuperMQ
**Planetary event-driven infrastructure**
**Made with ❤️ by [Abstract Machines](https://abstractmachines.fr/)**
[![Build Status](https://github.com/absmach/supermq/actions/workflows/build.yaml/badge.svg?branch=main)](https://github.com/absmach/supermq/actions/workflows/build.yaml)
[![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)
[![Go Report Card](https://goreportcard.com/badge/github.com/absmach/supermq)](https://goreportcard.com/report/github.com/absmach/supermq)
[![Coverage](https://codecov.io/gh/absmach/supermq/graph/badge.svg?token=nPCEr5nW8S)](https://codecov.io/gh/absmach/supermq)
[![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.abstractmachines.fr) | [Contributing](CONTRIBUTING.md) | [Website](https://abstractmachines.fr/) | [Chat](https://matrix.to/#/#supermq:matrix.org)
# Magistrala
### 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://magistrala.absmach.eu/docs/) | [Contributing](CONTRIBUTING.md) | [Website](https://absmach.eu/) | [Chat](https://matrix.to/#/#supermq:matrix.org)
</div>
## Introduction 🌍
Magistrala is an open-source IoT platform built for engineers who need full control over their messaging, device management, and data pipelines.
## Introduction 📖
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 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.
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.
## Why SuperMQ Stands Out 🚀
**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
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. 🌐✨
**What it is not:**
- Not just an MQTT broker
- Not a black-box SaaS
- Not tied to a single cloud or vendor
## Key Features 🌟
---
- **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. 🐳☸️
## 🧩 IoT Platform Framework
## Installation 🛠️
We call Magistrala a **framework**, not just a platform.
Clone the repository and start SuperMQ services:
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.
```bash
git clone https://github.com/absmach/supermq.git
cd supermq
docker compose -f docker/docker-compose.yaml --env-file docker/.env up
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
```
Or use the [Makefile](Makefile) for a simpler command:
### Actions, Permission Blocks, Roles, and Assignments
```bash
make run
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.
```
For production deployments, check our [Kubernetes guide](https://docs.supermq.abstractmachines.fr/kubernetes). ⚙️
Example:
### Usage 📤📥
```text
Give user1 the tenant-admin role on domain d1.
```
#### Using the CLI:
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
git clone https://github.com/absmach/magistrala.git
cd magistrala
make provision_atom_tokens
make run_latest
```
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.
### Certificates, broker secret and trace key
Generated by `make run_latest`, or on demand:
```bash
make check_certs
```
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
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
```
`make check_certs` skips certificates that already exist, so stale certificates
have to be removed rather than merely re-running the target.
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:
```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.abstractmachines.fr/cli) for more details.
## Documentation 📚
The official documentation is hosted at [SuperMQ docs page](https://docs.supermq.abstractmachines.fr).
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://abstractmachines.fr/)** 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! 🚀
## License
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 {
+272 -197
View File
@@ -3,8 +3,8 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.6
// protoc v6.30.2
// protoc-gen-go v1.36.11
// protoc v7.35.1
// source: auth/v1/auth.proto
package v1
@@ -70,9 +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
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
}
@@ -128,24 +130,223 @@ func (x *AuthNRes) GetUserRole() uint32 {
return 0
}
type AuthZReq struct {
func (x *AuthNRes) GetVerified() bool {
if x != nil {
return x.Verified
}
return false
}
func (x *AuthNRes) GetTokenType() uint32 {
if x != nil {
return x.TokenType
}
return 0
}
type PolicyReq struct {
state protoimpl.MessageState `protogen:"open.v1"`
Domain string `protobuf:"bytes,1,opt,name=domain,proto3" json:"domain,omitempty"` // Domain
SubjectType string `protobuf:"bytes,2,opt,name=subject_type,json=subjectType,proto3" json:"subject_type,omitempty"` // Client or User
SubjectKind string `protobuf:"bytes,3,opt,name=subject_kind,json=subjectKind,proto3" json:"subject_kind,omitempty"` // ID or Token
SubjectRelation string `protobuf:"bytes,4,opt,name=subject_relation,json=subjectRelation,proto3" json:"subject_relation,omitempty"` // Subject relation
Subject string `protobuf:"bytes,5,opt,name=subject,proto3" json:"subject,omitempty"` // Subject value (id or token, depending on kind)
Relation string `protobuf:"bytes,6,opt,name=relation,proto3" json:"relation,omitempty"` // Relation to filter
Permission string `protobuf:"bytes,7,opt,name=permission,proto3" json:"permission,omitempty"` // Action
Object string `protobuf:"bytes,8,opt,name=object,proto3" json:"object,omitempty"` // Object ID
ObjectType string `protobuf:"bytes,9,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
}
func (x *PolicyReq) Reset() {
*x = PolicyReq{}
mi := &file_auth_v1_auth_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PolicyReq) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PolicyReq) ProtoMessage() {}
func (x *PolicyReq) ProtoReflect() protoreflect.Message {
mi := &file_auth_v1_auth_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 PolicyReq.ProtoReflect.Descriptor instead.
func (*PolicyReq) Descriptor() ([]byte, []int) {
return file_auth_v1_auth_proto_rawDescGZIP(), []int{2}
}
func (x *PolicyReq) GetDomain() string {
if x != nil {
return x.Domain
}
return ""
}
func (x *PolicyReq) GetSubjectType() string {
if x != nil {
return x.SubjectType
}
return ""
}
func (x *PolicyReq) GetSubjectKind() string {
if x != nil {
return x.SubjectKind
}
return ""
}
func (x *PolicyReq) GetSubjectRelation() string {
if x != nil {
return x.SubjectRelation
}
return ""
}
func (x *PolicyReq) GetSubject() string {
if x != nil {
return x.Subject
}
return ""
}
func (x *PolicyReq) GetRelation() string {
if x != nil {
return x.Relation
}
return ""
}
func (x *PolicyReq) GetPermission() string {
if x != nil {
return x.Permission
}
return ""
}
func (x *PolicyReq) GetObject() string {
if x != nil {
return x.Object
}
return ""
}
func (x *PolicyReq) GetObjectType() string {
if x != nil {
return x.ObjectType
}
return ""
}
type PATReq struct {
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() {
*x = PATReq{}
mi := &file_auth_v1_auth_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PATReq) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PATReq) ProtoMessage() {}
func (x *PATReq) ProtoReflect() protoreflect.Message {
mi := &file_auth_v1_auth_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 PATReq.ProtoReflect.Descriptor instead.
func (*PATReq) Descriptor() ([]byte, []int) {
return file_auth_v1_auth_proto_rawDescGZIP(), []int{3}
}
func (x *PATReq) GetPatId() string {
if x != nil {
return x.PatId
}
return ""
}
func (x *PATReq) GetDomain() string {
if x != nil {
return x.Domain
}
return ""
}
func (x *PATReq) GetOperation() string {
if x != nil {
return x.Operation
}
return ""
}
func (x *PATReq) GetUserId() string {
if x != nil {
return x.UserId
}
return ""
}
func (x *PATReq) GetEntityId() string {
if x != nil {
return x.EntityId
}
return ""
}
func (x *PATReq) GetEntityType() string {
if x != nil {
return x.EntityType
}
return ""
}
type AuthZReq struct {
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
}
func (x *AuthZReq) Reset() {
*x = AuthZReq{}
mi := &file_auth_v1_auth_proto_msgTypes[2]
mi := &file_auth_v1_auth_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -157,7 +358,7 @@ func (x *AuthZReq) String() string {
func (*AuthZReq) ProtoMessage() {}
func (x *AuthZReq) ProtoReflect() protoreflect.Message {
mi := &file_auth_v1_auth_proto_msgTypes[2]
mi := &file_auth_v1_auth_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -170,154 +371,21 @@ func (x *AuthZReq) ProtoReflect() protoreflect.Message {
// Deprecated: Use AuthZReq.ProtoReflect.Descriptor instead.
func (*AuthZReq) Descriptor() ([]byte, []int) {
return file_auth_v1_auth_proto_rawDescGZIP(), []int{2}
return file_auth_v1_auth_proto_rawDescGZIP(), []int{4}
}
func (x *AuthZReq) GetDomain() string {
func (x *AuthZReq) GetPolicyReq() *PolicyReq {
if x != nil {
return x.Domain
return x.PolicyReq
}
return ""
return nil
}
func (x *AuthZReq) GetSubjectType() string {
func (x *AuthZReq) GetPatReq() *PATReq {
if x != nil {
return x.SubjectType
return x.PatReq
}
return ""
}
func (x *AuthZReq) GetSubjectKind() string {
if x != nil {
return x.SubjectKind
}
return ""
}
func (x *AuthZReq) GetSubjectRelation() string {
if x != nil {
return x.SubjectRelation
}
return ""
}
func (x *AuthZReq) GetSubject() string {
if x != nil {
return x.Subject
}
return ""
}
func (x *AuthZReq) GetRelation() string {
if x != nil {
return x.Relation
}
return ""
}
func (x *AuthZReq) GetPermission() string {
if x != nil {
return x.Permission
}
return ""
}
func (x *AuthZReq) GetObject() string {
if x != nil {
return x.Object
}
return ""
}
func (x *AuthZReq) GetObjectType() string {
if x != nil {
return x.ObjectType
}
return ""
}
type AuthZPatReq 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
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
OptionalDomainId string `protobuf:"bytes,4,opt,name=optional_domain_id,json=optionalDomainId,proto3" json:"optional_domain_id,omitempty"` // Optional domain id
Operation uint32 `protobuf:"varint,6,opt,name=operation,proto3" json:"operation,omitempty"` // Operation
EntityId string `protobuf:"bytes,7,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"` // EntityID
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *AuthZPatReq) Reset() {
*x = AuthZPatReq{}
mi := &file_auth_v1_auth_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *AuthZPatReq) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AuthZPatReq) ProtoMessage() {}
func (x *AuthZPatReq) ProtoReflect() protoreflect.Message {
mi := &file_auth_v1_auth_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 AuthZPatReq.ProtoReflect.Descriptor instead.
func (*AuthZPatReq) Descriptor() ([]byte, []int) {
return file_auth_v1_auth_proto_rawDescGZIP(), []int{3}
}
func (x *AuthZPatReq) GetUserId() string {
if x != nil {
return x.UserId
}
return ""
}
func (x *AuthZPatReq) GetPatId() string {
if x != nil {
return x.PatId
}
return ""
}
func (x *AuthZPatReq) GetEntityType() uint32 {
if x != nil {
return x.EntityType
}
return 0
}
func (x *AuthZPatReq) GetOptionalDomainId() string {
if x != nil {
return x.OptionalDomainId
}
return ""
}
func (x *AuthZPatReq) GetOperation() uint32 {
if x != nil {
return x.Operation
}
return 0
}
func (x *AuthZPatReq) GetEntityId() string {
if x != nil {
return x.EntityId
}
return ""
return nil
}
type AuthZRes struct {
@@ -330,7 +398,7 @@ type AuthZRes struct {
func (x *AuthZRes) Reset() {
*x = AuthZRes{}
mi := &file_auth_v1_auth_proto_msgTypes[4]
mi := &file_auth_v1_auth_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -342,7 +410,7 @@ func (x *AuthZRes) String() string {
func (*AuthZRes) ProtoMessage() {}
func (x *AuthZRes) ProtoReflect() protoreflect.Message {
mi := &file_auth_v1_auth_proto_msgTypes[4]
mi := &file_auth_v1_auth_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -355,7 +423,7 @@ func (x *AuthZRes) ProtoReflect() protoreflect.Message {
// Deprecated: Use AuthZRes.ProtoReflect.Descriptor instead.
func (*AuthZRes) Descriptor() ([]byte, []int) {
return file_auth_v1_auth_proto_rawDescGZIP(), []int{4}
return file_auth_v1_auth_proto_rawDescGZIP(), []int{5}
}
func (x *AuthZRes) GetAuthorized() bool {
@@ -378,12 +446,15 @@ const file_auth_v1_auth_proto_rawDesc = "" +
"\n" +
"\x12auth/v1/auth.proto\x12\aauth.v1\" \n" +
"\bAuthNReq\x12\x14\n" +
"\x05token\x18\x01 \x01(\tR\x05token\"P\n" +
"\x05token\x18\x01 \x01(\tR\x05token\"\x8b\x01\n" +
"\bAuthNRes\x12\x0e\n" +
"\x02id\x18\x01 \x01(\tR\x02id\x12\x17\n" +
"\auser_id\x18\x02 \x01(\tR\x06userId\x12\x1b\n" +
"\tuser_role\x18\x03 \x01(\rR\buserRole\"\xa2\x02\n" +
"\bAuthZReq\x12\x16\n" +
"\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\"\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" +
@@ -395,25 +466,29 @@ const file_auth_v1_auth_proto_rawDesc = "" +
"permission\x12\x16\n" +
"\x06object\x18\b \x01(\tR\x06object\x12\x1f\n" +
"\vobject_type\x18\t \x01(\tR\n" +
"objectType\"\xc7\x01\n" +
"\vAuthZPatReq\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\x06 \x01(\rR\toperation\x12\x1b\n" +
"\tentity_id\x18\a \x01(\tR\bentityId\":\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" +
"authorized\x12\x0e\n" +
"\x02id\x18\x02 \x01(\tR\x02id2\xf0\x01\n" +
"\x02id\x18\x02 \x01(\tR\x02id2z\n" +
"\vAuthService\x123\n" +
"\tAuthorize\x12\x11.auth.v1.AuthZReq\x1a\x11.auth.v1.AuthZRes\"\x00\x129\n" +
"\fAuthorizePAT\x12\x14.auth.v1.AuthZPatReq\x1a\x11.auth.v1.AuthZRes\"\x00\x126\n" +
"\fAuthenticate\x12\x11.auth.v1.AuthNReq\x1a\x11.auth.v1.AuthNRes\"\x00\x129\n" +
"\x0fAuthenticatePAT\x12\x11.auth.v1.AuthNReq\x1a\x11.auth.v1.AuthNRes\"\x00B-Z+github.com/absmach/supermq/api/grpc/auth/v1b\x06proto3"
"\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\"\x00B0Z.github.com/absmach/magistrala/api/grpc/auth/v1b\x06proto3"
var (
file_auth_v1_auth_proto_rawDescOnce sync.Once
@@ -427,28 +502,27 @@ func file_auth_v1_auth_proto_rawDescGZIP() []byte {
return file_auth_v1_auth_proto_rawDescData
}
var file_auth_v1_auth_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_auth_v1_auth_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_auth_v1_auth_proto_goTypes = []any{
(*AuthNReq)(nil), // 0: auth.v1.AuthNReq
(*AuthNRes)(nil), // 1: auth.v1.AuthNRes
(*AuthZReq)(nil), // 2: auth.v1.AuthZReq
(*AuthZPatReq)(nil), // 3: auth.v1.AuthZPatReq
(*AuthZRes)(nil), // 4: auth.v1.AuthZRes
(*AuthNReq)(nil), // 0: auth.v1.AuthNReq
(*AuthNRes)(nil), // 1: auth.v1.AuthNRes
(*PolicyReq)(nil), // 2: auth.v1.PolicyReq
(*PATReq)(nil), // 3: auth.v1.PATReq
(*AuthZReq)(nil), // 4: auth.v1.AuthZReq
(*AuthZRes)(nil), // 5: auth.v1.AuthZRes
}
var file_auth_v1_auth_proto_depIdxs = []int32{
2, // 0: auth.v1.AuthService.Authorize:input_type -> auth.v1.AuthZReq
3, // 1: auth.v1.AuthService.AuthorizePAT:input_type -> auth.v1.AuthZPatReq
0, // 2: auth.v1.AuthService.Authenticate:input_type -> auth.v1.AuthNReq
0, // 3: auth.v1.AuthService.AuthenticatePAT:input_type -> auth.v1.AuthNReq
4, // 4: auth.v1.AuthService.Authorize:output_type -> auth.v1.AuthZRes
4, // 5: auth.v1.AuthService.AuthorizePAT:output_type -> auth.v1.AuthZRes
1, // 6: auth.v1.AuthService.Authenticate:output_type -> auth.v1.AuthNRes
1, // 7: auth.v1.AuthService.AuthenticatePAT:output_type -> auth.v1.AuthNRes
4, // [4:8] is the sub-list for method output_type
0, // [0:4] 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
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
1, // 5: auth.v1.AuthService.Authenticate:output_type -> auth.v1.AuthNRes
4, // [4:6] is the sub-list for method output_type
2, // [2:4] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_auth_v1_auth_proto_init() }
@@ -456,13 +530,14 @@ func file_auth_v1_auth_proto_init() {
if File_auth_v1_auth_proto != nil {
return
}
file_auth_v1_auth_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_auth_v1_auth_proto_rawDesc), len(file_auth_v1_auth_proto_rawDesc)),
NumEnums: 0,
NumMessages: 5,
NumMessages: 6,
NumExtensions: 0,
NumServices: 1,
},
+9 -85
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.30.2
// - protoc-gen-go-grpc v1.6.2
// - protoc v7.35.1
// source: auth/v1/auth.proto
package v1
@@ -22,10 +22,8 @@ import (
const _ = grpc.SupportPackageIsVersion9
const (
AuthService_Authorize_FullMethodName = "/auth.v1.AuthService/Authorize"
AuthService_AuthorizePAT_FullMethodName = "/auth.v1.AuthService/AuthorizePAT"
AuthService_Authenticate_FullMethodName = "/auth.v1.AuthService/Authenticate"
AuthService_AuthenticatePAT_FullMethodName = "/auth.v1.AuthService/AuthenticatePAT"
AuthService_Authorize_FullMethodName = "/auth.v1.AuthService/Authorize"
AuthService_Authenticate_FullMethodName = "/auth.v1.AuthService/Authenticate"
)
// AuthServiceClient is the client API for AuthService service.
@@ -33,12 +31,10 @@ 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)
AuthorizePAT(ctx context.Context, in *AuthZPatReq, opts ...grpc.CallOption) (*AuthZRes, error)
Authenticate(ctx context.Context, in *AuthNReq, opts ...grpc.CallOption) (*AuthNRes, error)
AuthenticatePAT(ctx context.Context, in *AuthNReq, opts ...grpc.CallOption) (*AuthNRes, error)
}
type authServiceClient struct {
@@ -59,16 +55,6 @@ func (c *authServiceClient) Authorize(ctx context.Context, in *AuthZReq, opts ..
return out, nil
}
func (c *authServiceClient) AuthorizePAT(ctx context.Context, in *AuthZPatReq, opts ...grpc.CallOption) (*AuthZRes, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(AuthZRes)
err := c.cc.Invoke(ctx, AuthService_AuthorizePAT_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authServiceClient) Authenticate(ctx context.Context, in *AuthNReq, opts ...grpc.CallOption) (*AuthNRes, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(AuthNRes)
@@ -79,27 +65,15 @@ func (c *authServiceClient) Authenticate(ctx context.Context, in *AuthNReq, opts
return out, nil
}
func (c *authServiceClient) AuthenticatePAT(ctx context.Context, in *AuthNReq, opts ...grpc.CallOption) (*AuthNRes, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(AuthNRes)
err := c.cc.Invoke(ctx, AuthService_AuthenticatePAT_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// AuthServiceServer is the server API for AuthService service.
// All implementations must embed UnimplementedAuthServiceServer
// 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)
AuthorizePAT(context.Context, *AuthZPatReq) (*AuthZRes, error)
Authenticate(context.Context, *AuthNReq) (*AuthNRes, error)
AuthenticatePAT(context.Context, *AuthNReq) (*AuthNRes, error)
mustEmbedUnimplementedAuthServiceServer()
}
@@ -111,16 +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")
}
func (UnimplementedAuthServiceServer) AuthorizePAT(context.Context, *AuthZPatReq) (*AuthZRes, error) {
return nil, status.Errorf(codes.Unimplemented, "method AuthorizePAT 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")
}
func (UnimplementedAuthServiceServer) AuthenticatePAT(context.Context, *AuthNReq) (*AuthNRes, error) {
return nil, status.Errorf(codes.Unimplemented, "method AuthenticatePAT not implemented")
return nil, status.Error(codes.Unimplemented, "method Authenticate not implemented")
}
func (UnimplementedAuthServiceServer) mustEmbedUnimplementedAuthServiceServer() {}
func (UnimplementedAuthServiceServer) testEmbeddedByValue() {}
@@ -133,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.
@@ -161,24 +129,6 @@ func _AuthService_Authorize_Handler(srv interface{}, ctx context.Context, dec fu
return interceptor(ctx, in, info, handler)
}
func _AuthService_AuthorizePAT_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AuthZPatReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthServiceServer).AuthorizePAT(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthService_AuthorizePAT_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthServiceServer).AuthorizePAT(ctx, req.(*AuthZPatReq))
}
return interceptor(ctx, in, info, handler)
}
func _AuthService_Authenticate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AuthNReq)
if err := dec(in); err != nil {
@@ -197,24 +147,6 @@ func _AuthService_Authenticate_Handler(srv interface{}, ctx context.Context, dec
return interceptor(ctx, in, info, handler)
}
func _AuthService_AuthenticatePAT_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AuthNReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthServiceServer).AuthenticatePAT(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthService_AuthenticatePAT_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthServiceServer).AuthenticatePAT(ctx, req.(*AuthNReq))
}
return interceptor(ctx, in, info, handler)
}
// AuthService_ServiceDesc is the grpc.ServiceDesc for AuthService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
@@ -226,18 +158,10 @@ var AuthService_ServiceDesc = grpc.ServiceDesc{
MethodName: "Authorize",
Handler: _AuthService_Authorize_Handler,
},
{
MethodName: "AuthorizePAT",
Handler: _AuthService_AuthorizePAT_Handler,
},
{
MethodName: "Authenticate",
Handler: _AuthService_Authenticate_Handler,
},
{
MethodName: "AuthenticatePAT",
Handler: _AuthService_AuthenticatePAT_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "auth/v1/auth.proto",
+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.6
// protoc v6.30.2
// 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.30.2
// - 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.
+10 -19
View File
@@ -3,14 +3,14 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.6
// protoc v6.30.2
// 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"
@@ -27,8 +27,7 @@ const (
type AuthnReq struct {
state protoimpl.MessageState `protogen:"open.v1"`
ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"`
ClientSecret string `protobuf:"bytes,2,opt,name=client_secret,json=clientSecret,proto3" json:"client_secret,omitempty"`
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@@ -63,16 +62,9 @@ func (*AuthnReq) Descriptor() ([]byte, []int) {
return file_clients_v1_clients_proto_rawDescGZIP(), []int{0}
}
func (x *AuthnReq) GetClientId() string {
func (x *AuthnReq) GetToken() string {
if x != nil {
return x.ClientId
}
return ""
}
func (x *AuthnReq) GetClientSecret() string {
if x != nil {
return x.ClientSecret
return x.Token
}
return ""
}
@@ -294,10 +286,9 @@ var File_clients_v1_clients_proto protoreflect.FileDescriptor
const file_clients_v1_clients_proto_rawDesc = "" +
"\n" +
"\x18clients/v1/clients.proto\x12\n" +
"clients.v1\x1a\x16common/v1/common.proto\"L\n" +
"\bAuthnReq\x12\x1b\n" +
"\tclient_id\x18\x01 \x01(\tR\bclientId\x12#\n" +
"\rclient_secret\x18\x02 \x01(\tR\fclientSecret\"@\n" +
"clients.v1\x1a\x16common/v1/common.proto\" \n" +
"\bAuthnReq\x12\x14\n" +
"\x05token\x18\x01 \x01(\tR\x05token\"@\n" +
"\bAuthnRes\x12$\n" +
"\rauthenticated\x18\x01 \x01(\bR\rauthenticated\x12\x0e\n" +
"\x02id\x18\x02 \x01(\tR\x02id\"<\n" +
@@ -315,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.30.2
// - 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.6
// protoc v6.30.2
// 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.6
// protoc v6.30.2
// 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.30.2
// - 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.6
// protoc v6.30.2
// 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.30.2
// - 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",
}
+303 -25
View File
@@ -3,8 +3,8 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.6
// protoc v6.30.2
// protoc-gen-go v1.36.11
// protoc v7.35.1
// source: token/v1/token.proto
package v1
@@ -29,6 +29,8 @@ type IssueReq struct {
UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
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
}
@@ -84,9 +86,24 @@ func (x *IssueReq) GetType() uint32 {
return 0
}
func (x *IssueReq) GetVerified() bool {
if x != nil {
return x.Verified
}
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"`
Verified bool `protobuf:"varint,2,opt,name=verified,proto3" json:"verified,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@@ -128,6 +145,65 @@ func (x *RefreshReq) GetRefreshToken() string {
return ""
}
func (x *RefreshReq) GetVerified() bool {
if x != nil {
return x.Verified
}
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.
@@ -142,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)
}
@@ -154,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 {
@@ -167,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 {
@@ -191,27 +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\"T\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\"1\n" +
"\x04type\x18\x03 \x01(\rR\x04type\x12\x1a\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\"\x87\x01\n" +
"\rrefresh_token\x18\x01 \x01(\tR\frefreshToken\x12\x1a\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
@@ -225,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() }
@@ -248,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.30.2
// - 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",
+428
View File
@@ -0,0 +1,428 @@
// 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: users/v1/users.proto
package v1
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
structpb "google.golang.org/protobuf/types/known/structpb"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
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 RetrieveUsersReq struct {
state protoimpl.MessageState `protogen:"open.v1"`
Ids []string `protobuf:"bytes,1,rep,name=ids,proto3" json:"ids,omitempty"`
Offset uint64 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"`
Limit uint64 `protobuf:"varint,3,opt,name=limit,proto3" json:"limit,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RetrieveUsersReq) Reset() {
*x = RetrieveUsersReq{}
mi := &file_users_v1_users_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RetrieveUsersReq) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RetrieveUsersReq) ProtoMessage() {}
func (x *RetrieveUsersReq) ProtoReflect() protoreflect.Message {
mi := &file_users_v1_users_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 RetrieveUsersReq.ProtoReflect.Descriptor instead.
func (*RetrieveUsersReq) Descriptor() ([]byte, []int) {
return file_users_v1_users_proto_rawDescGZIP(), []int{0}
}
func (x *RetrieveUsersReq) GetIds() []string {
if x != nil {
return x.Ids
}
return nil
}
func (x *RetrieveUsersReq) GetOffset() uint64 {
if x != nil {
return x.Offset
}
return 0
}
func (x *RetrieveUsersReq) GetLimit() uint64 {
if x != nil {
return x.Limit
}
return 0
}
type RetrieveUsersRes struct {
state protoimpl.MessageState `protogen:"open.v1"`
Total uint64 `protobuf:"varint,1,opt,name=total,proto3" json:"total,omitempty"`
Limit uint64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"`
Offset uint64 `protobuf:"varint,3,opt,name=offset,proto3" json:"offset,omitempty"`
Users []*User `protobuf:"bytes,4,rep,name=users,proto3" json:"users,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RetrieveUsersRes) Reset() {
*x = RetrieveUsersRes{}
mi := &file_users_v1_users_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RetrieveUsersRes) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RetrieveUsersRes) ProtoMessage() {}
func (x *RetrieveUsersRes) ProtoReflect() protoreflect.Message {
mi := &file_users_v1_users_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 RetrieveUsersRes.ProtoReflect.Descriptor instead.
func (*RetrieveUsersRes) Descriptor() ([]byte, []int) {
return file_users_v1_users_proto_rawDescGZIP(), []int{1}
}
func (x *RetrieveUsersRes) GetTotal() uint64 {
if x != nil {
return x.Total
}
return 0
}
func (x *RetrieveUsersRes) GetLimit() uint64 {
if x != nil {
return x.Limit
}
return 0
}
func (x *RetrieveUsersRes) GetOffset() uint64 {
if x != nil {
return x.Offset
}
return 0
}
func (x *RetrieveUsersRes) GetUsers() []*User {
if x != nil {
return x.Users
}
return nil
}
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"`
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() {
*x = User{}
mi := &file_users_v1_users_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *User) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*User) ProtoMessage() {}
func (x *User) ProtoReflect() protoreflect.Message {
mi := &file_users_v1_users_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 User.ProtoReflect.Descriptor instead.
func (*User) Descriptor() ([]byte, []int) {
return file_users_v1_users_proto_rawDescGZIP(), []int{2}
}
func (x *User) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (x *User) GetFirstName() string {
if x != nil {
return x.FirstName
}
return ""
}
func (x *User) GetLastName() string {
if x != nil {
return x.LastName
}
return ""
}
func (x *User) GetTags() []string {
if x != nil {
return x.Tags
}
return nil
}
func (x *User) GetMetadata() *structpb.Struct {
if x != nil {
return x.Metadata
}
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
}
return 0
}
func (x *User) GetRole() uint32 {
if x != nil {
return x.Role
}
return 0
}
func (x *User) GetProfilePicture() string {
if x != nil {
return x.ProfilePicture
}
return ""
}
func (x *User) GetUsername() string {
if x != nil {
return x.Username
}
return ""
}
func (x *User) GetEmail() string {
if x != nil {
return x.Email
}
return ""
}
func (x *User) GetCreatedAt() *timestamppb.Timestamp {
if x != nil {
return x.CreatedAt
}
return nil
}
func (x *User) GetUpdatedAt() *timestamppb.Timestamp {
if x != nil {
return x.UpdatedAt
}
return nil
}
func (x *User) GetUpdatedBy() string {
if x != nil {
return x.UpdatedBy
}
return ""
}
func (x *User) GetVerifiedAt() *timestamppb.Timestamp {
if x != nil {
return x.VerifiedAt
}
return nil
}
func (x *User) GetAuthProvider() string {
if x != nil {
return x.AuthProvider
}
return ""
}
func (x *User) GetPermissions() []string {
if x != nil {
return x.Permissions
}
return nil
}
var File_users_v1_users_proto protoreflect.FileDescriptor
const file_users_v1_users_proto_rawDesc = "" +
"\n" +
"\x14users/v1/users.proto\x12\busers.v1\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"R\n" +
"\x10RetrieveUsersReq\x12\x10\n" +
"\x03ids\x18\x01 \x03(\tR\x03ids\x12\x16\n" +
"\x06offset\x18\x02 \x01(\x04R\x06offset\x12\x14\n" +
"\x05limit\x18\x03 \x01(\x04R\x05limit\"|\n" +
"\x10RetrieveUsersRes\x12\x14\n" +
"\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\"\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\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\f \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\x129\n" +
"\n" +
"updated_at\x18\r \x01(\v2\x1a.google.protobuf.TimestampR\tupdatedAt\x12\x1d\n" +
"\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\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\"\x00B1Z/github.com/absmach/magistrala/api/grpc/users/v1b\x06proto3"
var (
file_users_v1_users_proto_rawDescOnce sync.Once
file_users_v1_users_proto_rawDescData []byte
)
func file_users_v1_users_proto_rawDescGZIP() []byte {
file_users_v1_users_proto_rawDescOnce.Do(func() {
file_users_v1_users_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_users_v1_users_proto_rawDesc), len(file_users_v1_users_proto_rawDesc)))
})
return file_users_v1_users_proto_rawDescData
}
var file_users_v1_users_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_users_v1_users_proto_goTypes = []any{
(*RetrieveUsersReq)(nil), // 0: users.v1.RetrieveUsersReq
(*RetrieveUsersRes)(nil), // 1: users.v1.RetrieveUsersRes
(*User)(nil), // 2: users.v1.User
(*structpb.Struct)(nil), // 3: google.protobuf.Struct
(*timestamppb.Timestamp)(nil), // 4: google.protobuf.Timestamp
}
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
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() }
func file_users_v1_users_proto_init() {
if File_users_v1_users_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_users_v1_users_proto_rawDesc), len(file_users_v1_users_proto_rawDesc)),
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_users_v1_users_proto_goTypes,
DependencyIndexes: file_users_v1_users_proto_depIdxs,
MessageInfos: file_users_v1_users_proto_msgTypes,
}.Build()
File_users_v1_users_proto = out.File
file_users_v1_users_proto_goTypes = nil
file_users_v1_users_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: users/v1/users.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 (
UsersService_RetrieveUsers_FullMethodName = "/users.v1.UsersService/RetrieveUsers"
)
// UsersServiceClient is the client API for UsersService 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.
//
// UsersService exposes user-related functionality over gRPC.
type UsersServiceClient interface {
// RetrieveUsers fetches users for the provided IDs.
RetrieveUsers(ctx context.Context, in *RetrieveUsersReq, opts ...grpc.CallOption) (*RetrieveUsersRes, error)
}
type usersServiceClient struct {
cc grpc.ClientConnInterface
}
func NewUsersServiceClient(cc grpc.ClientConnInterface) UsersServiceClient {
return &usersServiceClient{cc}
}
func (c *usersServiceClient) RetrieveUsers(ctx context.Context, in *RetrieveUsersReq, opts ...grpc.CallOption) (*RetrieveUsersRes, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(RetrieveUsersRes)
err := c.cc.Invoke(ctx, UsersService_RetrieveUsers_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// UsersServiceServer is the server API for UsersService service.
// All implementations must embed UnimplementedUsersServiceServer
// for forward compatibility.
//
// UsersService exposes user-related functionality over gRPC.
type UsersServiceServer interface {
// RetrieveUsers fetches users for the provided IDs.
RetrieveUsers(context.Context, *RetrieveUsersReq) (*RetrieveUsersRes, error)
mustEmbedUnimplementedUsersServiceServer()
}
// UnimplementedUsersServiceServer 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 UnimplementedUsersServiceServer struct{}
func (UnimplementedUsersServiceServer) RetrieveUsers(context.Context, *RetrieveUsersReq) (*RetrieveUsersRes, error) {
return nil, status.Error(codes.Unimplemented, "method RetrieveUsers not implemented")
}
func (UnimplementedUsersServiceServer) mustEmbedUnimplementedUsersServiceServer() {}
func (UnimplementedUsersServiceServer) testEmbeddedByValue() {}
// UnsafeUsersServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to UsersServiceServer will
// result in compilation errors.
type UnsafeUsersServiceServer interface {
mustEmbedUnimplementedUsersServiceServer()
}
func RegisterUsersServiceServer(s grpc.ServiceRegistrar, srv UsersServiceServer) {
// 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.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&UsersService_ServiceDesc, srv)
}
func _UsersService_RetrieveUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RetrieveUsersReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(UsersServiceServer).RetrieveUsers(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: UsersService_RetrieveUsers_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(UsersServiceServer).RetrieveUsers(ctx, req.(*RetrieveUsersReq))
}
return interceptor(ctx, in, info, handler)
}
// UsersService_ServiceDesc is the grpc.ServiceDesc for UsersService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var UsersService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "users.v1.UsersService",
HandlerType: (*UsersServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "RetrieveUsers",
Handler: _UsersService_RetrieveUsers_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "users/v1/users.proto",
}
-54
View File
@@ -1,54 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package http
import (
"context"
"net/http"
apiutil "github.com/absmach/supermq/api/http/util"
"github.com/absmach/supermq/auth"
smqauthn "github.com/absmach/supermq/pkg/authn"
"github.com/go-chi/chi/v5"
)
type sessionKeyType string
const SessionKey = sessionKeyType("session")
func AuthenticateMiddleware(authn smqauthn.Authentication, domainCheck bool) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := apiutil.ExtractBearerToken(r)
if token == "" {
EncodeError(r.Context(), apiutil.ErrBearerToken, w)
return
}
resp, err := authn.Authenticate(r.Context(), token)
if err != nil {
EncodeError(r.Context(), err, w)
return
}
if domainCheck {
domain := chi.URLParam(r, "domainID")
if domain == "" {
EncodeError(r.Context(), apiutil.ErrMissingDomainID, w)
return
}
resp.DomainID = domain
switch resp.Role {
case smqauthn.AdminRole:
resp.DomainUserID = resp.UserID
case smqauthn.UserRole:
resp.DomainUserID = auth.EncodeDomainUserID(domain, resp.UserID)
}
}
ctx := context.WithValue(r.Context(), SessionKey, resp)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}
+83 -143
View File
@@ -7,17 +7,13 @@ import (
"context"
"encoding/json"
"net/http"
"net/mail"
"regexp"
"strings"
"github.com/absmach/supermq"
apiutil "github.com/absmach/supermq/api/http/util"
"github.com/absmach/supermq/certs"
"github.com/absmach/supermq/clients"
"github.com/absmach/supermq/groups"
"github.com/absmach/supermq/pkg/errors"
svcerr "github.com/absmach/supermq/pkg/errors/service"
"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"
)
@@ -28,14 +24,17 @@ const (
LimitKey = "limit"
OnlyTotal = "only_total"
NameOrder = "name"
IDOrder = "id"
AscDir = "asc"
DescDir = "desc"
NameOrder = "name"
IDOrder = "id"
AscDir = "asc"
DescDir = "desc"
UpdatedAtOrder = "updated_at"
CreatedAtOrder = "created_at"
MetadataKey = "metadata"
NameKey = "name"
TagKey = "tag"
TagsKey = "tags"
StatusKey = "status"
ClientKey = "client"
@@ -72,15 +71,15 @@ const (
DefTotal = uint64(100)
DefOffset = 0
DefOrder = "updated_at"
DefDir = "asc"
DefDir = "desc"
DefLimit = 10
DefLevel = 0
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"
@@ -108,6 +107,13 @@ func ValidateUUID(extID string) (err error) {
return nil
}
func ValidateEmail(email string) (err error) {
if _, err := mail.ParseAddress(email); err != nil {
return apiutil.ErrInvalidEmail
}
return nil
}
// ValidateName validates name format.
func ValidateName(id string) error {
if !nameRegExp.MatchString(id) {
@@ -148,8 +154,8 @@ func ValidateUserName(name string) error {
}
// EncodeResponse encodes successful response.
func EncodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error {
if ar, ok := response.(supermq.Response); ok {
func EncodeResponse(_ context.Context, w http.ResponseWriter, response any) error {
if ar, ok := response.(magistrala.Response); ok {
for k, v := range ar.Headers() {
w.Header().Set(k, v)
}
@@ -166,137 +172,71 @@ func EncodeResponse(_ context.Context, w http.ResponseWriter, response interface
// EncodeError encodes an error response.
func EncodeError(_ context.Context, err error, w http.ResponseWriter) {
var wrapper error
if errors.Contains(err, apiutil.ErrValidation) {
wrapper, err = errors.Unwrap(err)
w.Header().Set("Content-Type", ContentType)
if sdkErr, ok := err.(errors.SDKError); ok {
w.WriteHeader(sdkErr.StatusCode())
if err := json.NewEncoder(w).Encode(sdkErr); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
return
}
w.Header().Set("Content-Type", ContentType)
switch {
case errors.Contains(err, svcerr.ErrAuthorization),
errors.Contains(err, svcerr.ErrDomainAuthorization),
errors.Contains(err, svcerr.ErrUnauthorizedPAT):
err = unwrap(err)
w.WriteHeader(http.StatusForbidden)
case errors.Contains(err, svcerr.ErrAuthentication),
errors.Contains(err, apiutil.ErrBearerToken),
errors.Contains(err, svcerr.ErrLogin),
errors.Contains(err, apiutil.ErrUnsupportedTokenType):
err = unwrap(err)
if errors.Contains(err, errors.ErrAuthentication) {
w.WriteHeader(http.StatusUnauthorized)
case errors.Contains(err, svcerr.ErrMalformedEntity),
errors.Contains(err, apiutil.ErrMalformedPolicy),
errors.Contains(err, apiutil.ErrMissingSecret),
errors.Contains(err, errors.ErrMalformedEntity),
errors.Contains(err, apiutil.ErrMissingID),
errors.Contains(err, apiutil.ErrMissingName),
errors.Contains(err, apiutil.ErrMissingEmail),
errors.Contains(err, apiutil.ErrInvalidEmail),
errors.Contains(err, apiutil.ErrMissingHost),
errors.Contains(err, apiutil.ErrInvalidResetPass),
errors.Contains(err, apiutil.ErrEmptyList),
errors.Contains(err, apiutil.ErrMissingMemberKind),
errors.Contains(err, apiutil.ErrMissingMemberType),
errors.Contains(err, apiutil.ErrLimitSize),
errors.Contains(err, apiutil.ErrBearerKey),
errors.Contains(err, svcerr.ErrInvalidStatus),
errors.Contains(err, apiutil.ErrNameSize),
errors.Contains(err, apiutil.ErrInvalidIDFormat),
errors.Contains(err, apiutil.ErrInvalidQueryParams),
errors.Contains(err, apiutil.ErrMissingRelation),
errors.Contains(err, apiutil.ErrValidation),
errors.Contains(err, apiutil.ErrMissingPass),
errors.Contains(err, apiutil.ErrMissingConfPass),
errors.Contains(err, apiutil.ErrPasswordFormat),
errors.Contains(err, svcerr.ErrInvalidRole),
errors.Contains(err, svcerr.ErrInvalidPolicy),
errors.Contains(err, apiutil.ErrInvitationState),
errors.Contains(err, apiutil.ErrInvalidAPIKey),
errors.Contains(err, svcerr.ErrViewEntity),
errors.Contains(err, apiutil.ErrMissingCertData),
errors.Contains(err, apiutil.ErrInvalidContact),
errors.Contains(err, apiutil.ErrInvalidTopic),
errors.Contains(err, apiutil.ErrInvalidCertData),
errors.Contains(err, apiutil.ErrEmptyMessage),
errors.Contains(err, apiutil.ErrInvalidLevel),
errors.Contains(err, apiutil.ErrInvalidDirection),
errors.Contains(err, apiutil.ErrInvalidEntityType),
errors.Contains(err, apiutil.ErrMissingEntityType),
errors.Contains(err, apiutil.ErrInvalidTimeFormat),
errors.Contains(err, svcerr.ErrSearch),
errors.Contains(err, apiutil.ErrEmptySearchQuery),
errors.Contains(err, apiutil.ErrLenSearchQuery),
errors.Contains(err, apiutil.ErrMissingDomainID),
errors.Contains(err, certs.ErrFailedReadFromPKI),
errors.Contains(err, apiutil.ErrMissingUserID),
errors.Contains(err, apiutil.ErrMissingPATID),
errors.Contains(err, apiutil.ErrMissingUsername),
errors.Contains(err, apiutil.ErrMissingUsernameEmail),
errors.Contains(err, apiutil.ErrMissingFirstName),
errors.Contains(err, apiutil.ErrMissingLastName),
errors.Contains(err, apiutil.ErrInvalidUsername),
errors.Contains(err, apiutil.ErrMissingIdentity),
errors.Contains(err, apiutil.ErrInvalidProfilePictureURL),
errors.Contains(err, apiutil.ErrSelfParentingNotAllowed),
errors.Contains(err, apiutil.ErrMissingChildrenGroupIDs),
errors.Contains(err, apiutil.ErrMissingParentGroupID),
errors.Contains(err, apiutil.ErrMissingConnectionType),
errors.Contains(err, apiutil.ErrMissingRoleName),
errors.Contains(err, apiutil.ErrMissingRoleID),
errors.Contains(err, apiutil.ErrMissingPolicyEntityType),
errors.Contains(err, apiutil.ErrMissingRoleMembers),
errors.Contains(err, apiutil.ErrMissingDescription),
errors.Contains(err, apiutil.ErrMissingEntityID),
errors.Contains(err, apiutil.ErrInvalidRouteFormat),
errors.Contains(err, svcerr.ErrRetainOneMember),
errors.Contains(err, apiutil.ErrMissingRoute):
err = unwrap(err)
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)
case errors.Contains(err, svcerr.ErrCreateEntity),
errors.Contains(err, svcerr.ErrUpdateEntity),
errors.Contains(err, svcerr.ErrRemoveEntity),
errors.Contains(err, svcerr.ErrEnableClient),
errors.Contains(err, svcerr.ErrEnableUser),
errors.Contains(err, svcerr.ErrDisableUser):
err = unwrap(err)
w.WriteHeader(http.StatusUnprocessableEntity)
case errors.Contains(err, svcerr.ErrNotFound):
err = unwrap(err)
w.WriteHeader(http.StatusNotFound)
case errors.Contains(err, errors.ErrStatusAlreadyAssigned),
errors.Contains(err, svcerr.ErrInvitationAlreadyRejected),
errors.Contains(err, svcerr.ErrInvitationAlreadyAccepted),
errors.Contains(err, svcerr.ErrConflict):
err = unwrap(err)
w.WriteHeader(http.StatusConflict)
case errors.Contains(err, apiutil.ErrUnsupportedContentType):
err = unwrap(err)
if err := json.NewEncoder(w).Encode(retErr); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
return
case *errors.AuthNError:
w.WriteHeader(http.StatusUnauthorized)
if err := json.NewEncoder(w).Encode(retErr); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
return
case *errors.AuthZError:
w.WriteHeader(http.StatusForbidden)
if err := json.NewEncoder(w).Encode(retErr); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
return
case *errors.MediaTypeError:
w.WriteHeader(http.StatusUnsupportedMediaType)
if err := json.NewEncoder(w).Encode(retErr); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
return
case *errors.ServiceError:
w.WriteHeader(http.StatusUnprocessableEntity)
if err := json.NewEncoder(w).Encode(retErr); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
return
case *errors.NotFoundError:
w.WriteHeader(http.StatusNotFound)
if err := json.NewEncoder(w).Encode(retErr); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
return
case *errors.InternalError:
w.WriteHeader(http.StatusInternalServerError)
return
default:
w.WriteHeader(http.StatusInternalServerError)
}
if wrapper != nil {
err = errors.Wrap(wrapper, err)
}
if errorVal, ok := err.(errors.Error); ok {
if err := json.NewEncoder(w).Encode(errorVal); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}
}
func unwrap(err error) error {
wrapper, err := errors.Unwrap(err)
if wrapper != nil {
return wrapper
}
return err
}
+95 -100
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{})
@@ -115,7 +115,7 @@ func TestEncodeResponse(t *testing.T) {
cases := []struct {
desc string
resp interface{}
resp any
header http.Header
code int
body []byte
@@ -218,121 +218,116 @@ func TestEncodeResponse(t *testing.T) {
func TestEncodeError(t *testing.T) {
cases := []struct {
desc string
errs []error
code int
desc string
err error
code int
hasBody bool
checkError bool
}{
{
desc: "BadRequest",
errs: []error{
apiutil.ErrMissingSecret,
svcerr.ErrMalformedEntity,
errors.ErrMalformedEntity,
apiutil.ErrMissingID,
apiutil.ErrEmptyList,
apiutil.ErrMissingMemberType,
apiutil.ErrMissingMemberKind,
apiutil.ErrLimitSize,
apiutil.ErrNameSize,
svcerr.ErrViewEntity,
},
code: http.StatusBadRequest,
desc: "RequestError - Missing Secret",
err: apiutil.ErrMissingSecret,
code: http.StatusBadRequest,
hasBody: true,
},
{
desc: "BadRequest with validation error",
errs: []error{
errors.Wrap(apiutil.ErrValidation, apiutil.ErrMissingSecret),
errors.Wrap(apiutil.ErrValidation, svcerr.ErrMalformedEntity),
errors.Wrap(apiutil.ErrValidation, errors.ErrMalformedEntity),
errors.Wrap(apiutil.ErrValidation, apiutil.ErrMissingID),
errors.Wrap(apiutil.ErrValidation, apiutil.ErrEmptyList),
errors.Wrap(apiutil.ErrValidation, apiutil.ErrMissingMemberType),
errors.Wrap(apiutil.ErrValidation, apiutil.ErrMissingMemberKind),
errors.Wrap(apiutil.ErrValidation, apiutil.ErrLimitSize),
errors.Wrap(apiutil.ErrValidation, apiutil.ErrNameSize),
},
code: http.StatusBadRequest,
desc: "RequestError - Missing ID",
err: apiutil.ErrMissingID,
code: http.StatusBadRequest,
hasBody: true,
},
{
desc: "Unauthorized",
errs: []error{
svcerr.ErrAuthentication,
svcerr.ErrAuthentication,
apiutil.ErrBearerToken,
},
code: http.StatusUnauthorized,
},
{
desc: "NotFound",
errs: []error{
svcerr.ErrNotFound,
},
code: http.StatusNotFound,
desc: "RequestError - Empty List",
err: apiutil.ErrEmptyList,
code: http.StatusBadRequest,
hasBody: true,
},
{
desc: "Conflict",
errs: []error{
svcerr.ErrConflict,
svcerr.ErrConflict,
},
code: http.StatusConflict,
desc: "RequestError - Conflict",
err: svcerr.ErrConflict,
code: http.StatusBadRequest,
hasBody: true,
},
{
desc: "Forbidden",
errs: []error{
svcerr.ErrAuthorization,
svcerr.ErrAuthorization,
svcerr.ErrDomainAuthorization,
},
code: http.StatusForbidden,
desc: "NotFoundError - Not Found",
err: svcerr.ErrNotFound,
code: http.StatusNotFound,
hasBody: true,
},
{
desc: "UnsupportedMediaType",
errs: []error{
apiutil.ErrUnsupportedContentType,
},
code: http.StatusUnsupportedMediaType,
desc: "AuthNError - Authentication Failed",
err: svcerr.ErrAuthentication,
code: http.StatusUnauthorized,
hasBody: true,
},
{
desc: "StatusUnprocessableEntity",
errs: []error{
svcerr.ErrCreateEntity,
svcerr.ErrUpdateEntity,
svcerr.ErrRemoveEntity,
},
code: http.StatusUnprocessableEntity,
desc: "Generic Authentication Failed",
err: errors.ErrAuthentication,
code: http.StatusUnauthorized,
hasBody: true,
},
{
desc: "InternalServerError",
errs: []error{
errors.New("test"),
},
code: http.StatusInternalServerError,
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,
code: http.StatusForbidden,
hasBody: true,
},
{
desc: "MediaTypeError - Unsupported Content Type",
err: apiutil.ErrUnsupportedContentType,
code: http.StatusUnsupportedMediaType,
hasBody: true,
},
{
desc: "ServiceError - Create Entity Failed",
err: svcerr.ErrCreateEntity,
code: http.StatusUnprocessableEntity,
hasBody: true,
},
{
desc: "ServiceError - Update Entity Failed",
err: svcerr.ErrUpdateEntity,
code: http.StatusUnprocessableEntity,
hasBody: true,
},
{
desc: "ServiceError - Remove Entity Failed",
err: svcerr.ErrRemoveEntity,
code: http.StatusUnprocessableEntity,
hasBody: true,
},
{
desc: "InternalError",
err: errors.NewInternalError(),
code: http.StatusInternalServerError,
hasBody: false,
},
}
for _, c := range cases {
t.Run(c.desc, func(t *testing.T) {
responseWriter := newResponseWriter()
for _, err := range c.errs {
api.EncodeError(context.Background(), err, responseWriter)
assert.Equal(t, c.code, responseWriter.StatusCode())
message := body{}
jerr := json.Unmarshal(responseWriter.Body(), &message)
assert.NoError(t, jerr)
var wrapper error
switch errors.Contains(err, apiutil.ErrValidation) {
case true:
wrapper, err = errors.Unwrap(err)
assert.Equal(t, err.Error(), message.Error)
assert.Equal(t, wrapper.Error(), message.Message)
case false:
assert.Equal(t, err.Error(), message.Message)
}
api.EncodeError(context.Background(), c.err, responseWriter)
assert.Equal(t, c.code, responseWriter.StatusCode())
if !c.hasBody {
return
}
message := body{}
jerr := json.Unmarshal(responseWriter.Body(), &message)
assert.NoError(t, jerr)
assert.NotEmpty(t, message.Message)
})
}
}
+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()
+96 -87
View File
@@ -3,269 +3,278 @@
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
// errors are logged twice.
var (
// ErrValidation indicates that an error was returned by the API.
ErrValidation = errors.New("something went wrong with the request")
ErrValidation = errors.NewRequestError("something went wrong with the request")
// ErrBearerToken indicates missing or invalid bearer user token.
ErrBearerToken = errors.New("missing or invalid bearer user token")
ErrBearerToken = errors.NewAuthNError("missing or invalid bearer user token")
// ErrBearerKey indicates missing or invalid bearer entity key.
ErrBearerKey = errors.New("missing or invalid bearer entity key")
ErrBearerKey = errors.NewAuthNError("missing or invalid bearer entity key")
// ErrMissingID indicates missing entity ID.
ErrMissingID = errors.New("missing entity id")
ErrMissingID = errors.NewRequestError("missing entity id")
// ErrMissingEntityID indicates missing entity ID.
ErrMissingEntityID = errors.New("missing entity id")
ErrMissingEntityID = errors.NewRequestError("missing entity id")
// ErrMissingClientID indicates missing client ID.
ErrMissingClientID = errors.New("missing cient id")
ErrMissingClientID = errors.NewRequestError("missing client id")
// ErrMissingChannelID indicates missing client ID.
ErrMissingChannelID = errors.New("missing channel id")
ErrMissingChannelID = errors.NewRequestError("missing channel id")
// ErrMissingConnectionType indicates missing connection tpye.
ErrMissingConnectionType = errors.New("missing connection type")
ErrMissingConnectionType = errors.NewRequestError("missing connection type")
// ErrMissingParentGroupID indicates missing parent group ID.
ErrMissingParentGroupID = errors.New("missing parent group id")
ErrMissingParentGroupID = errors.NewRequestError("missing parent group id")
// ErrMissingChildrenGroupIDs indicates missing children group IDs.
ErrMissingChildrenGroupIDs = errors.New("missing children group ids")
ErrMissingChildrenGroupIDs = errors.NewRequestError("missing children group ids")
// ErrSelfParentingNotAllowed indicates child id is same as parent id.
ErrSelfParentingNotAllowed = errors.New("self parenting not allowed")
ErrSelfParentingNotAllowed = errors.NewRequestError("self parenting not allowed")
// ErrInvalidChildGroupID indicates invalid child group ID.
ErrInvalidChildGroupID = errors.New("invalid child group id")
ErrInvalidChildGroupID = errors.NewRequestError("invalid child group id")
// ErrInvalidAuthKey indicates invalid auth key.
ErrInvalidAuthKey = errors.New("invalid auth key")
// ErrInvalidIDFormat indicates an invalid ID format.
ErrInvalidIDFormat = errors.New("invalid id format provided")
ErrInvalidIDFormat = errors.NewRequestError("invalid id format provided")
// ErrNameSize indicates that name size exceeds the max.
ErrNameSize = errors.New("invalid name size")
ErrNameSize = errors.NewRequestError("invalid name size")
// ErrEmailSize indicates that email size exceeds the max.
ErrEmailSize = errors.New("invalid email size")
ErrEmailSize = errors.NewRequestError("invalid email size")
// ErrInvalidRole indicates that an invalid role.
ErrInvalidRole = errors.New("invalid client role")
ErrInvalidRole = errors.NewRequestError("invalid client role")
// ErrLimitSize indicates that an invalid limit.
ErrLimitSize = errors.New("invalid limit size")
ErrLimitSize = errors.NewRequestError("invalid limit size")
// ErrLevel indicates that an invalid level.
ErrLevel = errors.New("invalid level")
ErrLevel = errors.NewRequestError("invalid level")
// ErrOffsetSize indicates an invalid offset.
ErrOffsetSize = errors.New("invalid offset size")
ErrOffsetSize = errors.NewRequestError("invalid offset size")
// ErrInvalidOrder indicates an invalid list order.
ErrInvalidOrder = errors.New("invalid list order provided")
ErrInvalidOrder = errors.NewRequestError("invalid list order provided")
// ErrInvalidDirection indicates an invalid list direction.
ErrInvalidDirection = errors.New("invalid list direction provided")
ErrInvalidDirection = errors.NewRequestError("invalid list direction provided")
// ErrInvalidMemberKind indicates an invalid member kind.
ErrInvalidMemberKind = errors.New("invalid member kind")
ErrInvalidMemberKind = errors.NewRequestError("invalid member kind")
// ErrEmptyList indicates that entity data is empty.
ErrEmptyList = errors.New("empty list provided")
ErrEmptyList = errors.NewRequestError("empty list provided")
// ErrMissingRoleName indicates that role name is empty.
ErrMissingRoleName = errors.New("empty role name")
ErrMissingRoleName = errors.NewRequestError("empty role name")
// ErrMissingRoleID indicates that role id is empty.
ErrMissingRoleID = errors.New("empty role id")
ErrMissingRoleID = errors.NewRequestError("empty role id")
// ErrMissingRoleOperations indicates that role operations are empty.
ErrMissingRoleOperations = errors.New("empty role operations")
ErrMissingRoleOperations = errors.NewRequestError("empty role operations")
// ErrMissingRoleMembers indicates that role members are empty.
ErrMissingRoleMembers = errors.New("empty role members")
ErrMissingRoleMembers = errors.NewRequestError("empty role members")
// ErrMalformedPolicy indicates that policies are malformed.
ErrMalformedPolicy = errors.New("malformed policy")
ErrMalformedPolicy = errors.NewRequestError("malformed policy")
// ErrMissingPolicySub indicates that policies are subject.
ErrMissingPolicySub = errors.New("malformed policy subject")
ErrMissingPolicySub = errors.NewRequestError("malformed policy subject")
// ErrMissingPolicyObj indicates missing policies object.
ErrMissingPolicyObj = errors.New("malformed policy object")
ErrMissingPolicyObj = errors.NewRequestError("malformed policy object")
// ErrMalformedPolicyAct indicates missing policies action.
ErrMalformedPolicyAct = errors.New("malformed policy action")
ErrMalformedPolicyAct = errors.NewRequestError("malformed policy action")
// ErrMissingPolicyEntityType indicates missing policies entity type.
ErrMissingPolicyEntityType = errors.New("missing policy entity type")
ErrMissingPolicyEntityType = errors.NewRequestError("missing policy entity type")
// ErrMalformedPolicyPer indicates missing policies relation.
ErrMalformedPolicyPer = errors.New("malformed policy permission")
ErrMalformedPolicyPer = errors.NewRequestError("malformed policy permission")
// ErrMissingCertData indicates missing cert data (ttl).
ErrMissingCertData = errors.New("missing certificate data")
ErrMissingCertData = errors.NewRequestError("missing certificate data")
// ErrInvalidCertData indicates invalid cert data (ttl).
ErrInvalidCertData = errors.New("invalid certificate data")
ErrInvalidCertData = errors.NewRequestError("invalid certificate data")
// ErrInvalidTopic indicates an invalid subscription topic.
ErrInvalidTopic = errors.New("invalid Subscription topic")
ErrInvalidTopic = errors.NewRequestError("invalid Subscription topic")
// ErrInvalidContact indicates an invalid subscription contract.
ErrInvalidContact = errors.New("invalid Subscription contact")
ErrInvalidContact = errors.NewRequestError("invalid Subscription contact")
// ErrMissingEmail indicates missing email.
ErrMissingEmail = errors.New("missing email")
ErrMissingEmail = errors.NewRequestError("missing email")
// ErrInvalidEmail indicates missing email.
ErrInvalidEmail = errors.New("invalid email")
ErrInvalidEmail = errors.NewRequestError("invalid email")
// ErrMissingHost indicates missing host.
ErrMissingHost = errors.New("missing host")
ErrMissingHost = errors.NewRequestError("missing host")
// ErrMissingPass indicates missing password.
ErrMissingPass = errors.New("missing password")
ErrMissingPass = errors.NewRequestError("missing password")
// ErrMissingConfPass indicates missing conf password.
ErrMissingConfPass = errors.New("missing conf password")
ErrMissingConfPass = errors.NewRequestError("missing conf password")
// ErrInvalidResetPass indicates an invalid reset password.
ErrInvalidResetPass = errors.New("invalid reset password")
ErrInvalidResetPass = errors.NewRequestError("invalid reset password")
// ErrInvalidComparator indicates an invalid comparator.
ErrInvalidComparator = errors.New("invalid comparator")
ErrInvalidComparator = errors.NewRequestError("invalid comparator")
// ErrMissingMemberIDs indicates missing member ids.
ErrMissingMemberIDs = errors.New("missing member ids")
ErrMissingMemberIDs = errors.NewRequestError("missing member ids")
// ErrMissingMemberType indicates missing group member type.
ErrMissingMemberType = errors.New("missing group member type")
ErrMissingMemberType = errors.NewRequestError("missing group member type")
// ErrMissingMemberKind indicates missing group member kind.
ErrMissingMemberKind = errors.New("missing group member kind")
ErrMissingMemberKind = errors.NewRequestError("missing group member kind")
// ErrMissingRelation indicates missing relation.
ErrMissingRelation = errors.New("missing relation")
ErrMissingRelation = errors.NewRequestError("missing relation")
// ErrInvalidRelation indicates an invalid relation.
ErrInvalidRelation = errors.New("invalid relation")
ErrInvalidRelation = errors.NewRequestError("invalid relation")
// ErrInvalidAPIKey indicates an invalid API key type.
ErrInvalidAPIKey = errors.New("invalid api key type")
ErrInvalidAPIKey = errors.NewRequestError("invalid api key type")
// ErrInvitationState indicates an invalid invitation state.
ErrInvitationState = errors.New("invalid invitation state")
ErrInvitationState = errors.NewRequestError("invalid invitation state")
// ErrMissingIdentity indicates missing entity Identity.
ErrMissingIdentity = errors.New("missing entity identity")
ErrMissingIdentity = errors.NewRequestError("missing entity identity")
// ErrMissingSecret indicates missing secret.
ErrMissingSecret = errors.New("missing secret")
ErrMissingSecret = errors.NewRequestError("missing secret")
// ErrPasswordFormat indicates weak password.
ErrPasswordFormat = errors.New("password does not meet the requirements")
ErrPasswordFormat = errors.NewRequestError("password does not meet the requirements")
// ErrMissingName indicates missing identity name.
ErrMissingName = errors.New("missing identity name")
ErrMissingName = errors.NewRequestError("missing identity name")
// ErrMissingRoute indicates missing route.
ErrMissingRoute = errors.New("missing route")
ErrMissingRoute = errors.NewRequestError("missing route")
// ErrInvalidLevel indicates an invalid group level.
ErrInvalidLevel = errors.New("invalid group level (should be between 0 and 5)")
ErrInvalidLevel = errors.NewRequestError("invalid group level (should be between 0 and 5)")
// ErrNotFoundParam indicates that the parameter was not found in the query.
ErrNotFoundParam = errors.New("parameter not found in the query")
ErrNotFoundParam = errors.NewRequestError("parameter not found in the query")
// ErrInvalidQueryParams indicates invalid query parameters.
ErrInvalidQueryParams = errors.New("invalid query parameters")
ErrInvalidQueryParams = errors.NewRequestError("invalid query parameters")
// ErrInvalidVisibilityType indicates invalid visibility type.
ErrInvalidVisibilityType = errors.New("invalid visibility type")
ErrInvalidVisibilityType = errors.NewRequestError("invalid visibility type")
// ErrUnsupportedContentType indicates unacceptable or lack of Content-Type.
ErrUnsupportedContentType = errors.New("unsupported content type")
ErrUnsupportedContentType = errors.NewMediaTypeError("unsupported content type")
// ErrRollbackTx indicates failed to rollback transaction.
ErrRollbackTx = errors.New("failed to rollback transaction")
ErrRollbackTx = errors.NewRequestError("failed to rollback transaction")
// ErrInvalidAggregation indicates invalid aggregation value.
ErrInvalidAggregation = errors.New("invalid aggregation value")
ErrInvalidAggregation = errors.NewRequestError("invalid aggregation value")
// ErrInvalidInterval indicates invalid interval value.
ErrInvalidInterval = errors.New("invalid interval value")
ErrInvalidInterval = errors.NewRequestError("invalid interval value")
// ErrMissingFrom indicates missing from value.
ErrMissingFrom = errors.New("missing from time value")
ErrMissingFrom = errors.NewRequestError("missing from time value")
// ErrMissingTo indicates missing to value.
ErrMissingTo = errors.New("missing to time value")
ErrMissingTo = errors.NewRequestError("missing to time value")
// ErrEmptyMessage indicates empty message.
ErrEmptyMessage = errors.New("empty message")
ErrEmptyMessage = errors.NewRequestError("empty message")
// ErrMissingEntityType indicates missing entity type.
ErrMissingEntityType = errors.New("missing entity type")
ErrMissingEntityType = errors.NewRequestError("missing entity type")
// ErrInvalidEntityType indicates invalid entity type.
ErrInvalidEntityType = errors.New("invalid entity type")
ErrInvalidEntityType = errors.NewRequestError("invalid entity type")
// ErrInvalidTimeFormat indicates invalid time format i.e not unix time.
ErrInvalidTimeFormat = errors.New("invalid time format use unix time")
ErrInvalidTimeFormat = errors.NewRequestError("invalid time format use unix time")
// ErrEmptySearchQuery indicates search query should not be empty.
ErrEmptySearchQuery = errors.New("search query must not be empty")
ErrEmptySearchQuery = errors.NewRequestError("search query must not be empty")
// ErrLenSearchQuery indicates search query length.
ErrLenSearchQuery = errors.New("search query must be at least 3 characters")
ErrLenSearchQuery = errors.NewRequestError("search query must be at least 3 characters")
// ErrMissingDomainID indicates missing domainID.
ErrMissingDomainID = errors.New("missing domainID")
ErrMissingDomainID = errors.NewRequestError("missing domainID")
// ErrMissingUsername indicates missing user name.
ErrMissingUsername = errors.New("missing username")
ErrMissingUsername = errors.NewRequestError("missing username")
// ErrInvalidUsername indicates invalid user name.
ErrInvalidUsername = errors.New("invalid username")
ErrInvalidUsername = errors.NewRequestError("invalid username")
// ErrMissingFirstName indicates missing first name.
ErrMissingFirstName = errors.New("missing first name")
ErrMissingFirstName = errors.NewRequestError("missing first name")
// ErrMissingLastName indicates missing last name.
ErrMissingLastName = errors.New("missing last name")
ErrMissingLastName = errors.NewRequestError("missing last name")
// ErrInvalidProfilePictureURL indicates that the profile picture url is invalid.
ErrInvalidProfilePictureURL = errors.New("invalid profile picture url")
ErrInvalidProfilePictureURL = errors.NewRequestError("invalid profile picture url")
ErrMultipleEntitiesFilter = errors.New("multiple entities are provided in filter are not supported")
ErrMultipleEntitiesFilter = errors.NewRequestError("multiple entities are provided in filter are not supported")
// ErrMissingDescription indicates missing description.
ErrMissingDescription = errors.New("missing description")
ErrMissingDescription = errors.NewRequestError("missing description")
// ErrUnsupportedTokenType indicates that this type of token is not supported.
ErrUnsupportedTokenType = errors.New("unsupported content token type")
ErrUnsupportedTokenType = errors.NewRequestError("unsupported content token type")
// ErrMissingUserID indicates missing user ID.
ErrMissingUserID = errors.New("missing user id")
ErrMissingUserID = errors.NewRequestError("missing user id")
// ErrMissingPATID indicates missing pat ID.
ErrMissingPATID = errors.New("missing pat id")
ErrMissingPATID = errors.NewRequestError("missing pat id")
// ErrInvalidNameFormat indicates invalid name format.
ErrInvalidNameFormat = errors.New("invalid name format")
ErrInvalidNameFormat = errors.NewRequestError("invalid name format")
// ErrInvalidRouteFormat indicates invalid route format.
ErrInvalidRouteFormat = errors.New("invalid route format")
ErrInvalidRouteFormat = errors.NewRequestError("invalid route format")
// ErrMissingUsernameEmail indicates missing user name / email.
ErrMissingUsernameEmail = errors.New("missing username / email")
ErrMissingUsernameEmail = errors.NewRequestError("missing username / email")
// ErrInvalidVerification indicates invalid email verification.
ErrInvalidVerification = errors.NewRequestError("invalid verification")
// ErrEmailNotVerified indicates invalid email not verified.
ErrEmailNotVerified = errors.NewRequestError("email not verified")
// ErrMalformedRequest indicates malformed request body.
ErrMalformedRequestBody = errors.NewRequestError("request body is not a valid JSON, expecting a valid JSON")
)
+9 -4
View File
@@ -8,11 +8,16 @@ import (
"strings"
)
// BearerPrefix represents the token prefix for Bearer authentication scheme.
const BearerPrefix = "Bearer "
const (
// BearerPrefix represents the token prefix for Bearer authentication scheme.
BearerPrefix = "Bearer "
// ClientPrefix represents the key prefix for Client authentication scheme.
const ClientPrefix = "Client "
// ClientPrefix represents the key prefix for Client authentication scheme.
ClientPrefix = "Client "
// BasicAuthPrefix represents the prefix for Basic authentication scheme.
BasicAuthPrefix = "Basic "
)
// ExtractBearerToken returns value of the bearer token. If there is no bearer token - an empty value is returned.
func ExtractBearerToken(r *http.Request) string {
+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"
)
+3 -3
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"
)
@@ -39,7 +39,7 @@ func ReadStringQuery(r *http.Request, key, def string) (string, error) {
}
// ReadMetadataQuery reads the value of json http query parameters for a given key.
func ReadMetadataQuery(r *http.Request, key string, def map[string]interface{}) (map[string]interface{}, error) {
func ReadMetadataQuery(r *http.Request, key string, def map[string]any) (map[string]any, error) {
vals := r.URL.Query()[key]
if len(vals) > 1 {
return nil, ErrInvalidQueryParams
@@ -49,7 +49,7 @@ func ReadMetadataQuery(r *http.Request, key string, def map[string]interface{})
return def, nil
}
m := make(map[string]interface{})
m := make(map[string]any)
err := json.Unmarshal([]byte(vals[0]), &m)
if err != nil {
return nil, errors.Wrap(ErrInvalidQueryParams, err)
+9 -9
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"
)
@@ -67,14 +67,14 @@ func TestReadMetadataQuery(t *testing.T) {
desc string
url string
key string
ret map[string]interface{}
ret map[string]any
err error
}{
{
desc: "valid metadata query",
url: "http://localhost:8080/?key={\"test\":\"test\"}",
key: "key",
ret: map[string]interface{}{"test": "test"},
ret: map[string]any{"test": "test"},
err: nil,
},
{
@@ -177,7 +177,7 @@ func TestReadNumQuery(t *testing.T) {
url string
key string
numType string
ret interface{}
ret any
err error
}{
{
@@ -316,7 +316,7 @@ func TestReadNumQuery(t *testing.T) {
assert.NoError(t, err)
r := &http.Request{URL: parsedURL}
var ret interface{}
var ret any
switch c.numType {
case "int64":
ret, err = apiutil.ReadNumQuery[int64](r, c.key, 0)
@@ -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)
+7 -7
View File
@@ -2,21 +2,21 @@
# 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
version: '1.0.0'
title: Magistrala MQTT Adapter
version: '0.18.0'
contact:
name: SuperMQ Team
url: 'https://github.com/absmach/supermq'
email: info@abstractmachines.fr
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.
Additionally, the MQTT adapter and the message broker are replicating the traffic between brokers.
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
+10 -10
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: '1.0.0'
version: '0.18.0'
contact:
name: SuperMQ Team
url: 'https://github.com/absmach/supermq'
email: info@abstractmachines.fr
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,8 +28,8 @@ servers:
description: Hostname of the WebSocket adapter
default: localhost
port:
description: SuperMQ WebSocket Adapter port
default: '8186'
description: Magistrala WebSocket Adapter port
default: '8008'
channels:
'm/{domainPrefix}/c/{channelPrefix}/{subtopic}':
@@ -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.magistrala.abstractmachines.fr](https://docs.api.supermq.abstractmachines.fr)
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>"
+54 -43
View File
@@ -3,17 +3,17 @@
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@abstractmachines.fr
email: info@absmach.eu
license:
name: Apache 2.0
url: https://github.com/absmach/supermq/blob/main/LICENSE
version: 0.15.1
url: https://github.com/absmach/magistrala/blob/main/LICENSE
version: 0.18.0
servers:
- url: http://localhost:9001
@@ -24,17 +24,17 @@ tags:
description: Everything about your Keys.
externalDocs:
description: Find out more about keys
url: https://docs.supermq.abstractmachines.fr/
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.abstractmachines.fr/
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.abstractmachines.fr/
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
+642 -236
View File
@@ -1,140 +1,357 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
openapi: 3.0.1
openapi: 3.0.3
info:
title: SuperMQ Certs service
title: Certs Service API
description: |
HTTP API for Certs service
Some useful links:
- [The SuperMQ repository](https://github.com/absmach/supermq)
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:
email: info@abstractmachines.fr
name: Abstract Machines
license:
name: Apache 2.0
url: https://github.com/absmach/supermq/blob/main/LICENSE
version: 0.15.1
name: Apache-2.0
url: https://www.apache.org/licenses/LICENSE-2.0.html
servers:
- url: http://localhost:9019
- url: https://localhost:9019
description: Development server
tags:
- name: certs
description: Everything about your Certs
externalDocs:
description: Find out more about certs
url: https://docs.supermq.abstractmachines.fr/
- 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:
/{domainID}/certs/issue/{entityID}:
post:
operationId: createCert
summary: Creates a certificate for client
description: Creates a certificate for client
tags:
- certs
- 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: "auth.yaml#/components/parameters/DomainID"
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/EntityID'
requestBody:
$ref: "#/components/requestBodies/CertReq"
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/IssueCertRequest'
responses:
"201":
description: Created
"400":
description: Failed due to malformed JSON.
"401":
description: Missing or invalid access token provided.
"403":
description: Failed to perform authorization over the entity.
"415":
description: Missing or invalid content type.
"422":
description: Database can't process request.
"500":
$ref: "#/components/responses/ServiceError"
'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/{certID}:
get:
operationId: getCert
summary: Retrieves a certificate
description: |
Retrieves a certificate for a given cert ID.
/{domainID}/certs/{id}/renew:
patch:
tags:
- certs
- certificates
summary: Renew a certificate
description: Renews an existing certificate with extended TTL and new serial number
operationId: renewCert
security:
- BearerAuth: []
parameters:
- $ref: "auth.yaml#/components/parameters/DomainID"
- $ref: "#/components/parameters/CertID"
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/CertID'
responses:
"200":
$ref: "#/components/responses/CertRes"
"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: |
Failed to retrieve corresponding certificate.
"422":
description: Database can't process request.
"500":
$ref: "#/components/responses/ServiceError"
delete:
'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
summary: Revokes a certificate
description: |
Revokes a certificate for a given cert ID.
tags:
- certs
security:
- BearerAuth: []
parameters:
- $ref: "auth.yaml#/components/parameters/DomainID"
- $ref: "#/components/parameters/CertID"
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/CertID'
responses:
"200":
$ref: "#/components/responses/RevokeRes"
"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: |
Failed to revoke corresponding certificate.
"422":
description: Database can't process request.
"500":
$ref: "#/components/responses/ServiceError"
'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}/serials/{clientID}:
get:
operationId: getSerials
summary: Retrieves certificates' serial IDs
description: |
Retrieves a list of certificates' serial IDs for a given client ID.
/{domainID}/certs/{entityID}/delete:
delete:
tags:
- certs
- certificates
summary: Delete certificates for an entity
description: Deletes all certificates associated with the specified entity
operationId: deleteCert
security:
- BearerAuth: []
parameters:
- $ref: "auth.yaml#/components/parameters/DomainID"
- $ref: "#/components/parameters/ClientID"
- $ref: '#/components/parameters/DomainID'
- $ref: '#/components/parameters/EntityID'
responses:
"200":
$ref: "#/components/responses/SerialsPageRes"
"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: |
Failed to retrieve corresponding certificates.
"422":
description: Database can't process request.
"500":
$ref: "#/components/responses/ServiceError"
'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:
@@ -143,174 +360,363 @@ paths:
- health
security: []
responses:
"200":
$ref: "#/components/responses/HealthRes"
"500":
$ref: "#/components/responses/ServiceError"
'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:
ClientID:
name: clientID
description: Client ID
DomainID:
name: domainID
in: path
required: true
description: Domain identifier
schema:
type: string
format: uuid
EntityID:
name: entityID
in: path
required: true
description: Entity identifier for the certificate
schema:
type: string
CertID:
name: certID
description: Serial of certificate
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
format: uuid
required: true
schemas:
Cert:
IssueCertRequest:
type: object
required:
- options
properties:
client_id:
ttl:
type: string
format: uuid
description: Corresponding SuperMQ Client ID.
client_cert:
type: string
description: Client Certificate.
client_key:
type: string
description: Key for the client_cert.
issuing_ca:
type: string
description: CA Certificate that is used to issue client certs, usually intermediate.
serial:
type: string
description: Certificate serial
expire:
type: string
description: Certificate expiry date
Serial:
type: object
properties:
serial:
type: string
description: Certificate serial
CertsPage:
type: object
properties:
certs:
description: Time to live for the certificate (e.g., "8760h" for 1 year)
example: "8760h"
ip_addresses:
type: array
minItems: 0
uniqueItems: true
items:
$ref: "#/components/schemas/Cert"
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.
SerialsPage:
type: object
properties:
serials:
type: array
description: Certificate serials IDs.
minItems: 0
uniqueItems: true
items:
type: string
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.
Revoke:
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:
revocation_time:
serial_number:
type: string
description: Certificate revocation time
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"
requestBodies:
CertReq:
description: |
Issues a certificate that is required for mTLS. To create a certificate for a client
provide a client id, data identifying particular client will be embedded into the Certificate.
x509 and ECC certificates are supported when using when Vault is used as PKI.
content:
application/json:
schema:
type: object
required:
- client_id
- ttl
properties:
client_id:
type: string
format: uuid
ttl:
type: string
example: "10h"
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:
ServiceError:
description: Unexpected server-side error occurred.
CertRes:
description: Certificate data.
BadRequest:
description: Bad request - invalid parameters or malformed request
content:
application/json:
schema:
$ref: "#/components/schemas/Cert"
links:
serial:
operationId: getSerials
parameters:
clientID: $response.body#/client_id
delete:
operationId: revokeCert
parameters:
certID: $response.body#/serial
CertsPageRes:
description: Certificates page.
$ref: '#/components/schemas/Error'
Unauthorized:
description: Unauthorized - invalid or missing authentication token
content:
application/json:
schema:
$ref: "#/components/schemas/CertsPage"
SerialsPageRes:
description: Serials page.
$ref: '#/components/schemas/Error'
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: "#/components/schemas/SerialsPage"
RevokeRes:
description: Certificate revoked.
$ref: '#/components/schemas/Error'
UnprocessableEntity:
description: Unprocessable entity - request cannot be processed
content:
application/json:
schema:
$ref: "#/components/schemas/Revoke"
$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"
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: |
* Users access: "Authorization: Bearer <user_token>"
security:
- bearerAuth: []
$ref: './schemas/health_info.yaml'
+138 -26
View File
@@ -3,17 +3,17 @@
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@abstractmachines.fr
email: info@absmach.eu
license:
name: Apache 2.0
url: https://github.com/absmach/supermq/blob/main/LICENSE
version: 0.15.1
url: https://github.com/absmach/magistrala/blob/main/LICENSE
version: 0.18.0
servers:
- url: http://localhost:9005
@@ -24,17 +24,17 @@ tags:
description: CRUD operations for your channels
externalDocs:
description: Find out more about channels
url: https://docs.supermq.abstractmachines.fr/
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.abstractmachines.fr/
url: https://magistrala.absmach.eu/docs/
- name: Health
description: Health check operations
externalDocs:
description: Find out more about health checks
url: https://docs.supermq.abstractmachines.fr/
url: https://magistrala.absmach.eu/docs/
paths:
/{domainID}/channels:
@@ -87,8 +87,23 @@ paths:
- $ref: "auth.yaml#/components/parameters/DomainID"
- $ref: "#/components/parameters/Limit"
- $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"
- $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/Client"
- $ref: "#/components/parameters/Group"
- $ref: "#/components/parameters/User"
- $ref: "#/components/parameters/CreatedFrom"
- $ref: "#/components/parameters/CreatedTo"
responses:
"200":
$ref: "#/components/responses/ChannelPageRes"
@@ -644,9 +659,7 @@ components:
example: 10
description: Maximum number of items to return in one page.
required:
- channels
- total
- offset
ChannelUpdate:
type: object
@@ -693,7 +706,10 @@ components:
type: array
description: Connection types.
items:
example: publish
type: string
enum:
- publish
- subscribe
ChannelConnectionReqSchema:
type: object
@@ -707,7 +723,10 @@ components:
type: array
description: Connection types.
items:
example: publish
type: string
enum:
- publish
- subscribe
Error:
type: object
@@ -764,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
@@ -819,7 +834,6 @@ components:
in: query
schema:
type: string
minimum: 0
required: false
Limit:
@@ -832,7 +846,7 @@ components:
maximum: 100
minimum: 1
required: false
example: "100"
example: 100
Offset:
name: offset
@@ -843,17 +857,115 @@ components:
default: 0
minimum: 0
required: false
example: "0"
example: 0
Connected:
name: connected
description: Connection state of the subset to retrieve.
Order:
name: order
description: Field by which to order the results
in: query
schema:
type: string
required: false
example: created_at
Direction:
name: dir
description: Direction of ordering the results.
in: query
schema:
type: string
enum:
- asc
- desc
required: false
example: desc
ID:
name: id
description: List channels with the given ID.
in: query
schema:
type: string
format: uuid
required: false
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
AccessType:
name: access_type
description: Type of access the user has on the channel.
in: query
schema:
type: string
enum:
- direct
- domain
- indirect
- indirect_group
required: false
example: direct
OnlyTotal:
name: only_total
description: If true, the response will contain only the total number of channels that match the query parameters.
in: query
schema:
type: boolean
default: true
default: false
required: false
Client:
name: client
description: If provided lists channels that a client with the provided ID is connected to.
in: query
schema:
type: string
format: uuid
minLength: 36
required: false
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
Group:
name: group
description: If provided lists channels belonging to a group with the provided ID.
in: query
schema:
type: string
format: uuid
minLength: 36
required: false
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
User:
name: user
description: If provided lists channels associated with a user with the provided ID. Only available for admin users.
in: query
schema:
type: string
format: uuid
minLength: 36
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
+238 -31
View File
@@ -3,17 +3,17 @@
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@abstractmachines.fr
email: info@absmach.eu
license:
name: Apache 2.0
url: https://github.com/absmach/supermq/blob/main/LICENSE
version: 0.15.1
url: https://github.com/absmach/magistrala/blob/main/LICENSE
version: 0.18.0
servers:
- url: http://localhost:9006
@@ -24,17 +24,17 @@ tags:
description: CRUD operations for your clients
externalDocs:
description: Find out more about clients
url: https://docs.supermq.abstractmachines.fr/
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.abstractmachines.fr/
description: Find out more about roles
url: https://magistrala.absmach.eu/docs/
- name: Health
description: Health check operations
externalDocs:
description: Find out more about health checks
url: https://docs.supermq.abstractmachines.fr/
url: https://magistrala.absmach.eu/docs/
paths:
/{domainID}/clients:
@@ -84,10 +84,24 @@ paths:
- $ref: "auth.yaml#/components/parameters/DomainID"
- $ref: "#/components/parameters/Limit"
- $ref: "#/components/parameters/Offset"
- $ref: "#/components/parameters/Order"
- $ref: "#/components/parameters/Direction"
- $ref: "#/components/parameters/Metadata"
- $ref: "#/components/parameters/Status"
- $ref: "#/components/parameters/ClientName"
- $ref: "#/components/parameters/Tags"
- $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/Channel"
- $ref: "#/components/parameters/ConnectionType"
- $ref: "#/components/parameters/Group"
- $ref: "#/components/parameters/User"
- $ref: "#/components/parameters/CreatedFrom"
- $ref: "#/components/parameters/CreatedTo"
security:
- bearerAuth: []
responses:
@@ -169,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
@@ -311,7 +325,7 @@ paths:
- bearerAuth: []
responses:
"200":
$ref: "#/components/responses/ClientRes"
$ref: "#/components/responses/DisabledClientRes"
"400":
description: Failed due to malformed client's ID.
"401":
@@ -436,7 +450,7 @@ paths:
- bearerAuth: []
responses:
"201":
$ref: "./schemas/roles.yaml#/components/responses/CreateRoleRes"
$ref: "./schemas/roles.yaml#/components/responses/CreateRoleRes"
"400":
description: Failed due to malformed client's ID.
"401":
@@ -931,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
@@ -946,7 +964,7 @@ components:
ParentGroupReqObj:
type: object
properties:
parent_group_id:
parent_group_id:
type: string
format: uuid
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
@@ -989,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
@@ -1046,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
@@ -1089,9 +1115,7 @@ components:
example: 10
description: Maximum number of items to return in one page.
required:
- clients
- total
- offset
ClientUpdate:
type: object
@@ -1103,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:
@@ -1120,6 +1149,63 @@ components:
items:
type: string
DisabledClient:
type: object
properties:
id:
type: string
format: uuid
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
description: Client unique identifier.
name:
type: string
example: clientName
description: Client name.
tags:
type: array
minItems: 0
items:
type: string
example: ["tag1", "tag2"]
description: Client tags.
domain_id:
type: string
format: uuid
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
description: ID of the domain to which client belongs.
credentials:
type: object
properties:
identity:
type: string
example: clientIDentity
description: Client Identity for example email address.
secret:
type: string
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
description: Client secret password.
metadata:
type: object
example: { "model": "example" }
description: Arbitrary, object-encoded client's data visible to other clients.
status:
type: string
description: Client Status
format: string
example: disabled
created_at:
type: string
format: date-time
example: "2019-11-26 13:31:52"
description: Time when the channel was created.
updated_at:
type: string
format: date-time
example: "2019-11-26 13:31:52"
description: Time when the channel was created.
xml:
name: client
ClientSecret:
type: object
properties:
@@ -1198,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
@@ -1215,7 +1297,6 @@ components:
in: query
schema:
type: string
minimum: 0
required: false
Limit:
@@ -1228,7 +1309,7 @@ components:
maximum: 100
minimum: 1
required: false
example: "100"
example: 100
Offset:
name: offset
@@ -1239,7 +1320,126 @@ components:
default: 0
minimum: 0
required: false
example: "0"
example: 0
Order:
name: order
description: Field by which to order the results
in: query
schema:
type: string
required: false
example: created_at
Direction:
name: dir
description: Direction of ordering the results.
in: query
schema:
type: string
enum:
- asc
- desc
required: false
example: desc
ID:
name: id
description: List clients with the given ID.
in: query
schema:
type: string
format: uuid
required: false
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
AccessType:
name: access_type
description: Type of access the user has on the client.
in: query
schema:
type: string
enum:
- direct
- domain
- indirect
- indirect_group
required: false
example: direct
OnlyTotal:
name: only_total
description: If true, the response will contain only the total number of clients that match the query parameters.
in: query
schema:
type: boolean
default: false
required: false
Channel:
name: channel
description: If provided lists clients connected to a channel with the provided ID.
in: query
schema:
type: string
format: uuid
minLength: 36
required: false
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
ConnectionType:
name: connection_type
description: If provided with channel parameter lists clients connected to the channel with the provided connection type.
in: query
schema:
type: string
enum:
- Publish
- Subscribe
required: false
example: Publish
Group:
name: group
description: If provided lists clients belonging to a group with the provided ID.
in: query
schema:
type: string
format: uuid
minLength: 36
required: false
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
User:
name: user
description: If provided lists clients associated with a user with the provided ID. Only available for admin users.
in: query
schema:
type: string
format: uuid
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:
@@ -1261,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:
@@ -1337,7 +1537,14 @@ components:
application/json:
schema:
$ref: "#/components/schemas/Client"
DisabledClientRes:
description: Data retrieved.
content:
application/json:
schema:
$ref: "#/components/schemas/DisabledClient"
ClientPageRes:
description: Data retrieved.
content:
+100 -54
View File
@@ -9,11 +9,11 @@ info:
Some useful links:
- [The Magistrala repository](https://github.com/absmach/magistrala)
contact:
email: info@abstractmachines.fr
email: info@absmach.eu
license:
name: Apache 2.0
url: https://github.com/absmach/magistrala/blob/main/LICENSE
version: 0.15.1
version: 0.18.0
servers:
- url: http://localhost:9003
@@ -24,22 +24,22 @@ tags:
description: CRUD operations for your domains
externalDocs:
description: Find out more about domains
url: https://docs.magistrala.abstractmachines.fr/
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.abstractmachines.fr/
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.abstractmachines.fr/
url: https://magistrala.absmach.eu/docs/
- name: Health
description: Service health check endpoint.
externalDocs:
description: Find out more about health check
url: https://docs.magistrala.abstractmachines.fr/
url: https://magistrala.absmach.eu/docs/
paths:
/domains:
@@ -73,10 +73,19 @@ paths:
parameters:
- $ref: "#/components/parameters/Limit"
- $ref: "#/components/parameters/Offset"
- $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: "#/components/parameters/Permission"
- $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/CreatedFrom"
- $ref: "#/components/parameters/CreatedTo"
tags:
- Domains
security:
@@ -757,45 +766,18 @@ paths:
"500":
$ref: "#/components/responses/ServiceError"
/domains/{domainID}/invitations/{userID}:
get:
operationId: getInvitation
summary: Retrieves a specific invitation
description: |
Retrieves a specific invitation that is identifier by the user ID and domain ID.
tags:
- Invitations
parameters:
- $ref: "#/components/parameters/DomainID"
- $ref: "#/components/parameters/UserID"
security:
- bearerAuth: []
responses:
"200":
$ref: "#/components/responses/InvitationRes"
"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"
delete:
operationId: deleteInvitation
summary: Deletes a specific invitation
description: |
Deletes a specific invitation that is identifier by the user ID and domain ID.
Deletes a specific invitation that is identified by the user ID and domain ID.
The user ID is provided in the request body.
tags:
- Invitations
parameters:
- $ref: "#/components/parameters/DomainID"
- $ref: "#/components/parameters/UserID"
requestBody:
$ref: "#/components/requestBodies/DeleteInvitationReq"
security:
- bearerAuth: []
responses:
@@ -1017,9 +999,7 @@ components:
example: 10
description: Maximum number of items to return in one page.
required:
- domains
- total
- offset
DomainUpdate:
type: object
properties:
@@ -1167,14 +1147,6 @@ components:
type: string
required: false
example: "domainName"
Permission:
name: permission
description: permission.
in: query
schema:
type: string
required: false
example: "edit"
ApiKeyId:
name: keyID
description: API Key ID.
@@ -1210,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.
@@ -1272,15 +1252,66 @@ components:
- all
required: false
example: accepted
RoleID:
name: roleID
description: Unique role identifier.
Order:
name: order
description: Field by which to order the results
in: query
schema:
type: string
format: uuid
required: true
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
required: false
example: created_at
Direction:
name: dir
description: Direction of ordering the results.
in: query
schema:
type: string
enum:
- asc
- desc
required: false
example: desc
AccessType:
name: access_type
description: Type of access the user has on the domain.
in: query
schema:
type: string
enum:
- direct
- domain
- indirect
- indirect_group
required: false
example: direct
OnlyTotal:
name: only_total
description: If true, the response will contain only the total number of domains that match the query parameters.
in: query
schema:
type: boolean
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:
@@ -1319,6 +1350,21 @@ components:
description: Domain unique identifier.
required:
- domain_id
DeleteInvitationReq:
description: JSON-formatted document describing request for deleting invitation
required: true
content:
application/json:
schema:
type: object
properties:
user_id:
type: string
format: uuid
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
description: User unique identifier.
required:
- user_id
responses:
ServiceError:
+136 -29
View File
@@ -3,17 +3,17 @@
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@abstractmachines.fr
email: info@absmach.eu
license:
name: Apache 2.0
url: https://github.com/absmach/supermq/blob/main/LICENSE
version: 0.15.1
url: https://github.com/absmach/magistrala/blob/main/LICENSE
version: 0.18.0
servers:
- url: http://localhost:9004
@@ -24,17 +24,17 @@ tags:
description: CRUD operations for your groups
externalDocs:
description: Find out more about users groups
url: https://docs.supermq.abstractmachines.fr/
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.abstractmachines.fr/
url: https://magistrala.absmach.eu/docs/
- name: Health
description: Health check operations
externalDocs:
description: Find out more about health checks
url: https://docs.supermq.abstractmachines.fr/
url: https://magistrala.absmach.eu/docs/
paths:
/{domainID}/groups:
@@ -88,11 +88,23 @@ paths:
- $ref: "auth.yaml#/components/parameters/DomainID"
- $ref: "#/components/parameters/Limit"
- $ref: "#/components/parameters/Offset"
- $ref: "#/components/parameters/Order"
- $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: "./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/CreatedFrom"
- $ref: "#/components/parameters/CreatedTo"
responses:
"200":
$ref: "#/components/responses/GroupPageRes"
@@ -234,7 +246,6 @@ paths:
"500":
$ref: "#/components/responses/ServiceError"
/{domainID}/groups/{groupID}/enable:
post:
operationId: enableGroup
@@ -320,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"
@@ -354,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":
@@ -384,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":
@@ -1132,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
@@ -1196,9 +1219,7 @@ components:
example: 10
description: Maximum number of items to return in one page.
required:
- groups
- total
- offset
GroupsHierarchyPage:
type: object
@@ -1358,26 +1379,25 @@ components:
Status:
name: status
description: User account status.
description: Lists groups with the given status.
in: query
schema:
type: string
default: enabled
enum:
- enabled
- disabled
- all
required: false
example: enabled
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
@@ -1389,7 +1409,7 @@ components:
example: "groupName"
GroupDescription:
name: name
name: description
description: Group's description.
in: query
schema:
@@ -1504,7 +1524,6 @@ components:
in: query
schema:
type: string
minimum: 0
required: false
Limit:
@@ -1517,7 +1536,7 @@ components:
maximum: 100
minimum: 1
required: false
example: "100"
example: 100
Offset:
name: offset
@@ -1528,7 +1547,92 @@ components:
default: 0
minimum: 0
required: false
example: "0"
example: 0
Order:
name: order
description: Field by which to order the results
in: query
schema:
type: string
required: false
example: created_at
DirectionOrder:
name: order
description: Direction of ordering the results.
in: query
schema:
type: string
enum:
- asc
- desc
required: false
example: desc
ID:
name: id
description: List groups with the given ID.
in: query
schema:
type: string
format: uuid
required: false
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
AccessType:
name: access_type
description: Type of access the user has on the group.
in: query
schema:
type: string
enum:
- direct
- domain
- indirect
- indirect_group
required: false
example: direct
OnlyTotal:
name: only_total
description: If true, the response will contain only the total number of groups that match the query parameters.
in: query
schema:
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.
in: query
schema:
type: string
format: uuid
minLength: 36
required: false
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
requestBodies:
GroupCreateReq:
@@ -1589,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:
@@ -1636,6 +1740,7 @@ components:
application/json:
schema:
$ref: "#/components/schemas/GroupsPage"
links: {}
GroupsHierarchyPageRes:
description: Group hierarchy retrieved.
@@ -1643,6 +1748,7 @@ components:
application/json:
schema:
$ref: "#/components/schemas/GroupsHierarchyPage"
links: {}
MembersPageRes:
description: Group members retrieved.
@@ -1650,6 +1756,7 @@ components:
application/json:
schema:
$ref: "#/components/schemas/MembersPage"
links: {}
HealthRes:
description: Service Health Check.
+8 -6
View File
@@ -3,17 +3,17 @@
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@abstractmachines.fr
email: info@absmach.eu
license:
name: Apache 2.0
url: https://github.com/absmach/supermq/blob/main/LICENSE
version: 0.15.1
url: https://github.com/absmach/magistrala/blob/main/LICENSE
version: 0.18.0
servers:
- url: http://localhost:8008
@@ -24,7 +24,7 @@ tags:
description: Everything about your Messages
externalDocs:
description: Find out more about messages
url: https://docs.supermq.abstractmachines.fr/
url: https://magistrala.absmach.eu/docs/
paths:
/m/{domainPrefix}/c/{channelPrefix}:
@@ -47,6 +47,8 @@ paths:
description: Message discarded due to its malformed content.
"401":
description: Missing or invalid access token provided.
"403":
description: Access denied to the requested resource.
"404":
description: Message discarded due to invalid channel id.
"415":
-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.15.1
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>"
+1 -1
View File
@@ -11,7 +11,7 @@ properties:
version:
type: string
description: Service version.
example: v0.14.0
example: v0.18.0
commit:
type: string
description: Service commit hash.
+30 -5
View File
@@ -6,12 +6,12 @@ components:
NewRole:
type: object
properties:
role_id:
id:
type: string
format: uuid
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
description: Role unique identifier.
role_name:
name:
type: string
description: Role's name.
example: "roleName"
@@ -44,12 +44,12 @@ components:
Role:
type: object
properties:
role_id:
id:
type: string
format: uuid
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
description: Role unique identifier.
role_name:
name:
type: string
description: Role's name.
example: "roleName"
@@ -82,7 +82,7 @@ components:
CreateRoleObj:
type: object
properties:
role_name:
name:
type: string
description: Role's name.
example: "roleName"
@@ -270,6 +270,31 @@ components:
type: string
required: true
example: "roleID"
RoleIDQuery:
name: role_id
description: Filter by role ID.
in: query
schema:
type: string
format: uuid
required: false
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
RoleNameQuery:
name: role_name
description: Filter by role name.
in: query
schema:
type: string
required: false
example: admin
ActionsQuery:
name: actions
description: Filter by actions. Multiple actions can be specified separated by comma.
in: query
schema:
type: string
required: false
example: "action1,action2"
requestBodies:
CreateRoleReq:
-431
View File
@@ -1,431 +0,0 @@
# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
openapi: 3.0.1
info:
title: SuperMQ twins service
description: |
HTTP API for managing digital twins and their states.
Some useful links:
- [The SuperMQ repository](https://github.com/absmach/supermq)
contact:
email: info@abstractmachines.fr
license:
name: Apache 2.0
url: https://github.com/absmach/supermq/blob/main/LICENSE
version: 0.15.1
servers:
- url: http://localhost:9018
- url: https://localhost:9018
tags:
- name: twins
description: Everything about your Twins
externalDocs:
description: Find out more about twins
url: https://docs.supermq.abstractmachines.fr/
paths:
/twins:
post:
operationId: createTwin
summary: Adds new twin
description: |
Adds new twin to the list of twins owned by user identified using
the provided access token.
tags:
- twins
requestBody:
$ref: "#/components/requestBodies/TwinReq"
responses:
"201":
$ref: "#/components/responses/TwinCreateRes"
"400":
description: Failed due to malformed JSON.
"401":
description: Missing or invalid access token provided.
"415":
description: Missing or invalid content type.
"422":
description: Database can't process request.
"500":
$ref: "#/components/responses/ServiceError"
get:
operationId: getTwins
summary: Retrieves twins
description: |
Retrieves a list of twins. Due to performance concerns, data
is retrieved in subsets.
tags:
- twins
parameters:
- $ref: "#/components/parameters/Limit"
- $ref: "#/components/parameters/Offset"
- $ref: "#/components/parameters/Name"
- $ref: "#/components/parameters/Metadata"
responses:
"200":
$ref: "#/components/responses/TwinsPageRes"
"400":
description: Failed due to malformed query parameters.
"401":
description: Missing or invalid access token provided.
"422":
description: Database can't process request.
"500":
$ref: "#/components/responses/ServiceError"
/twins/{twinID}:
get:
operationId: getTwin
summary: Retrieves twin info
tags:
- twins
parameters:
- $ref: "#/components/parameters/TwinID"
responses:
"200":
$ref: "#/components/responses/TwinRes"
"400":
description: Failed due to malformed twin's ID.
"401":
description: Missing or invalid access token provided.
"404":
description: Twin does not exist.
"422":
description: Database can't process request.
"500":
$ref: "#/components/responses/ServiceError"
put:
operationId: updateTwin
summary: Updates twin info
description: |
Update is performed by replacing the current resource data with values
provided in a request payload. Note that the twin's ID cannot be changed.
tags:
- twins
parameters:
- $ref: "#/components/parameters/TwinID"
requestBody:
$ref: "#/components/requestBodies/TwinReq"
responses:
"200":
description: Twin updated.
"400":
description: Failed due to malformed twin's ID or malformed JSON.
"401":
description: Missing or invalid access token provided.
"404":
description: Twin does not exist.
"415":
description: Missing or invalid content type.
"422":
description: Database can't process request.
"500":
$ref: "#/components/responses/ServiceError"
delete:
operationId: removeTwin
summary: Removes a twin
description: Removes a twin.
tags:
- twins
parameters:
- $ref: "#/components/parameters/TwinID"
responses:
"204":
description: Twin removed.
"400":
description: Failed due to malformed twin's ID.
"401":
description: Missing or invalid access token provided
"404":
description: Twin does not exist.
"415":
description: Missing or invalid content type.
"422":
description: Database can't process request.
"500":
$ref: "#/components/responses/ServiceError"
/states/{twinID}:
get:
operationId: getStates
summary: Retrieves states of twin with id twinID
description: |
Retrieves a list of states. Due to performance concerns, data
is retrieved in subsets.
tags:
- states
parameters:
- $ref: "#/components/parameters/TwinID"
- $ref: "#/components/parameters/Limit"
- $ref: "#/components/parameters/Offset"
responses:
"200":
$ref: "#/components/responses/StatesPageRes"
"400":
description: Failed due to malformed query parameters.
"401":
description: Missing or invalid access token provided.
"404":
description: Twin 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:
parameters:
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
Name:
name: name
description: Twin name
in: query
schema:
type: string
required: false
Metadata:
name: metadata
description: |
Metadata filter. Filtering is performed matching the parameter with
metadata on top level. Parameter is json.
in: query
schema:
type: string
minimum: 0
required: false
TwinID:
name: twinID
description: Unique twin identifier.
in: path
schema:
type: string
format: uuid
minimum: 1
required: true
schemas:
Attribute:
type: object
properties:
name:
type: string
description: Name of the attribute.
channel:
type: string
description: SuperMQ channel used by attribute.
subtopic:
type: string
description: Subtopic used by attribute.
persist_state:
type: boolean
description: Trigger state creation based on the attribute.
Definition:
type: object
properties:
delta:
type: number
description: Minimal time delay before new state creation.
attributes:
type: array
minItems: 0
items:
$ref: "#/components/schemas/Attribute"
TwinReqObj:
type: object
properties:
name:
type: string
description: Free-form twin name.
metadata:
type: object
description: Arbitrary, object-encoded twin's data.
definition:
$ref: "#/components/schemas/Definition"
TwinResObj:
type: object
properties:
owner:
type: string
description: Email address of SuperMQ user that owns twin.
id:
type: string
format: uuid
description: Unique twin identifier generated by the service.
name:
type: string
description: Free-form twin name.
revision:
type: number
description: Oridnal revision number of twin.
created:
type: string
format: date
description: Twin creation date and time.
updated:
type: string
format: date
description: Twin update date and time.
definitions:
type: array
minItems: 0
items:
$ref: "#/components/schemas/Definition"
metadata:
type: object
description: Arbitrary, object-encoded twin's data.
TwinsPage:
type: object
properties:
twins:
type: array
minItems: 0
items:
$ref: "#/components/schemas/TwinResObj"
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.
required:
- twins
State:
type: object
properties:
twin_id:
type: string
format: uuid
description: ID of twin state belongs to.
id:
type: number
description: State position in a time row of states.
created:
type: string
format: date
description: State creation date.
payload:
type: object
description: Object-encoded states's payload.
StatesPage:
type: object
properties:
states:
type: array
minItems: 0
items:
$ref: "#/components/schemas/State"
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.
required:
- states
requestBodies:
TwinReq:
description: JSON-formatted document describing the twin to create or update.
content:
application/json:
schema:
$ref: "#/components/schemas/TwinReqObj"
required: true
responses:
TwinCreateRes:
description: Created twin's relative URL (i.e. /twins/{twinID}).
headers:
Location:
content:
text/plain:
schema:
type: string
TwinRes:
description: Data retrieved.
content:
application/json:
schema:
$ref: "#/components/schemas/TwinResObj"
links:
update:
operationId: updateTwin
parameters:
twinID: $response.body#/id
delete:
operationId: removeTwin
parameters:
twinID: $response.body#/id
states:
operationId: getStates
parameters:
twinID: $response.body#/id
TwinsPageRes:
description: Data retrieved.
content:
application/json:
schema:
$ref: "#/components/schemas/TwinsPage"
StatesPageRes:
description: Data retrieved.
content:
application/json:
schema:
$ref: "#/components/schemas/StatesPage"
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: []
+267 -43
View File
@@ -3,17 +3,17 @@
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@abstractmachines.fr
email: info@absmach.eu
license:
name: Apache 2.0
url: https://github.com/absmach/supermq/blob/main/LICENSE
version: 0.15.1
url: https://github.com/absmach/magistrala/blob/main/LICENSE
version: 0.18.0
servers:
- url: http://localhost:9002
@@ -24,12 +24,12 @@ tags:
description: Everything about your Users
externalDocs:
description: Find out more about users
url: https://docs.supermq.abstractmachines.fr/
url: https://magistrala.absmach.eu/docs/
- name: Health
description: Health check operations
externalDocs:
description: Find out more about health checks
url: https://docs.supermq.abstractmachines.fr/
url: https://magistrala.absmach.eu/docs/
paths:
/users:
@@ -75,13 +75,18 @@ paths:
parameters:
- $ref: "#/components/parameters/Limit"
- $ref: "#/components/parameters/Offset"
- $ref: "#/components/parameters/Order"
- $ref: "#/components/parameters/Direction"
- $ref: "#/components/parameters/Metadata"
- $ref: "#/components/parameters/Status"
- $ref: "#/components/parameters/FirstName"
- $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:
@@ -113,7 +118,7 @@ paths:
- bearerAuth: []
responses:
"200":
$ref: "#/components/responses/UserRes"
$ref: "#/components/responses/UserProfileRes"
"400":
description: Failed due to malformed query parameters.
"401":
@@ -151,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:
@@ -458,7 +463,7 @@ paths:
- bearerAuth: []
responses:
"200":
$ref: "#/components/responses/UserRes"
$ref: "#/components/responses/UserProfileRes"
"400":
description: Failed due to malformed JSON.
"401":
@@ -566,7 +571,7 @@ paths:
requestBody:
$ref: "#/components/requestBodies/IssueTokenReq"
responses:
"200":
"201":
$ref: "#/components/responses/TokenRes"
"400":
description: Failed due to malformed JSON.
@@ -607,6 +612,105 @@ 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
tags:
- Users
summary: Sends a verification email
description: |
Sends a verification email to the user.
security:
- bearerAuth: []
responses:
"200":
description: Sent verification email if registered.
"400":
description: Failed due to malformed JSON.
"401":
description: Missing or invalid access token provided.
"415":
description: Missing or invalid content type.
"422":
description: Database can't process request.
"500":
$ref: "#/components/responses/ServiceError"
/verify-email:
get:
operationId: verifyEmail
tags:
- Users
summary: Verify user's email
description: |
Verify user's email using the token from the verification link.
parameters:
- $ref: "#/components/parameters/VerificationToken"
responses:
"200":
description: Email verified successfully.
"400":
description: Failed due to malformed query parameters.
"401":
description: Missing or invalid access token provided.
"404":
description: A non-existent entity request.
"422":
description: Database can't process request.
"500":
$ref: "#/components/responses/ServiceError"
/health:
get:
operationId: health
@@ -655,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
@@ -663,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"
@@ -707,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
@@ -719,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"
@@ -760,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
@@ -779,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
@@ -818,6 +930,7 @@ components:
description: Total number of items.
offset:
type: integer
example: 1
description: Number of items to skip during retrieval.
limit:
type: integer
@@ -826,7 +939,7 @@ components:
required:
- users
- total
- offset
- limit
UserUpdate:
type: object
@@ -842,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
@@ -856,7 +969,6 @@ components:
example: ["yello", "orange"]
description: User tags.
minItems: 0
uniqueItems: true
items:
type: string
@@ -875,7 +987,7 @@ components:
properties:
email:
type: string
example: user@supermq.com
example: user@magistrala.com
description: User email address.
required:
- email
@@ -886,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
@@ -977,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:
@@ -1086,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
@@ -1226,7 +1362,7 @@ components:
maximum: 100
minimum: 1
required: false
example: "100"
example: 100
Offset:
name: offset
@@ -1237,7 +1373,65 @@ components:
default: 0
minimum: 0
required: false
example: "0"
example: 0
Order:
name: order
description: Field by which to order the results
in: query
schema:
type: string
required: false
example: created_at
Direction:
name: dir
description: Direction of ordering the results.
in: query
schema:
type: string
enum:
- asc
- desc
required: false
example: desc
OnlyTotal:
name: only_total
description: If true, the response will contain only the total number of users that match the query parameters.
in: query
schema:
type: boolean
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.
in: query
schema:
type: string
required: true
requestBodies:
UserCreateReq:
@@ -1249,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:
@@ -1354,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
@@ -1377,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.
@@ -1443,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:
@@ -1470,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:
+95 -95
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:
@@ -40,7 +40,7 @@ The following actions are supported:
## Domains
Domains are used to group users and clients. Each domain has a unique route that is associated with the domain. Domains are used to group users and their entities.
Domains are used to group users and clients. Each domain has a unique `route` that is associated with the domain. Domains are used to group users and their entities.
Domain consists of the following fields:
@@ -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
@@ -183,7 +183,7 @@ PATs in SuperMQ are designed with the following features:
A PAT consists of three parts separated by underscores:
```
```bash
pat_<encoded-user-and-pat-id>_<random-string>
```
@@ -195,7 +195,7 @@ Where:
### PAT Operations
SuperMQ supports the following operations for PATs:
Magistrala supports the following operations for PATs:
| Operation | Description |
| ----------- | ------------------------------------ |
@@ -318,7 +318,7 @@ curl --location --request PATCH 'http://localhost:9001/pats/a2500226-95dc-4285-8
When making API requests, include the PAT in the Authorization header:
```
```bash
Authorization: Bearer pat_<encoded-user-and-pat-id>_<random-string>
```
@@ -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.abstractmachines.fr/?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.abstractmachines.fr
[doc]: https://magistrala.absmach.eu/docs/
+66 -95
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"
@@ -18,11 +18,9 @@ import (
const authSvcName = "auth.v1.AuthService"
type authGrpcClient struct {
authenticate endpoint.Endpoint
authenticatePAT endpoint.Endpoint
authorize endpoint.Endpoint
authorizePAT endpoint.Endpoint
timeout time.Duration
authenticate endpoint.Endpoint
authorize endpoint.Endpoint
timeout time.Duration
}
var _ grpcAuthV1.AuthServiceClient = (*authGrpcClient)(nil)
@@ -38,14 +36,6 @@ func NewAuthClient(conn *grpc.ClientConn, timeout time.Duration) grpcAuthV1.Auth
decodeIdentifyResponse,
grpcAuthV1.AuthNRes{},
).Endpoint(),
authenticatePAT: kitgrpc.NewClient(
conn,
authSvcName,
"AuthenticatePAT",
encodeIdentifyRequest,
decodeIdentifyPATResponse,
grpcAuthV1.AuthNRes{},
).Endpoint(),
authorize: kitgrpc.NewClient(
conn,
authSvcName,
@@ -54,14 +44,6 @@ func NewAuthClient(conn *grpc.ClientConn, timeout time.Duration) grpcAuthV1.Auth
decodeAuthorizeResponse,
grpcAuthV1.AuthZRes{},
).Endpoint(),
authorizePAT: kitgrpc.NewClient(
conn,
authSvcName,
"AuthorizePAT",
encodeAuthorizePATRequest,
decodeAuthorizeResponse,
grpcAuthV1.AuthZRes{},
).Endpoint(),
timeout: timeout,
}
}
@@ -75,50 +57,55 @@ 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)}, 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 interface{}) (interface{}, error) {
func encodeIdentifyRequest(_ context.Context, grpcReq any) (any, error) {
req := grpcReq.(authenticateReq)
return &grpcAuthV1.AuthNReq{Token: req.token}, nil
}
func decodeIdentifyResponse(_ context.Context, grpcRes interface{}) (interface{}, 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)}, nil
}
func (client authGrpcClient) AuthenticatePAT(ctx context.Context, token *grpcAuthV1.AuthNReq, _ ...grpc.CallOption) (*grpcAuthV1.AuthNRes, error) {
ctx, cancel := context.WithTimeout(ctx, client.timeout)
defer cancel()
res, err := client.authenticatePAT(ctx, authenticateReq{token: token.GetToken()})
if err != nil {
return &grpcAuthV1.AuthNRes{}, grpcapi.DecodeError(err)
}
ir := res.(authenticateRes)
return &grpcAuthV1.AuthNRes{Id: ir.id, UserId: ir.userID}, nil
}
func decodeIdentifyPATResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
res := grpcRes.(*grpcAuthV1.AuthNRes)
return authenticateRes{id: res.GetId(), userID: res.GetUserId()}, 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) {
ctx, cancel := context.WithTimeout(ctx, client.timeout)
defer cancel()
res, err := client.authorize(ctx, authReq{
Domain: req.GetDomain(),
SubjectType: req.GetSubjectType(),
Subject: req.GetSubject(),
SubjectKind: req.GetSubjectKind(),
Relation: req.GetRelation(),
Permission: req.GetPermission(),
ObjectType: req.GetObjectType(),
Object: req.GetObject(),
})
var authReqData authReq
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(),
}
}
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()
}
}
res, err := client.authorize(ctx, authReqData)
if err != nil {
return &grpcAuthV1.AuthZRes{}, grpcapi.DecodeError(err)
}
@@ -127,53 +114,37 @@ func (client authGrpcClient) Authorize(ctx context.Context, req *grpcAuthV1.Auth
return &grpcAuthV1.AuthZRes{Authorized: ar.authorized, Id: ar.id}, nil
}
func decodeAuthorizeResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
func decodeAuthorizeResponse(_ context.Context, grpcRes any) (any, error) {
res := grpcRes.(*grpcAuthV1.AuthZRes)
return authorizeRes{authorized: res.Authorized, id: res.Id}, nil
}
func encodeAuthorizeRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
func encodeAuthorizeRequest(_ context.Context, grpcReq any) (any, error) {
req := grpcReq.(authReq)
return &grpcAuthV1.AuthZReq{
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
}
func (client authGrpcClient) AuthorizePAT(ctx context.Context, req *grpcAuthV1.AuthZPatReq, _ ...grpc.CallOption) (r *grpcAuthV1.AuthZRes, err error) {
ctx, cancel := context.WithTimeout(ctx, client.timeout)
defer cancel()
res, err := client.authorizePAT(ctx, authPATReq{
userID: req.GetUserId(),
patID: req.GetPatId(),
entityType: auth.EntityType(req.GetEntityType()),
optionalDomainID: req.GetOptionalDomainId(),
operation: auth.Operation(req.GetOperation()),
entityID: req.GetEntityId(),
})
if err != nil {
return &grpcAuthV1.AuthZRes{}, grpcapi.DecodeError(err)
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,
},
}
ar := res.(authorizeRes)
return &grpcAuthV1.AuthZRes{Authorized: ar.authorized, Id: ar.id}, 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,
}
}
func encodeAuthorizePATRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
req := grpcReq.(authPATReq)
return &grpcAuthV1.AuthZPatReq{
UserId: req.userID,
PatId: req.patID,
EntityType: uint32(req.entityType),
OptionalDomainId: req.optionalDomainID,
Operation: uint32(req.operation),
EntityId: req.entityID,
}, nil
return authZReq, nil
}
+23 -37
View File
@@ -6,13 +6,13 @@ 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"
)
func authenticateEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
return func(ctx context.Context, request any) (any, error) {
req := request.(authenticateReq)
if err := req.validate(); err != nil {
return authenticateRes{}, err
@@ -23,33 +23,34 @@ func authenticateEndpoint(svc auth.Service) endpoint.Endpoint {
return authenticateRes{}, err
}
return authenticateRes{userID: key.Subject, userRole: key.Role}, nil
}
}
func authenticatePATEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(authenticateReq)
if err := req.validate(); err != nil {
return authenticateRes{}, err
}
pat, err := svc.IdentifyPAT(ctx, req.token)
if err != nil {
return authenticateRes{}, err
}
return authenticateRes{id: pat.ID, userID: pat.User}, nil
return authenticateRes{id: key.ID, userID: key.Subject, userRole: key.Role, verified: key.Verified, tokenType: key.Type}, nil
}
}
func authorizeEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
return func(ctx context.Context, request any) (any, error) {
req := request.(authReq)
if err := req.validate(); err != nil {
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{
Domain: req.Domain,
SubjectType: req.SubjectType,
@@ -59,22 +60,7 @@ func authorizeEndpoint(svc auth.Service) endpoint.Endpoint {
Permission: req.Permission,
ObjectType: req.ObjectType,
Object: req.Object,
})
if err != nil {
return authorizeRes{authorized: false}, err
}
return authorizeRes{authorized: true}, nil
}
}
func authorizePATEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(authPATReq)
if err := req.validate(); err != nil {
return authorizeRes{}, err
}
err := svc.AuthorizePAT(ctx, req.userID, req.patID, req.entityType, req.optionalDomainID, req.operation, req.entityID)
}, pat)
if err != nil {
return authorizeRes{authorized: false}, err
}
-374
View File
@@ -1,374 +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
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"
validPATToken = "valid"
inValidPATToken = "invalid"
validPolicy = "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
idt *grpcAuthV1.AuthNRes
svcErr error
err error
}{
{
desc: "authenticate user with valid user token",
token: validToken,
idt: &grpcAuthV1.AuthNRes{UserId: id, UserRole: uint32(auth.UserRole)},
err: nil,
},
{
desc: "authenticate user with invalid user token",
token: "invalid",
idt: &grpcAuthV1.AuthNRes{},
svcErr: svcerr.ErrAuthentication,
err: svcerr.ErrAuthentication,
},
{
desc: "authenticate user with empty token",
token: "",
idt: &grpcAuthV1.AuthNRes{},
err: apiutil.ErrBearerToken,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
svcCall := svc.On("Identify", mock.Anything, mock.Anything).Return(auth.Key{Subject: id, Role: auth.UserRole}, 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{
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{
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{
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{
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{
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{
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{
Subject: id,
SubjectType: usersType,
Object: authoritiesObj,
ObjectType: usersType,
Relation: memberRelation,
Permission: "",
},
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
err: apiutil.ErrMalformedPolicyPer,
},
}
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()
})
}
}
func TestIdentifyPAT(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
idt *grpcAuthV1.AuthNRes
svcErr error
err error
}{
{
desc: "authenticate user with valid user token",
token: validToken,
idt: &grpcAuthV1.AuthNRes{Id: id, UserId: clientID},
err: nil,
},
{
desc: "authenticate user with invalid user token",
token: "invalid",
idt: &grpcAuthV1.AuthNRes{},
svcErr: svcerr.ErrAuthentication,
err: svcerr.ErrAuthentication,
},
{
desc: "authenticate user with empty token",
token: "",
idt: &grpcAuthV1.AuthNRes{},
err: apiutil.ErrBearerToken,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
svcCall := svc.On("IdentifyPAT", mock.Anything, tc.token).Return(auth.PAT{ID: id, User: clientID, IssuedAt: time.Now()}, tc.svcErr)
idt, err := grpcClient.AuthenticatePAT(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 TestAuthorizePAT(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.AuthZPatReq
authResponse *grpcAuthV1.AuthZRes
err error
}{
{
desc: "authorize user with authorized token",
token: validPATToken,
authRequest: &grpcAuthV1.AuthZPatReq{
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 token",
token: inValidPATToken,
authRequest: &grpcAuthV1.AuthZPatReq{
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 user with missing user id",
token: validPATToken,
authRequest: &grpcAuthV1.AuthZPatReq{
PatId: id,
EntityType: uint32(auth.ClientsType),
OptionalDomainId: domainID,
Operation: uint32(auth.CreateOp),
EntityId: clientID,
},
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
err: apiutil.ErrMissingUserID,
},
{
desc: "authorize user with missing pat id",
token: validPATToken,
authRequest: &grpcAuthV1.AuthZPatReq{
UserId: id,
EntityType: uint32(auth.ClientsType),
OptionalDomainId: domainID,
Operation: uint32(auth.CreateOp),
EntityId: clientID,
},
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
err: apiutil.ErrMissingPATID,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
svccall := svc.On("AuthorizePAT",
mock.Anything,
tc.authRequest.UserId,
tc.authRequest.PatId,
mock.Anything,
tc.authRequest.OptionalDomainId,
mock.Anything,
mock.Anything,
mock.Anything).Return(tc.err)
ar, err := grpcClient.AuthorizePAT(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()
})
}
}
+20 -21
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 {
@@ -33,9 +32,28 @@ type authReq struct {
Permission string
ObjectType string
Object string
// PAT authorization fields
UserID string
PatID string
EntityType string
Operation string
EntityID string
}
func (req authReq) validate() error {
if req.PatID != "" {
if req.UserID == "" {
return apiutil.ErrMissingUserID
}
if req.EntityID == "" {
return apiutil.ErrMissingID
}
if req.EntityType == "" {
return apiutil.ErrMissingPolicyObj
}
}
if req.Subject == "" || req.SubjectType == "" {
return apiutil.ErrMissingPolicySub
}
@@ -50,22 +68,3 @@ func (req authReq) validate() error {
return nil
}
type authPATReq struct {
userID string
patID string
entityType auth.EntityType
optionalDomainID string
operation auth.Operation
entityID string
}
func (req authPATReq) validate() error {
if req.userID == "" {
return apiutil.ErrMissingUserID
}
if req.patID == "" {
return apiutil.ErrMissingPATID
}
return nil
}
+6 -4
View File
@@ -3,12 +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
id string
userID string
userRole auth.Role
verified bool
tokenType auth.KeyType
}
type authorizeRes struct {
+44 -67
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"
)
@@ -16,10 +16,8 @@ var _ grpcAuthV1.AuthServiceServer = (*authGrpcServer)(nil)
type authGrpcServer struct {
grpcAuthV1.UnimplementedAuthServiceServer
authorize kitgrpc.Handler
authenticate kitgrpc.Handler
authenticatePAT kitgrpc.Handler
authorizePAT kitgrpc.Handler
authorize kitgrpc.Handler
authenticate kitgrpc.Handler
}
// NewAuthServer returns new AuthnServiceServer instance.
@@ -36,18 +34,6 @@ func NewAuthServer(svc auth.Service) grpcAuthV1.AuthServiceServer {
decodeAuthenticateRequest,
encodeAuthenticateResponse,
),
authenticatePAT: kitgrpc.NewServer(
(authenticatePATEndpoint(svc)),
decodeAuthenticateRequest,
encodeAuthenticatePATResponse,
),
authorizePAT: kitgrpc.NewServer(
(authorizePATEndpoint(svc)),
decodeAuthorizePATRequest,
encodeAuthorizeResponse,
),
}
}
@@ -59,14 +45,6 @@ func (s *authGrpcServer) Authenticate(ctx context.Context, req *grpcAuthV1.AuthN
return res.(*grpcAuthV1.AuthNRes), nil
}
func (s *authGrpcServer) AuthenticatePAT(ctx context.Context, req *grpcAuthV1.AuthNReq) (*grpcAuthV1.AuthNRes, error) {
_, res, err := s.authenticatePAT.ServeGRPC(ctx, req)
if err != nil {
return nil, grpcapi.EncodeError(err)
}
return res.(*grpcAuthV1.AuthNRes), nil
}
func (s *authGrpcServer) Authorize(ctx context.Context, req *grpcAuthV1.AuthZReq) (*grpcAuthV1.AuthZRes, error) {
_, res, err := s.authorize.ServeGRPC(ctx, req)
if err != nil {
@@ -75,56 +53,55 @@ func (s *authGrpcServer) Authorize(ctx context.Context, req *grpcAuthV1.AuthZReq
return res.(*grpcAuthV1.AuthZRes), nil
}
func decodeAuthenticateRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
func decodeAuthenticateRequest(_ context.Context, grpcReq any) (any, error) {
req := grpcReq.(*grpcAuthV1.AuthNReq)
return authenticateReq{token: req.GetToken()}, nil
}
func encodeAuthenticateResponse(_ context.Context, grpcRes interface{}) (interface{}, 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)}, nil
return &grpcAuthV1.AuthNRes{Id: res.id, UserId: res.userID, UserRole: uint32(res.userRole), Verified: res.verified, TokenType: uint32(res.tokenType)}, nil
}
func encodeAuthenticatePATResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
res := grpcRes.(authenticateRes)
return &grpcAuthV1.AuthNRes{Id: res.id, UserId: res.userID}, nil
}
func decodeAuthorizeRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
func decodeAuthorizeRequest(_ context.Context, grpcReq any) (any, error) {
req := grpcReq.(*grpcAuthV1.AuthZReq)
return authReq{
Domain: req.GetDomain(),
SubjectType: req.GetSubjectType(),
SubjectKind: req.GetSubjectKind(),
Subject: req.GetSubject(),
Relation: req.GetRelation(),
Permission: req.GetPermission(),
ObjectType: req.GetObjectType(),
Object: req.GetObject(),
}, nil
if req == 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 interface{}) (interface{}, error) {
func encodeAuthorizeResponse(_ context.Context, grpcRes any) (any, error) {
res := grpcRes.(authorizeRes)
return &grpcAuthV1.AuthZRes{Authorized: res.authorized, Id: res.id}, nil
}
func decodeAuthorizePATRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
req := grpcReq.(*grpcAuthV1.AuthZPatReq)
return authPATReq{
userID: req.GetUserId(),
patID: req.GetPatId(),
entityType: auth.EntityType(req.GetEntityType()),
optionalDomainID: req.GetOptionalDomainId(),
operation: auth.Operation(req.GetOperation()),
entityID: req.GetEntityId(),
}, nil
}
func (s *authGrpcServer) AuthorizePAT(ctx context.Context, req *grpcAuthV1.AuthZPatReq) (*grpcAuthV1.AuthZRes, error) {
_, res, err := s.authorizePAT.ServeGRPC(ctx, req)
if err != nil {
return nil, grpcapi.EncodeError(err)
}
return res.(*grpcAuthV1.AuthZRes), nil
}
-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)
}
+81 -19
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,9 +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()),
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)
@@ -63,16 +83,18 @@ func (client tokenGrpcClient) Issue(ctx context.Context, req *grpcTokenV1.IssueR
return res.(*grpcTokenV1.Token), nil
}
func encodeIssueRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
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),
UserId: req.userID,
UserRole: uint32(req.userRole),
Type: uint32(req.keyType),
Verified: req.verified,
Description: req.description,
}, nil
}
func decodeIssueResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
func decodeIssueResponse(_ context.Context, grpcRes any) (any, error) {
return grpcRes, nil
}
@@ -80,18 +102,58 @@ func (client tokenGrpcClient) Refresh(ctx context.Context, req *grpcTokenV1.Refr
ctx, cancel := context.WithTimeout(ctx, client.timeout)
defer cancel()
res, err := client.refresh(ctx, refreshReq{refreshToken: req.GetRefreshToken()})
res, err := client.refresh(ctx, refreshReq{refreshToken: req.GetRefreshToken(), verified: req.GetVerified()})
if err != nil {
return &grpcTokenV1.Token{}, grpcapi.DecodeError(err)
}
return res.(*grpcTokenV1.Token), nil
}
func encodeRefreshRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
func encodeRefreshRequest(_ context.Context, grpcReq any) (any, error) {
req := grpcReq.(refreshReq)
return &grpcTokenV1.RefreshReq{RefreshToken: req.refreshToken}, nil
return &grpcTokenV1.RefreshReq{RefreshToken: req.refreshToken, Verified: req.verified}, nil
}
func decodeRefreshResponse(_ context.Context, grpcRes interface{}) (interface{}, 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
}
+40 -7
View File
@@ -6,21 +6,23 @@ package token
import (
"context"
"github.com/absmach/supermq/auth"
"github.com/absmach/magistrala/auth"
"github.com/go-kit/kit/endpoint"
)
func issueEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
return func(ctx context.Context, request any) (any, error) {
req := request.(issueReq)
if err := req.validate(); err != nil {
return issueRes{}, err
}
key := auth.Key{
Type: req.keyType,
Subject: req.userID,
Role: req.userRole,
Type: req.keyType,
Subject: req.userID,
Role: req.userRole,
Verified: req.verified,
Description: req.description,
}
tkn, err := svc.Issue(ctx, "", key)
if err != nil {
@@ -36,13 +38,13 @@ func issueEndpoint(svc auth.Service) endpoint.Endpoint {
}
func refreshEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
return func(ctx context.Context, request any) (any, error) {
req := request.(refreshReq)
if err := req.validate(); err != nil {
return issueRes{}, err
}
key := auth.Key{Type: auth.RefreshKey}
key := auth.Key{Type: auth.RefreshKey, Verified: req.verified}
tkn, err := svc.Issue(ctx, req.refreshToken, key)
if err != nil {
return issueRes{}, err
@@ -55,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()
}
}
+33 -5
View File
@@ -4,14 +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
userID string
userRole auth.Role
keyType auth.KeyType
verified bool
description string
}
func (req issueReq) validate() error {
@@ -27,6 +29,7 @@ func (req issueReq) validate() error {
type refreshReq struct {
refreshToken string
verified bool
}
func (req refreshReq) validate() error {
@@ -36,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
}
+73 -13
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,
),
}
}
@@ -52,21 +64,23 @@ func (s *tokenGrpcServer) Refresh(ctx context.Context, req *grpcTokenV1.RefreshR
return res.(*grpcTokenV1.Token), nil
}
func decodeIssueRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
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()),
userID: req.GetUserId(),
userRole: auth.Role(req.GetUserRole()),
keyType: auth.KeyType(req.GetType()),
verified: req.Verified,
description: req.GetDescription(),
}, nil
}
func decodeRefreshRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
func decodeRefreshRequest(_ context.Context, grpcReq any) (any, error) {
req := grpcReq.(*grpcTokenV1.RefreshReq)
return refreshReq{refreshToken: req.GetRefreshToken()}, nil
return refreshReq{refreshToken: req.GetRefreshToken(), verified: req.Verified}, nil
}
func encodeIssueResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
func encodeIssueResponse(_ context.Context, grpcRes any) (any, error) {
res := grpcRes.(issueRes)
return &grpcTokenV1.Token{
@@ -75,3 +89,49 @@ func encodeIssueResponse(_ context.Context, grpcRes interface{}) (interface{}, e
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())
+16 -4
View File
@@ -7,12 +7,12 @@ import (
"context"
"time"
"github.com/absmach/supermq/auth"
"github.com/absmach/magistrala/auth"
"github.com/go-kit/kit/endpoint"
)
func issueEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
return func(ctx context.Context, request any) (any, error) {
req := request.(issueKeyReq)
if err := req.validate(); err != nil {
return nil, err
@@ -44,7 +44,7 @@ func issueEndpoint(svc auth.Service) endpoint.Endpoint {
}
func retrieveEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
return func(ctx context.Context, request any) (any, error) {
req := request.(keyReq)
if err := req.validate(); err != nil {
@@ -71,7 +71,7 @@ func retrieveEndpoint(svc auth.Service) endpoint.Endpoint {
}
func revokeEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
return func(ctx context.Context, request any) (any, error) {
req := request.(keyReq)
if err := req.validate(); err != nil {
@@ -85,3 +85,15 @@ func revokeEndpoint(svc auth.Service) endpoint.Endpoint {
return revokeKeyRes{}, nil
}
}
func retrieveJWKSEndpoint(svc auth.Service, jwksCacheMaxAge, jwksCacheStaleWhileRevalidate int) endpoint.Endpoint {
return func(ctx context.Context, request any) (any, error) {
jwks := svc.RetrieveJWKS()
return retrieveJWKSRes{
Keys: jwks,
CacheMaxAge: jwksCacheMaxAge,
CacheStaleWhileRevalidate: jwksCacheStaleWhileRevalidate,
}, nil
}
}
+106 -101
View File
@@ -4,7 +4,6 @@
package keys_test
import (
"context"
"encoding/json"
"fmt"
"io"
@@ -14,33 +13,26 @@ 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/jwt"
"github.com/absmach/supermq/auth/mocks"
smqlog "github.com/absmach/supermq/logger"
svcerr "github.com/absmach/supermq/pkg/errors/service"
policymocks "github.com/absmach/supermq/pkg/policies/mocks"
"github.com/absmach/supermq/pkg/uuid"
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"
)
const (
secret = "secret"
contentType = "application/json"
id = "123e4567-e89b-12d3-a456-000000000001"
email = "user@example.com"
loginDuration = 30 * time.Minute
refreshDuration = 24 * time.Hour
invalidDuration = 7 * 24 * time.Hour
accessToken = "valid token"
)
var (
krepo *mocks.KeyRepository
pEvaluator *policymocks.Evaluator
)
var Token = auth.Token{
AccessToken: accessToken,
}
type issueRequest struct {
Duration time.Duration `json:"duration,omitempty"`
@@ -72,25 +64,14 @@ func (tr testRequest) make() (*http.Response, error) {
return tr.client.Do(req)
}
func newService() auth.Service {
krepo = new(mocks.KeyRepository)
pRepo := new(mocks.PATSRepository)
cache := new(mocks.Cache)
hash := new(mocks.Hasher)
idProvider := uuid.NewMock()
pService := new(policymocks.Service)
pEvaluator = new(policymocks.Evaluator)
t := jwt.New([]byte(secret))
func newServer() (*httptest.Server, *mocks.Service) {
svc := new(mocks.Service)
mux := httpapi.MakeHandler(svc, mglog.NewMock(), "", 900, 60)
return auth.New(krepo, pRepo, cache, hash, idProvider, t, pEvaluator, pService, loginDuration, refreshDuration, invalidDuration)
return httptest.NewServer(mux), svc
}
func newServer(svc auth.Service) *httptest.Server {
mux := httpapi.MakeHandler(svc, smqlog.NewMock(), "")
return httptest.NewServer(mux)
}
func toJSON(data interface{}) string {
func toJSON(data any) string {
jsonData, err := json.Marshal(data)
if err != nil {
return ""
@@ -99,13 +80,7 @@ func toJSON(data interface{}) string {
}
func TestIssue(t *testing.T) {
svc := newService()
policyCall := pEvaluator.On("CheckPolicy", mock.Anything, mock.Anything).Return(nil)
token, err := svc.Issue(context.Background(), "", auth.Key{Type: auth.AccessKey, Role: auth.UserRole, IssuedAt: time.Now(), Subject: id})
assert.Nil(t, err, fmt.Sprintf("Issuing login key expected to succeed: %s", err))
policyCall.Unset()
ts := newServer(svc)
ts, svc := newServer()
defer ts.Close()
client := ts.Client()
@@ -119,6 +94,8 @@ func TestIssue(t *testing.T) {
ct string
token string
status int
svcRes auth.Token
svcErr error
}{
{
desc: "issue login key with empty token",
@@ -131,28 +108,30 @@ func TestIssue(t *testing.T) {
desc: "issue API key",
req: toJSON(ak),
ct: contentType,
token: token.AccessToken,
token: accessToken,
status: http.StatusCreated,
svcRes: Token,
},
{
desc: "issue recovery key",
req: toJSON(rk),
ct: contentType,
token: token.AccessToken,
token: accessToken,
status: http.StatusCreated,
svcRes: Token,
},
{
desc: "issue login key wrong content type",
req: toJSON(lk),
ct: "",
token: token.AccessToken,
token: accessToken,
status: http.StatusUnsupportedMediaType,
},
{
desc: "issue recovery key wrong content type",
req: toJSON(rk),
ct: "",
token: token.AccessToken,
token: accessToken,
status: http.StatusUnsupportedMediaType,
},
{
@@ -160,6 +139,7 @@ func TestIssue(t *testing.T) {
req: toJSON(ak),
ct: contentType,
token: "wrong",
svcErr: svcerr.ErrAuthentication,
status: http.StatusUnauthorized,
},
{
@@ -167,27 +147,28 @@ func TestIssue(t *testing.T) {
req: toJSON(rk),
ct: contentType,
token: "",
svcErr: svcerr.ErrAuthentication,
status: http.StatusUnauthorized,
},
{
desc: "issue key with invalid request",
req: "{",
ct: contentType,
token: token.AccessToken,
token: accessToken,
status: http.StatusBadRequest,
},
{
desc: "issue key with invalid JSON",
req: "{invalid}",
ct: contentType,
token: token.AccessToken,
token: accessToken,
status: http.StatusBadRequest,
},
{
desc: "issue key with invalid JSON content",
req: `{"Type":{"key":"AccessToken"}}`,
ct: contentType,
token: token.AccessToken,
token: accessToken,
status: http.StatusBadRequest,
},
}
@@ -201,30 +182,16 @@ func TestIssue(t *testing.T) {
token: tc.token,
body: strings.NewReader(tc.req),
}
repocall := krepo.On("Save", mock.Anything, mock.Anything).Return("", nil)
policyCall := pEvaluator.On("CheckPolicy", mock.Anything, mock.Anything).Return(nil)
svcCall := svc.On("Issue", mock.Anything, tc.token, mock.Anything).Return(tc.svcRes, tc.svcErr)
res, err := req.make()
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode))
repocall.Unset()
policyCall.Unset()
svcCall.Unset()
}
}
func TestRetrieve(t *testing.T) {
svc := newService()
policyCall := pEvaluator.On("CheckPolicy", mock.Anything, mock.Anything).Return(nil)
token, err := svc.Issue(context.Background(), "", auth.Key{Type: auth.AccessKey, Role: auth.UserRole, IssuedAt: time.Now(), Subject: id})
assert.Nil(t, err, fmt.Sprintf("Issuing login key expected to succeed: %s", err))
key := auth.Key{Type: auth.APIKey, IssuedAt: time.Now(), Subject: id}
repocall := krepo.On("Save", mock.Anything, mock.Anything).Return(mock.Anything, nil)
k, err := svc.Issue(context.Background(), token.AccessToken, key)
assert.Nil(t, err, fmt.Sprintf("Issuing login key expected to succeed: %s", err))
repocall.Unset()
policyCall.Unset()
ts := newServer(svc)
ts, svc := newServer()
defer ts.Close()
client := ts.Client()
@@ -234,12 +201,13 @@ func TestRetrieve(t *testing.T) {
token string
key auth.Key
status int
err error
svcRes auth.Key
svcErr error
}{
{
desc: "retrieve an existing key",
id: k.AccessToken,
token: token.AccessToken,
id: id,
token: accessToken,
key: auth.Key{
Subject: id,
Type: auth.AccessKey,
@@ -247,28 +215,28 @@ func TestRetrieve(t *testing.T) {
ExpiresAt: time.Now().Add(refreshDuration),
},
status: http.StatusOK,
err: nil,
svcErr: nil,
},
{
desc: "retrieve a non-existing key",
id: "non-existing",
token: token.AccessToken,
status: http.StatusBadRequest,
err: svcerr.ErrNotFound,
token: accessToken,
status: http.StatusNotFound,
svcErr: svcerr.ErrNotFound,
},
{
desc: "retrieve a key with an invalid token",
id: k.AccessToken,
id: accessToken,
token: "wrong",
status: http.StatusUnauthorized,
err: svcerr.ErrAuthentication,
svcErr: svcerr.ErrAuthentication,
},
{
desc: "retrieve a key with an empty token",
token: "",
id: k.AccessToken,
id: accessToken,
status: http.StatusUnauthorized,
err: svcerr.ErrAuthentication,
svcErr: svcerr.ErrAuthentication,
},
}
@@ -279,30 +247,16 @@ func TestRetrieve(t *testing.T) {
url: fmt.Sprintf("%s/keys/%s", ts.URL, tc.id),
token: tc.token,
}
policyCall := pEvaluator.On("CheckPolicy", mock.Anything, mock.Anything).Return(nil)
repocall := krepo.On("Retrieve", mock.Anything, mock.Anything, mock.Anything).Return(tc.key, tc.err)
svcCall := svc.On("RetrieveKey", mock.Anything, tc.token, tc.id).Return(tc.svcRes, tc.svcErr)
res, err := req.make()
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode))
repocall.Unset()
policyCall.Unset()
svcCall.Unset()
}
}
func TestRevoke(t *testing.T) {
svc := newService()
policyCall := pEvaluator.On("CheckPolicy", mock.Anything, mock.Anything).Return(nil)
token, err := svc.Issue(context.Background(), "", auth.Key{Type: auth.AccessKey, Role: auth.UserRole, IssuedAt: time.Now(), Subject: id})
assert.Nil(t, err, fmt.Sprintf("Issuing login key expected to succeed: %s", err))
key := auth.Key{Type: auth.APIKey, IssuedAt: time.Now(), Subject: id}
repocall := krepo.On("Save", mock.Anything, mock.Anything).Return(mock.Anything, nil)
k, err := svc.Issue(context.Background(), token.AccessToken, key)
assert.Nil(t, err, fmt.Sprintf("Issuing login key expected to succeed: %s", err))
repocall.Unset()
policyCall.Unset()
ts := newServer(svc)
ts, svc := newServer()
defer ts.Close()
client := ts.Client()
@@ -311,29 +265,33 @@ func TestRevoke(t *testing.T) {
id string
token string
status int
svcErr error
}{
{
desc: "revoke an existing key",
id: k.AccessToken,
token: token.AccessToken,
id: id,
token: accessToken,
status: http.StatusNoContent,
},
{
desc: "revoke a non-existing key",
id: "non-existing",
token: token.AccessToken,
status: http.StatusNoContent,
token: accessToken,
svcErr: svcerr.ErrNotFound,
status: http.StatusNotFound,
},
{
desc: "revoke key with invalid token",
id: k.AccessToken,
id: id,
token: "wrong",
svcErr: svcerr.ErrAuthentication,
status: http.StatusUnauthorized,
},
{
desc: "revoke key with empty token",
id: k.AccessToken,
id: id,
token: "",
svcErr: svcerr.ErrAuthentication,
status: http.StatusUnauthorized,
},
}
@@ -345,10 +303,57 @@ func TestRevoke(t *testing.T) {
url: fmt.Sprintf("%s/keys/%s", ts.URL, tc.id),
token: tc.token,
}
repocall := krepo.On("Remove", mock.Anything, mock.Anything, mock.Anything).Return(nil)
svcCall := svc.On("Revoke", mock.Anything, tc.token, tc.id).Return(tc.svcErr)
res, err := req.make()
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode))
repocall.Unset()
svcCall.Unset()
}
}
func TestRetrieveJWKS(t *testing.T) {
ts, svc := newServer()
defer ts.Close()
client := ts.Client()
cases := []struct {
desc string
svcRes []auth.PublicKeyInfo
status int
}{
{
desc: "retrieve JWKS with keys",
svcRes: []auth.PublicKeyInfo{newPublicKeyInfo(), newPublicKeyInfo()},
status: http.StatusOK,
},
{
desc: "retrieve empty JWKS",
svcRes: []auth.PublicKeyInfo{},
status: http.StatusOK,
},
}
for _, tc := range cases {
req := testRequest{
client: client,
method: http.MethodGet,
url: fmt.Sprintf("%s/keys/.well-known/jwks.json", ts.URL),
}
svcCall := svc.On("RetrieveJWKS").Return(tc.svcRes)
res, err := req.make()
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode))
svcCall.Unset()
}
}
func newPublicKeyInfo() auth.PublicKeyInfo {
return auth.PublicKeyInfo{
KeyID: "test-key-id",
KeyType: "OKP",
Algorithm: "EdDSA",
Use: "sig",
Curve: "Ed25519",
X: "base64url-encoded-public-key",
}
}
+4 -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 {
@@ -46,3 +46,5 @@ func (req keyReq) validate() error {
}
return nil
}
type jwksReq 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"
)
+39 -4
View File
@@ -4,16 +4,20 @@
package keys
import (
"encoding/json"
"fmt"
"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)
_ magistrala.Response = (*issueKeyRes)(nil)
_ magistrala.Response = (*revokeKeyRes)(nil)
_ magistrala.Response = (*retrieveKeyRes)(nil)
_ magistrala.Response = (*retrieveJWKSRes)(nil)
)
type issueKeyRes struct {
@@ -69,3 +73,34 @@ func (res revokeKeyRes) Headers() map[string]string {
func (res revokeKeyRes) Empty() bool {
return true
}
type retrieveJWKSRes struct {
Keys []auth.PublicKeyInfo `json:"-"`
CacheMaxAge int `json:"-"`
CacheStaleWhileRevalidate int `json:"-"`
}
func (res retrieveJWKSRes) MarshalJSON() ([]byte, error) {
type jwksResponse struct {
Keys []auth.PublicKeyInfo `json:"keys"`
}
return json.Marshal(jwksResponse{Keys: res.Keys})
}
func (res retrieveJWKSRes) Code() int {
return http.StatusOK
}
func (res retrieveJWKSRes) Headers() map[string]string {
cacheControl := fmt.Sprintf("public, max-age=%d, stale-while-revalidate=%d", res.CacheMaxAge, res.CacheStaleWhileRevalidate)
headers := map[string]string{
"Cache-Control": cacheControl,
}
return headers
}
func (res retrieveJWKSRes) Empty() bool {
return false
}
+20 -8
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"
)
@@ -21,7 +21,7 @@ import (
const contentType = "application/json"
// MakeHandler returns a HTTP handler for API endpoints.
func MakeHandler(svc auth.Service, mux *chi.Mux, logger *slog.Logger) *chi.Mux {
func MakeHandler(svc auth.Service, mux *chi.Mux, logger *slog.Logger, jwksCacheMaxAge, jwksCacheStaleWhileRevalidate int) *chi.Mux {
opts := []kithttp.ServerOption{
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, api.EncodeError)),
}
@@ -46,27 +46,39 @@ func MakeHandler(svc auth.Service, mux *chi.Mux, logger *slog.Logger) *chi.Mux {
api.EncodeResponse,
opts...,
).ServeHTTP)
r.Get("/.well-known/jwks.json", kithttp.NewServer(
retrieveJWKSEndpoint(svc, jwksCacheMaxAge, jwksCacheStaleWhileRevalidate),
decodeJWKSReq,
api.EncodeResponse,
opts...,
).ServeHTTP)
})
return mux
}
func decodeIssue(_ context.Context, r *http.Request) (interface{}, error) {
func decodeIssue(_ context.Context, r *http.Request) (any, error) {
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
return nil, apiutil.ErrUnsupportedContentType
}
req := issueKeyReq{token: apiutil.ExtractBearerToken(r)}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
return nil, errors.Wrap(apiutil.ErrMalformedRequestBody, err)
}
return req, nil
}
func decodeKeyReq(_ context.Context, r *http.Request) (interface{}, error) {
func decodeKeyReq(_ context.Context, r *http.Request) (any, error) {
req := keyReq{
token: apiutil.ExtractBearerToken(r),
id: chi.URLParam(r, "id"),
}
return req, nil
}
func decodeJWKSReq(_ context.Context, _ *http.Request) (any, error) {
req := jwksReq{}
return req, nil
}
+14 -14
View File
@@ -6,12 +6,12 @@ package pats
import (
"context"
"github.com/absmach/supermq/auth"
"github.com/absmach/magistrala/auth"
"github.com/go-kit/kit/endpoint"
)
func createPATEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
return func(ctx context.Context, request any) (any, error) {
req := request.(createPatReq)
if err := req.validate(); err != nil {
return nil, err
@@ -27,7 +27,7 @@ func createPATEndpoint(svc auth.Service) endpoint.Endpoint {
}
func retrievePATEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
return func(ctx context.Context, request any) (any, error) {
req := request.(retrievePatReq)
if err := req.validate(); err != nil {
return nil, err
@@ -43,7 +43,7 @@ func retrievePATEndpoint(svc auth.Service) endpoint.Endpoint {
}
func updatePATNameEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
return func(ctx context.Context, request any) (any, error) {
req := request.(updatePatNameReq)
if err := req.validate(); err != nil {
return nil, err
@@ -59,7 +59,7 @@ func updatePATNameEndpoint(svc auth.Service) endpoint.Endpoint {
}
func updatePATDescriptionEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
return func(ctx context.Context, request any) (any, error) {
req := request.(updatePatDescriptionReq)
if err := req.validate(); err != nil {
return nil, err
@@ -75,7 +75,7 @@ func updatePATDescriptionEndpoint(svc auth.Service) endpoint.Endpoint {
}
func listPATSEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
return func(ctx context.Context, request any) (any, error) {
req := request.(listPatsReq)
if err := req.validate(); err != nil {
return nil, err
@@ -98,7 +98,7 @@ func listPATSEndpoint(svc auth.Service) endpoint.Endpoint {
}
func deletePATEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
return func(ctx context.Context, request any) (any, error) {
req := request.(deletePatReq)
if err := req.validate(); err != nil {
return nil, err
@@ -113,7 +113,7 @@ func deletePATEndpoint(svc auth.Service) endpoint.Endpoint {
}
func resetPATSecretEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
return func(ctx context.Context, request any) (any, error) {
req := request.(resetPatSecretReq)
if err := req.validate(); err != nil {
return nil, err
@@ -129,7 +129,7 @@ func resetPATSecretEndpoint(svc auth.Service) endpoint.Endpoint {
}
func revokePATSecretEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
return func(ctx context.Context, request any) (any, error) {
req := request.(revokePatSecretReq)
if err := req.validate(); err != nil {
return nil, err
@@ -144,7 +144,7 @@ func revokePATSecretEndpoint(svc auth.Service) endpoint.Endpoint {
}
func clearAllPATEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
return func(ctx context.Context, request any) (any, error) {
req := request.(clearAllPATReq)
if err := req.validate(); err != nil {
return nil, err
@@ -159,7 +159,7 @@ func clearAllPATEndpoint(svc auth.Service) endpoint.Endpoint {
}
func addScopeEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
return func(ctx context.Context, request any) (any, error) {
req := request.(addScopeReq)
if err := req.validate(); err != nil {
return nil, err
@@ -174,7 +174,7 @@ func addScopeEndpoint(svc auth.Service) endpoint.Endpoint {
}
func removeScopeEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
return func(ctx context.Context, request any) (any, error) {
req := request.(removeScopeReq)
if err := req.validate(); err != nil {
return nil, err
@@ -189,7 +189,7 @@ func removeScopeEndpoint(svc auth.Service) endpoint.Endpoint {
}
func clearAllScopeEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
return func(ctx context.Context, request any) (any, error) {
req := request.(clearAllScopeReq)
if err := req.validate(); err != nil {
return nil, err
@@ -204,7 +204,7 @@ func clearAllScopeEndpoint(svc auth.Service) endpoint.Endpoint {
}
func listScopesEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
return func(ctx context.Context, request any) (any, error) {
req := request.(listScopesReq)
if err := req.validate(); err != nil {
return nil, err
+5 -5
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 {
@@ -199,12 +199,12 @@ type addScopeReq struct {
Scopes []auth.Scope `json:"scopes,omitempty"`
}
func (aser *addScopeReq) UnmarshalJSON(data []byte) error {
func (req *addScopeReq) UnmarshalJSON(data []byte) error {
type Alias addScopeReq
aux := &struct {
*Alias
}{
Alias: (*Alias)(aser),
Alias: (*Alias)(req),
}
if err := json.Unmarshal(data, aux); err != nil {
+724
View File
@@ -0,0 +1,724 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package pats
import (
"encoding/json"
"testing"
"time"
apiutil "github.com/absmach/magistrala/api/http/util"
"github.com/absmach/magistrala/auth"
"github.com/stretchr/testify/assert"
)
var valid = "valid"
func TestCreatePatReqValidate(t *testing.T) {
cases := []struct {
desc string
req createPatReq
err error
}{
{
desc: "valid request",
req: createPatReq{
token: valid,
Name: "test-pat",
Description: "test description",
Duration: 24 * time.Hour,
},
err: nil,
},
{
desc: "empty token",
req: createPatReq{
token: "",
Name: "test-pat",
Description: "test description",
Duration: 24 * time.Hour,
},
err: apiutil.ErrBearerToken,
},
{
desc: "empty name",
req: createPatReq{
token: valid,
Name: "",
Description: "test description",
Duration: 24 * time.Hour,
},
err: apiutil.ErrMissingName,
},
{
desc: "whitespace only name",
req: createPatReq{
token: valid,
Name: " ",
Description: "test description",
Duration: 24 * time.Hour,
},
err: apiutil.ErrMissingName,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
err := tc.req.validate()
assert.Equal(t, tc.err, err, "validate() error = %v, expected %v", err, tc.err)
})
}
}
func TestCreatePatReqUnmarshalJSON(t *testing.T) {
cases := []struct {
desc string
data string
expected createPatReq
err bool
}{
{
desc: "valid JSON with duration",
data: `{"name":"test-pat","description":"test desc","duration":"24h"}`,
expected: createPatReq{
Name: "test-pat",
Description: "test desc",
Duration: 24 * time.Hour,
},
err: false,
},
{
desc: "invalid duration format",
data: `{"name":"test-pat","description":"test desc","duration":"invalid"}`,
err: true,
},
{
desc: "invalid JSON",
data: `{invalid json}`,
err: true,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
var req createPatReq
err := json.Unmarshal([]byte(tc.data), &req)
if tc.err {
assert.Error(t, err, "UnmarshalJSON() should return error")
} else {
assert.NoError(t, err, "UnmarshalJSON() should not return error")
assert.Equal(t, tc.expected.Name, req.Name)
assert.Equal(t, tc.expected.Description, req.Description)
assert.Equal(t, tc.expected.Duration, req.Duration)
}
})
}
}
func TestRetrievePatReqValidate(t *testing.T) {
cases := []struct {
desc string
req retrievePatReq
err error
}{
{
desc: "valid request",
req: retrievePatReq{
token: valid,
id: "pat-id",
},
err: nil,
},
{
desc: "empty token",
req: retrievePatReq{
token: "",
id: "pat-id",
},
err: apiutil.ErrBearerToken,
},
{
desc: "empty id",
req: retrievePatReq{
token: valid,
id: "",
},
err: apiutil.ErrMissingPATID,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
err := tc.req.validate()
assert.Equal(t, tc.err, err, "validate() error = %v, expected %v", err, tc.err)
})
}
}
func TestUpdatePatNameReqValidate(t *testing.T) {
cases := []struct {
desc string
req updatePatNameReq
err error
}{
{
desc: "valid request",
req: updatePatNameReq{
token: valid,
id: "pat-id",
Name: "new-name",
},
err: nil,
},
{
desc: "empty token",
req: updatePatNameReq{
token: "",
id: "pat-id",
Name: "new-name",
},
err: apiutil.ErrBearerToken,
},
{
desc: "empty id",
req: updatePatNameReq{
token: valid,
id: "",
Name: "new-name",
},
err: apiutil.ErrMissingPATID,
},
{
desc: "empty name",
req: updatePatNameReq{
token: valid,
id: "pat-id",
Name: "",
},
err: apiutil.ErrMissingName,
},
{
desc: "whitespace only name",
req: updatePatNameReq{
token: valid,
id: "pat-id",
Name: " ",
},
err: apiutil.ErrMissingName,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
err := tc.req.validate()
assert.Equal(t, tc.err, err, "validate() error = %v, expected %v", err, tc.err)
})
}
}
func TestUpdatePatDescriptionReqValidate(t *testing.T) {
cases := []struct {
desc string
req updatePatDescriptionReq
err error
}{
{
desc: "valid request",
req: updatePatDescriptionReq{
token: valid,
id: "pat-id",
Description: "new description",
},
err: nil,
},
{
desc: "empty token",
req: updatePatDescriptionReq{
token: "",
id: "pat-id",
Description: "new description",
},
err: apiutil.ErrBearerToken,
},
{
desc: "empty id",
req: updatePatDescriptionReq{
token: valid,
id: "",
Description: "new description",
},
err: apiutil.ErrMissingPATID,
},
{
desc: "empty description",
req: updatePatDescriptionReq{
token: valid,
id: "pat-id",
Description: "",
},
err: apiutil.ErrMissingDescription,
},
{
desc: "whitespace only description",
req: updatePatDescriptionReq{
token: valid,
id: "pat-id",
Description: " ",
},
err: apiutil.ErrMissingDescription,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
err := tc.req.validate()
assert.Equal(t, tc.err, err, "validate() error = %v, expected %v", err, tc.err)
})
}
}
func TestListPatsReqValidate(t *testing.T) {
cases := []struct {
desc string
req listPatsReq
err error
}{
{
desc: "valid request",
req: listPatsReq{
token: valid,
offset: 0,
limit: 10,
},
err: nil,
},
{
desc: "empty token",
req: listPatsReq{
token: "",
offset: 0,
limit: 10,
},
err: apiutil.ErrBearerToken,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
err := tc.req.validate()
assert.Equal(t, tc.err, err, "validate() error = %v, expected %v", err, tc.err)
})
}
}
func TestDeletePatReqValidate(t *testing.T) {
cases := []struct {
desc string
req deletePatReq
err error
}{
{
desc: "valid request",
req: deletePatReq{
token: valid,
id: "pat-id",
},
err: nil,
},
{
desc: "empty token",
req: deletePatReq{
token: "",
id: "pat-id",
},
err: apiutil.ErrBearerToken,
},
{
desc: "empty id",
req: deletePatReq{
token: valid,
id: "",
},
err: apiutil.ErrMissingPATID,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
err := tc.req.validate()
assert.Equal(t, tc.err, err, "validate() error = %v, expected %v", err, tc.err)
})
}
}
func TestResetPatSecretReqValidate(t *testing.T) {
cases := []struct {
desc string
req resetPatSecretReq
err error
}{
{
desc: "valid request",
req: resetPatSecretReq{
token: valid,
id: "pat-id",
Duration: 24 * time.Hour,
},
err: nil,
},
{
desc: "empty token",
req: resetPatSecretReq{
token: "",
id: "pat-id",
Duration: 24 * time.Hour,
},
err: apiutil.ErrBearerToken,
},
{
desc: "empty id",
req: resetPatSecretReq{
token: valid,
id: "",
Duration: 24 * time.Hour,
},
err: apiutil.ErrMissingPATID,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
err := tc.req.validate()
assert.Equal(t, tc.err, err, "validate() error = %v, expected %v", err, tc.err)
})
}
}
func TestResetPatSecretReqUnmarshalJSON(t *testing.T) {
cases := []struct {
desc string
data string
expected resetPatSecretReq
err bool
}{
{
desc: "valid JSON with duration",
data: `{"duration":"48h"}`,
expected: resetPatSecretReq{
Duration: 48 * time.Hour,
},
err: false,
},
{
desc: "invalid duration format",
data: `{"duration":"invalid"}`,
err: true,
},
{
desc: "invalid JSON",
data: `{invalid}`,
err: true,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
var req resetPatSecretReq
err := json.Unmarshal([]byte(tc.data), &req)
if tc.err {
assert.Error(t, err, "UnmarshalJSON() should return error")
} else {
assert.NoError(t, err, "UnmarshalJSON() should not return error")
assert.Equal(t, tc.expected.Duration, req.Duration)
}
})
}
}
func TestRevokePatSecretReqValidate(t *testing.T) {
cases := []struct {
desc string
req revokePatSecretReq
err error
}{
{
desc: "valid request",
req: revokePatSecretReq{
token: valid,
id: "pat-id",
},
err: nil,
},
{
desc: "empty token",
req: revokePatSecretReq{
token: "",
id: "pat-id",
},
err: apiutil.ErrBearerToken,
},
{
desc: "empty id",
req: revokePatSecretReq{
token: valid,
id: "",
},
err: apiutil.ErrMissingPATID,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
err := tc.req.validate()
assert.Equal(t, tc.err, err, "validate() error = %v, expected %v", err, tc.err)
})
}
}
func TestClearAllPATReqValidate(t *testing.T) {
cases := []struct {
desc string
req clearAllPATReq
err error
}{
{
desc: "valid request",
req: clearAllPATReq{
token: valid,
},
err: nil,
},
{
desc: "empty token",
req: clearAllPATReq{
token: "",
},
err: apiutil.ErrBearerToken,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
err := tc.req.validate()
assert.Equal(t, tc.err, err, "validate() error = %v, expected %v", err, tc.err)
})
}
}
func TestAddScopeReqValidate(t *testing.T) {
validScope := auth.Scope{
DomainID: "domain1",
EntityType: auth.GroupsType,
EntityID: "entity1",
Operation: "create",
}
invalidScope := auth.Scope{
DomainID: "",
EntityType: auth.GroupsType,
EntityID: "",
Operation: "view",
}
cases := []struct {
desc string
req addScopeReq
err error
}{
{
desc: "valid request",
req: addScopeReq{
token: valid,
id: "pat-id",
Scopes: []auth.Scope{validScope},
},
err: nil,
},
{
desc: "empty token",
req: addScopeReq{
token: "",
id: "pat-id",
Scopes: []auth.Scope{validScope},
},
err: apiutil.ErrBearerToken,
},
{
desc: "empty id",
req: addScopeReq{
token: valid,
id: "",
Scopes: []auth.Scope{validScope},
},
err: apiutil.ErrMissingPATID,
},
{
desc: "empty scopes",
req: addScopeReq{
token: valid,
id: "pat-id",
Scopes: []auth.Scope{},
},
err: apiutil.ErrValidation,
},
{
desc: "invalid scope",
req: addScopeReq{
token: valid,
id: "pat-id",
Scopes: []auth.Scope{invalidScope},
},
err: apiutil.ErrValidation,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
err := tc.req.validate()
if tc.err != nil {
assert.Error(t, err, "validate() should return error")
} else {
assert.NoError(t, err, "validate() should not return error")
}
})
}
}
func TestRemoveScopeReqValidate(t *testing.T) {
cases := []struct {
desc string
req removeScopeReq
err error
}{
{
desc: "valid request",
req: removeScopeReq{
token: valid,
id: "pat-id",
ScopesID: []string{"scope1", "scope2"},
},
err: nil,
},
{
desc: "empty token",
req: removeScopeReq{
token: "",
id: "pat-id",
ScopesID: []string{"scope1"},
},
err: apiutil.ErrBearerToken,
},
{
desc: "empty id",
req: removeScopeReq{
token: valid,
id: "",
ScopesID: []string{"scope1"},
},
err: apiutil.ErrMissingPATID,
},
{
desc: "empty scopes list",
req: removeScopeReq{
token: valid,
id: "pat-id",
ScopesID: []string{},
},
err: apiutil.ErrValidation,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
err := tc.req.validate()
assert.Equal(t, tc.err, err, "validate() error = %v, expected %v", err, tc.err)
})
}
}
func TestClearAllScopeReqValidate(t *testing.T) {
cases := []struct {
desc string
req clearAllScopeReq
err error
}{
{
desc: "valid request",
req: clearAllScopeReq{
token: valid,
id: "pat-id",
},
err: nil,
},
{
desc: "empty token",
req: clearAllScopeReq{
token: "",
id: "pat-id",
},
err: apiutil.ErrBearerToken,
},
{
desc: "empty id",
req: clearAllScopeReq{
token: valid,
id: "",
},
err: apiutil.ErrMissingPATID,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
err := tc.req.validate()
assert.Equal(t, tc.err, err, "validate() error = %v, expected %v", err, tc.err)
})
}
}
func TestListScopesReqValidate(t *testing.T) {
cases := []struct {
desc string
req listScopesReq
err error
}{
{
desc: "valid request",
req: listScopesReq{
token: valid,
offset: 0,
limit: 10,
patID: "pat-id",
},
err: nil,
},
{
desc: "empty token",
req: listScopesReq{
token: "",
offset: 0,
limit: 10,
patID: "pat-id",
},
err: apiutil.ErrBearerToken,
},
{
desc: "empty patID",
req: listScopesReq{
token: valid,
offset: 0,
limit: 10,
patID: "",
},
err: apiutil.ErrMissingPATID,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
err := tc.req.validate()
assert.Equal(t, tc.err, err, "validate() error = %v, expected %v", err, tc.err)
})
}
}
+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 {
+23 -23
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"
)
@@ -130,7 +130,7 @@ func MakeHandler(svc auth.Service, mux *chi.Mux, logger *slog.Logger) *chi.Mux {
return mux
}
func decodeCreatePATRequest(_ context.Context, r *http.Request) (interface{}, error) {
func decodeCreatePATRequest(_ context.Context, r *http.Request) (any, error) {
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
return nil, apiutil.ErrUnsupportedContentType
}
@@ -140,12 +140,12 @@ func decodeCreatePATRequest(_ context.Context, r *http.Request) (interface{}, er
}
req := createPatReq{token: token}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(err, errors.ErrMalformedEntity))
return nil, errors.Wrap(apiutil.ErrMalformedRequestBody, err)
}
return req, nil
}
func decodeRetrievePATRequest(_ context.Context, r *http.Request) (interface{}, error) {
func decodeRetrievePATRequest(_ context.Context, r *http.Request) (any, error) {
token := apiutil.ExtractBearerToken(r)
if strings.HasPrefix(token, patPrefix) {
return nil, apiutil.ErrUnsupportedTokenType
@@ -158,7 +158,7 @@ func decodeRetrievePATRequest(_ context.Context, r *http.Request) (interface{},
return req, nil
}
func decodeUpdatePATNameRequest(_ context.Context, r *http.Request) (interface{}, error) {
func decodeUpdatePATNameRequest(_ context.Context, r *http.Request) (any, error) {
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
return nil, apiutil.ErrUnsupportedContentType
}
@@ -171,12 +171,12 @@ func decodeUpdatePATNameRequest(_ context.Context, r *http.Request) (interface{}
id: chi.URLParam(r, "id"),
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
return nil, errors.Wrap(apiutil.ErrMalformedRequestBody, err)
}
return req, nil
}
func decodeUpdatePATDescriptionRequest(_ context.Context, r *http.Request) (interface{}, error) {
func decodeUpdatePATDescriptionRequest(_ context.Context, r *http.Request) (any, error) {
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
return nil, apiutil.ErrUnsupportedContentType
}
@@ -190,12 +190,12 @@ func decodeUpdatePATDescriptionRequest(_ context.Context, r *http.Request) (inte
id: chi.URLParam(r, "id"),
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
return nil, errors.Wrap(apiutil.ErrMalformedRequestBody, err)
}
return req, nil
}
func decodeListPATSRequest(_ context.Context, r *http.Request) (interface{}, error) {
func decodeListPATSRequest(_ context.Context, r *http.Request) (any, error) {
l, err := apiutil.ReadNumQuery[uint64](r, api.LimitKey, api.DefLimit)
if err != nil {
return nil, errors.Wrap(apiutil.ErrValidation, err)
@@ -237,7 +237,7 @@ func decodeListPATSRequest(_ context.Context, r *http.Request) (interface{}, err
return req, nil
}
func decodeDeletePATRequest(_ context.Context, r *http.Request) (interface{}, error) {
func decodeDeletePATRequest(_ context.Context, r *http.Request) (any, error) {
token := apiutil.ExtractBearerToken(r)
if strings.HasPrefix(token, patPrefix) {
return nil, apiutil.ErrUnsupportedTokenType
@@ -248,7 +248,7 @@ func decodeDeletePATRequest(_ context.Context, r *http.Request) (interface{}, er
}, nil
}
func decodeResetPATSecretRequest(_ context.Context, r *http.Request) (interface{}, error) {
func decodeResetPATSecretRequest(_ context.Context, r *http.Request) (any, error) {
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
return nil, apiutil.ErrUnsupportedContentType
}
@@ -262,12 +262,12 @@ func decodeResetPATSecretRequest(_ context.Context, r *http.Request) (interface{
id: chi.URLParam(r, "id"),
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
return nil, errors.Wrap(apiutil.ErrMalformedRequestBody, err)
}
return req, nil
}
func decodeRevokePATSecretRequest(_ context.Context, r *http.Request) (interface{}, error) {
func decodeRevokePATSecretRequest(_ context.Context, r *http.Request) (any, error) {
token := apiutil.ExtractBearerToken(r)
if strings.HasPrefix(token, patPrefix) {
return nil, apiutil.ErrUnsupportedTokenType
@@ -278,7 +278,7 @@ func decodeRevokePATSecretRequest(_ context.Context, r *http.Request) (interface
}, nil
}
func decodeClearAllPATRequest(_ context.Context, r *http.Request) (interface{}, error) {
func decodeClearAllPATRequest(_ context.Context, r *http.Request) (any, error) {
token := apiutil.ExtractBearerToken(r)
if strings.HasPrefix(token, patPrefix) {
return nil, apiutil.ErrUnsupportedTokenType
@@ -289,7 +289,7 @@ func decodeClearAllPATRequest(_ context.Context, r *http.Request) (interface{},
}, nil
}
func decodeAddScopeRequest(_ context.Context, r *http.Request) (interface{}, error) {
func decodeAddScopeRequest(_ context.Context, r *http.Request) (any, error) {
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
return nil, apiutil.ErrUnsupportedContentType
}
@@ -305,13 +305,13 @@ func decodeAddScopeRequest(_ context.Context, r *http.Request) (interface{}, err
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
return nil, errors.Wrap(apiutil.ErrMalformedRequestBody, err)
}
return req, nil
}
func decodeListScopeRequest(_ context.Context, r *http.Request) (interface{}, error) {
func decodeListScopeRequest(_ context.Context, r *http.Request) (any, error) {
l, err := apiutil.ReadNumQuery[uint64](r, api.LimitKey, api.DefLimit)
if err != nil {
return nil, errors.Wrap(apiutil.ErrValidation, err)
@@ -333,7 +333,7 @@ func decodeListScopeRequest(_ context.Context, r *http.Request) (interface{}, er
return req, nil
}
func decodeRemoveScopeRequest(_ context.Context, r *http.Request) (interface{}, error) {
func decodeRemoveScopeRequest(_ context.Context, r *http.Request) (any, error) {
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
return nil, apiutil.ErrUnsupportedContentType
}
@@ -348,12 +348,12 @@ func decodeRemoveScopeRequest(_ context.Context, r *http.Request) (interface{},
id: chi.URLParam(r, "id"),
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
return nil, errors.Wrap(apiutil.ErrMalformedRequestBody, err)
}
return req, nil
}
func decodeClearAllScopeRequest(_ context.Context, r *http.Request) (interface{}, error) {
func decodeClearAllScopeRequest(_ context.Context, r *http.Request) (any, error) {
token := apiutil.ExtractBearerToken(r)
if strings.HasPrefix(token, patPrefix) {
return nil, apiutil.ErrUnsupportedTokenType
+7 -7
View File
@@ -6,22 +6,22 @@ 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"
)
// MakeHandler returns a HTTP handler for API endpoints.
func MakeHandler(svc auth.Service, logger *slog.Logger, instanceID string) http.Handler {
func MakeHandler(svc auth.Service, logger *slog.Logger, instanceID string, jwksCacheMaxAge, jwksCacheStaleWhileRevalidate int) http.Handler {
mux := chi.NewRouter()
mux = keys.MakeHandler(svc, mux, logger)
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)
}

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