mirror of
https://github.com/absmach/magistrala.git
synced 2026-08-07 15:25:48 +00:00
Compare commits
832 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f8410b8940 | |||
| 2260293dfc | |||
| c9f34e3759 | |||
| aeb1d9d0a1 | |||
| 03a8feb679 | |||
| 9c2608659f | |||
| 2c476c17ee | |||
| 3b2dd09ab4 | |||
| 5255d887ef | |||
| bb8917cc34 | |||
| 4792a99c9a | |||
| fe49305238 | |||
| 03143d4142 | |||
| 15a6c026e9 | |||
| 175f0e08ab | |||
| 41526634f8 | |||
| 73a640e646 | |||
| 6ca535155a | |||
| 4a449629b3 | |||
| 1cd00fbd83 | |||
| a871fa926e | |||
| c7fad0d2ca | |||
| 51e782693d | |||
| e3a3e052d2 | |||
| 1e8437cfc2 | |||
| f8f4ccac79 | |||
| 56bb07273d | |||
| aba4d6a0b7 | |||
| b948edc573 | |||
| 20bafe0077 | |||
| 4e77ae65e2 | |||
| 61c120f947 | |||
| 0d4f4c9266 | |||
| 668338dfa2 | |||
| 38ea004e30 | |||
| 7b99baeb02 | |||
| cd31b1c6bd | |||
| 1a348b11dd | |||
| f552e08661 | |||
| 5606cdbe47 | |||
| 59d9f91813 | |||
| 5b913dd46b | |||
| 9293de7636 | |||
| 2dd8c44aa3 | |||
| 28fc9738df | |||
| ad1d67a678 | |||
| 1086f3e208 | |||
| b896c03f5f | |||
| d78c1e8d20 | |||
| 551d44d58e | |||
| 927230dbb4 | |||
| c7996ce6cf | |||
| bf7a965195 | |||
| 67c28ff134 | |||
| a526a2ccd5 | |||
| c679224596 | |||
| e1c881d2ad | |||
| 9a0d8062be | |||
| 25d8b86f2b | |||
| 24ca513eff | |||
| 52510d8c62 | |||
| 6b6bab79c6 | |||
| 6a5d28c65a | |||
| 59f8d4e4d7 | |||
| e23555ee2a | |||
| cb337a38fd | |||
| f9b503f1d6 | |||
| 0fe5a6d6e8 | |||
| f612109f24 | |||
| 3fcf2e5369 | |||
| 1355bc8bb7 | |||
| 1e7e65d642 | |||
| 3a5c1e12df | |||
| 61b95a28c2 | |||
| 4c40b8b82c | |||
| 955c556fe6 | |||
| dc437a8296 | |||
| 314537f7c5 | |||
| 7e5fd0cfa8 | |||
| 6a2c8a3ca6 | |||
| 2bea4412d8 | |||
| c8cb0daa6c | |||
| f8017c8b9f | |||
| 27fc32c153 | |||
| 9aa9487207 | |||
| 1292095cdb | |||
| 856ef1ba49 | |||
| 146028fb98 | |||
| 6cb3e635c9 | |||
| 175d27c4b6 | |||
| eec6b8be07 | |||
| e48e5dee1f | |||
| 0df8e8451c | |||
| e77e3a3bb6 | |||
| 3e6b771850 | |||
| 15e756a5a3 | |||
| c5a4336d43 | |||
| b05ae65e24 | |||
| 1a8d11acdd | |||
| 27b72db52e | |||
| e75ce59998 | |||
| cd281c2589 | |||
| 9d13d5b528 | |||
| f7dcaa949b | |||
| fa080ab0f8 | |||
| 5807cf1754 | |||
| f96ddab9dd | |||
| 914d491a13 | |||
| 843a0cae1f | |||
| 9ba9a12084 | |||
| 5ed6b258a0 | |||
| eb83edbcde | |||
| 5c12bc8c91 | |||
| 589209eae2 | |||
| a2e660b8a1 | |||
| 21731aef37 | |||
| 2f55947305 | |||
| 80806c4745 | |||
| 1947f6e78e | |||
| 5b0c556b60 | |||
| 5891e4bb75 | |||
| 299742096a | |||
| 27c57b192b | |||
| 8083cec373 | |||
| e2d9b1ddf9 | |||
| 6092bc2cf0 | |||
| 071d23a5f0 | |||
| 7bb4b298c5 | |||
| cac6c648d3 | |||
| 4ee7736b32 | |||
| 8ed8915e4f | |||
| 65c6a4d8f4 | |||
| ec223e7467 | |||
| aa3cc3d7ee | |||
| 9650dde716 | |||
| d02747a56f | |||
| dc0df1c955 | |||
| 64b4497ad4 | |||
| 1b26264495 | |||
| 69366d77cc | |||
| fa8862cbc8 | |||
| 15b8901853 | |||
| 9258237cb6 | |||
| 2adeecd9ec | |||
| c5eee6d8fd | |||
| 648edbd386 | |||
| 35fb296318 | |||
| a98777b191 | |||
| 3c693a7b41 | |||
| c230a24b7d | |||
| 42b2a8c166 | |||
| 6468ebe749 | |||
| 1adbe1ff24 | |||
| 27995cb093 | |||
| 5833bafbee | |||
| 6394908b2c | |||
| 0e0598c6d8 | |||
| 3e400da5ad | |||
| 2112281171 | |||
| 6f40c7fa1e | |||
| b0e9e43b9e | |||
| bc7727c275 | |||
| 8d1c3c41b5 | |||
| d84df8604f | |||
| d4d8bc5351 | |||
| ac9bc9aad6 | |||
| 4b83301f69 | |||
| b746a8679f | |||
| e6022542b9 | |||
| 6c77e1b738 | |||
| 04774ae972 | |||
| ae7c93020a | |||
| b031dc08b8 | |||
| 0465ceb7a3 | |||
| af424ee2cb | |||
| 96a15b32dd | |||
| 61f1e9aca2 | |||
| 29f7063c15 | |||
| 1f48a73677 | |||
| cd9cb9e1d5 | |||
| 8d9e92f228 | |||
| ad685c27ad | |||
| 44485cacec | |||
| 7fac6ff4c4 | |||
| 1930a0c8f2 | |||
| 9eac9366ba | |||
| ad191c4609 | |||
| 1d935f0519 | |||
| bc1ccace4a | |||
| 89fdb4e6c7 | |||
| 44e44639aa | |||
| d31c66174e | |||
| e6d7a07277 | |||
| a2ea92a5ba | |||
| 3320a716f3 | |||
| a70b838f1c | |||
| c50221a042 | |||
| 1efa8b5bce | |||
| e57ad79cd4 | |||
| 22616911d2 | |||
| 766bb5519a | |||
| fbcdef9693 | |||
| 9aacde7c5b | |||
| cdf26051f6 | |||
| a9a412e909 | |||
| 0754fa1126 | |||
| ec75f4eadb | |||
| af35396601 | |||
| 6a27594751 | |||
| 555d89d358 | |||
| c3c9dcf318 | |||
| 5a75772f62 | |||
| b9ac94f058 | |||
| 8ab1f4c408 | |||
| e842bfaab6 | |||
| 886cd63415 | |||
| 9cd22910d8 | |||
| 906e365adf | |||
| 8e7e897906 | |||
| 4b50ef93a2 | |||
| 73c2d76b58 | |||
| 473338527a | |||
| 12d1a0de32 | |||
| b4e0e89c38 | |||
| 6f5e535b30 | |||
| fb1062a98a | |||
| c56a5ae577 | |||
| a19cd9c97b | |||
| 0e1a090f16 | |||
| ef712443e1 | |||
| 248b708909 | |||
| c63c936b36 | |||
| 4927333691 | |||
| 5acc8f96a6 | |||
| 9d91740063 | |||
| 1951f206cb | |||
| 441feb8578 | |||
| 7d11f16988 | |||
| 2e3f52fdbf | |||
| b942a42271 | |||
| 0178594c25 | |||
| 3dbd617ed0 | |||
| 8188da16b3 | |||
| bc7b988098 | |||
| a0b3970ad6 | |||
| 0f20663cfb | |||
| 4dc98763a6 | |||
| 230be1d13b | |||
| 99493d86ff | |||
| 4ffb1fe422 | |||
| f4417ecb78 | |||
| 9b77130f6e | |||
| 71ea84c3ec | |||
| 36c138688d | |||
| 86afe1736f | |||
| 8e70e1113e | |||
| a379d11035 | |||
| 45a5c42ea4 | |||
| 99a55a6e24 | |||
| 6e404caa32 | |||
| 898048cb8b | |||
| 0794c2828e | |||
| 7be4ec6890 | |||
| 5669e8a76e | |||
| d4dc7ffe35 | |||
| b6080bc42b | |||
| 0dea465fb3 | |||
| 879225f7a8 | |||
| f8a7a75486 | |||
| fb0b188d4e | |||
| 376bc8b9c4 | |||
| da319a1aa9 | |||
| 2ab3db79e5 | |||
| 33e8d4f47e | |||
| 902e85e648 | |||
| afb28667c4 | |||
| 26feb34f8d | |||
| bdfdb67998 | |||
| 1c0400d3a5 | |||
| fa5b6b86c6 | |||
| 16f1b411ec | |||
| be66701b15 | |||
| 0a18a580eb | |||
| a0044c51be | |||
| 788d8334f7 | |||
| 7ecdd7ebe3 | |||
| dda01ff4a1 | |||
| 5d04de4ffa | |||
| f6e8db4c09 | |||
| 0f9ae05615 | |||
| bcba9e962e | |||
| 191f8a1e0f | |||
| 0d1aafcbbf | |||
| 9a194a86df | |||
| 668013cbad | |||
| d83f0b8559 | |||
| c198e8093b | |||
| 12a562284e | |||
| 54c1ff0587 | |||
| d9cf3851a1 | |||
| 9abdf39fd6 | |||
| d8e895970c | |||
| f7f399a5a5 | |||
| 3a1b9ce20b | |||
| 8d04e7adbe | |||
| 707ca54ef9 | |||
| ca93b8865a | |||
| 86dd4ede3a | |||
| 5b7b759131 | |||
| 2aa247b3c3 | |||
| ec126a5976 | |||
| c8814237cf | |||
| e98b6576f1 | |||
| c429b1d5ff | |||
| 09de0cf2f5 | |||
| a01d933218 | |||
| d8b7af424e | |||
| 798ed3a2dd | |||
| d3c9e0bbcd | |||
| b69947fc57 | |||
| e4553f27d1 | |||
| cf68a07b00 | |||
| c691fb779a | |||
| a93fccc234 | |||
| 4bea349b04 | |||
| ab41689a9b | |||
| 921e5111b5 | |||
| 21c7b1019e | |||
| d64a74b1be | |||
| 343a771c4f | |||
| 5e96516bf6 | |||
| 582b764679 | |||
| 56528ee68a | |||
| 8856a26869 | |||
| b2eb51c155 | |||
| a95d1bb672 | |||
| 5b572cd5fc | |||
| 8fce6fc8d4 | |||
| d2eabd1836 | |||
| 8c3f621e21 | |||
| 0275c8a5c4 | |||
| 0dd25d7140 | |||
| 079749b3e8 | |||
| c0fd0f410f | |||
| 58753f60d8 | |||
| 04f6117e36 | |||
| 7f4633a3d1 | |||
| d6c260b803 | |||
| 2dba6e644f | |||
| a7d2acb591 | |||
| 2b5a670bef | |||
| 16eff6bebb | |||
| c7c224b5f1 | |||
| 86a8f49e82 | |||
| 9a9e22fbce | |||
| d7d059767b | |||
| 3b38863b61 | |||
| c092e4c888 | |||
| 17a884f7e9 | |||
| 920d775965 | |||
| 7a3c598fb9 | |||
| 8b185cf48c | |||
| 0c7ec7c197 | |||
| 7b13473af8 | |||
| b586d988e6 | |||
| 16ac66c35f | |||
| ecf78a36ba | |||
| 39bb9f5240 | |||
| f76332ef71 | |||
| ed367fb1e5 | |||
| b04fb5cd97 | |||
| 5ea3cbd014 | |||
| cc9fc70d6d | |||
| 8aa5668a73 | |||
| bd9e0c9b5a | |||
| f79cce34fa | |||
| fc02c26a84 | |||
| c14bb6e18a | |||
| 62f4599140 | |||
| 56fa8aee84 | |||
| 6d7100b8ec | |||
| 602025b48b | |||
| 0e571d1905 | |||
| 757ad31f92 | |||
| 01f20a29d2 | |||
| 5fd1d9b431 | |||
| 6151be72ce | |||
| 299cee7771 | |||
| a01d2571de | |||
| 1c3ffba300 | |||
| ba9d65898f | |||
| 814f19390d | |||
| af8caa4cc8 | |||
| ff55a7625a | |||
| 8e5daf735d | |||
| f2006ae97a | |||
| efb392f77b | |||
| 739730efe5 | |||
| 05e72a5932 | |||
| a1e4b51d55 | |||
| 006a1fb0f4 | |||
| e14eee0ac5 | |||
| 49fd8448c0 | |||
| b79fdb1534 | |||
| 3931ecabdb | |||
| 7a3a55d399 | |||
| 340098cec3 | |||
| 12b41e3ab0 | |||
| ce570be40e | |||
| 5e77512009 | |||
| 321e38590c | |||
| 7ae2f7de00 | |||
| 056dd34f9b | |||
| 623b9910d5 | |||
| 6011cad546 | |||
| e56b86823e | |||
| 878860d249 | |||
| 3ff3469455 | |||
| cca5e27de7 | |||
| 7e1b53bf3e | |||
| ddb3f9ba6d | |||
| 3b675a7ab3 | |||
| f6b3938f96 | |||
| b0493e03af | |||
| 1ad754d933 | |||
| 001c8255eb | |||
| 1e4341a6ec | |||
| 2bee2efae5 | |||
| 065e764387 | |||
| e7032a6313 | |||
| b23a8c20eb | |||
| 5cc3c1b4fa | |||
| 88f7172fb4 | |||
| fd76a03257 | |||
| adf94adc7b | |||
| 98bc206169 | |||
| 17b5224090 | |||
| 56829c15d8 | |||
| df0f9068d6 | |||
| de05aa7f88 | |||
| 9997d0c77f | |||
| d4c8383266 | |||
| 986bc38a19 | |||
| f96876fe04 | |||
| a5bf63c2c6 | |||
| a4e4527b04 | |||
| 506f67f222 | |||
| 5c0a0237d7 | |||
| 2a86caeb3d | |||
| eaaba5beeb | |||
| 72c762f9cb | |||
| 972fa0b25b | |||
| da6e3e17a6 | |||
| db553d328a | |||
| 3fc7868759 | |||
| 62a3578e0d | |||
| 42f48b41ba | |||
| 7667eee725 | |||
| 597ad23ba1 | |||
| 838cfd59a6 | |||
| 984d67eaa1 | |||
| 6121c18088 | |||
| 392940cfa8 | |||
| 118d85f1e8 | |||
| 236b841182 | |||
| da17597121 | |||
| bd44d1e95a | |||
| 67ab52db90 | |||
| cff6e7f085 | |||
| 7c6bc9cd7e | |||
| 484de372ec | |||
| 07dbb86203 | |||
| 53cb10bb89 | |||
| e69730d9d6 | |||
| ef328369b8 | |||
| e5b2fa2ec7 | |||
| 97f8092868 | |||
| d2dbc4c44c | |||
| d77d005659 | |||
| 104c5b3da4 | |||
| 53e39a1dc6 | |||
| 3cb41fa6e7 | |||
| 88d583bfb1 | |||
| a8b12e4461 | |||
| bc6339bf52 | |||
| 15d8e94678 | |||
| 250070dc15 | |||
| f7ee4f103c | |||
| fbbe5ff767 | |||
| 5d755990b7 | |||
| fdea1a753e | |||
| d02d63d1eb | |||
| 153d230907 | |||
| 3a11b54394 | |||
| 6fd7e3de63 | |||
| 33407fad16 | |||
| a9169276e5 | |||
| df5d752c4b | |||
| cd73d36bdf | |||
| 2b2d8b8a5c | |||
| a052559983 | |||
| 8de72f88f4 | |||
| d89c199f3a | |||
| 378da932b5 | |||
| c89cb41c5b | |||
| ca0f7ca3e8 | |||
| 6abc52d074 | |||
| f12aacd1da | |||
| c32d40636d | |||
| 6b16535958 | |||
| 58ba597c62 | |||
| 8e552d0a96 | |||
| 4f73a52192 | |||
| 7486317363 | |||
| 7ac7b1f9c6 | |||
| 10c6140e3c | |||
| c50bf5bebf | |||
| 0e2ae5e5e1 | |||
| 1474da8b2e | |||
| e95d1bfbcf | |||
| f0d014eba2 | |||
| 9e6da193c8 | |||
| e8e17f5530 | |||
| 0d126c3be0 | |||
| d46c8d71a0 | |||
| 99b3e67918 | |||
| d6aa51bf24 | |||
| f288c77893 | |||
| f7d0513ad5 | |||
| 8c93dae2ba | |||
| 42802703d4 | |||
| e8e8a4bd8a | |||
| e8d77679e4 | |||
| 901ed73fc9 | |||
| b444046661 | |||
| cff356461d | |||
| adfb2f4143 | |||
| 4a24edc9ea | |||
| 48e4c12187 | |||
| 559e05f0f4 | |||
| 1e77579b33 | |||
| ed7f818514 | |||
| 8b732db931 | |||
| 922de4abaa | |||
| c401324667 | |||
| fed25100d4 | |||
| 51d2c37458 | |||
| 9630595333 | |||
| 178aa46ad4 | |||
| 10bc218dee | |||
| 243ccade0b | |||
| e29b54c54d | |||
| 3b937c284c | |||
| 5b2c1bab8e | |||
| ba556e1e0d | |||
| 8d4e752274 | |||
| b20b45023d | |||
| f42f45e305 | |||
| aa5a2bffe8 | |||
| 73138d83bd | |||
| 92e84c05ce | |||
| eb49015dce | |||
| d9f3bca478 | |||
| c039b0a45d | |||
| ccf4ab934f | |||
| 317a7e4ac4 | |||
| 41ff500ccf | |||
| c5fb31fbe5 | |||
| 54a134e72f | |||
| 8b9ec40abc | |||
| 6d305286df | |||
| e8d69e67be | |||
| 31342746a0 | |||
| b11cf10622 | |||
| cacec3adaa | |||
| cd945419c4 | |||
| 3a02788e3a | |||
| a5059a7946 | |||
| a596afb498 | |||
| 87c390da4c | |||
| ef8631bd1f | |||
| e271d0ff29 | |||
| 233bbf9861 | |||
| 0019f71b46 | |||
| 077882f672 | |||
| db7a9ce0ac | |||
| 50de747792 | |||
| f88e11bdb2 | |||
| ca8ed3b006 | |||
| 0a1ac0183c | |||
| 52c0f26c08 | |||
| ea42694dc8 | |||
| 225b10e866 | |||
| eb881690c7 | |||
| eb513e19df | |||
| f305f40acb | |||
| a457601d77 | |||
| 61eca8a371 | |||
| e5765c6a9b | |||
| 957fd786f8 | |||
| e66eaae328 | |||
| f40ef0b0a3 | |||
| 858045bb18 | |||
| 95c174c094 | |||
| 4552b7c7ab | |||
| d454db70e8 | |||
| db0183b5b3 | |||
| b45ee62e3d | |||
| 5f0235ce67 | |||
| 9f1aa4aef9 | |||
| 85bcb4e70c | |||
| b9cf48d9c8 | |||
| e611165fc8 | |||
| 67aee00dc4 | |||
| c32b802a07 | |||
| 2098c85287 | |||
| 2bc851c38b | |||
| fdaecf54e5 | |||
| 1ce5952d1a | |||
| 44e9c4e819 | |||
| 16820d1da2 | |||
| 8fb2b052e4 | |||
| a8e25b16ec | |||
| 48c4a7e7d4 | |||
| 529d81739c | |||
| 81c1ccf2ed | |||
| b992f45bdd | |||
| 092e679103 | |||
| 2eccae8097 | |||
| 6d9f08622b | |||
| cb186979d5 | |||
| 6c95a0505a | |||
| 81d56b5cb9 | |||
| fa3c084d86 | |||
| c077a03d54 | |||
| f5cc255caa | |||
| 871998c529 | |||
| 612f0a82a7 | |||
| c156aed68d | |||
| 8015b40980 | |||
| a97155d8fb | |||
| d23e005618 | |||
| 3ae864d39e | |||
| 4697ad4415 | |||
| 7aef267fdd | |||
| e3f5f6e720 | |||
| 6a41ea10a3 | |||
| 03065369a7 | |||
| 38386a3d96 | |||
| 06cb004a9b | |||
| dcc8a831f9 | |||
| b97b1398f7 | |||
| c3e7159cb7 | |||
| 0e3dbf6e38 | |||
| c398908d50 | |||
| c4c037f839 | |||
| 66fe5f1483 | |||
| 8440affe5f | |||
| 6c54214732 | |||
| 78cd5a88bd | |||
| 5faf15723d | |||
| 395a97b0fc | |||
| df698e9560 | |||
| 862cdc8aa7 | |||
| f50cc5b80d | |||
| 5412bddfcf | |||
| ffba4ebb8e | |||
| 468362aac4 | |||
| 04c3594627 | |||
| b49a2cd012 | |||
| c0b9017679 | |||
| e315d05355 | |||
| 573fefc86d | |||
| ccb4827c52 | |||
| b8a1fe1af6 | |||
| 083e655bde | |||
| 8596b73375 | |||
| c518c0bcd6 | |||
| 13024417ca | |||
| e86eda5f54 | |||
| 9d982c466b | |||
| a82413c32a | |||
| e48a52c023 | |||
| d9cd733c90 | |||
| 4e2ae73fb0 | |||
| 86d896dd44 | |||
| 6d11c54874 | |||
| 1a817f6684 | |||
| ee3716623c | |||
| 2fe2f850c2 | |||
| 0794363a3c | |||
| b0e37dacf4 | |||
| 1893107b07 | |||
| 50b374bd3e | |||
| be9bc22df4 | |||
| d19a2e4337 | |||
| 288f94de35 | |||
| 709b670819 | |||
| 9cfa7134b0 | |||
| 4d6f523260 | |||
| be69946036 | |||
| fdb8aa216e | |||
| 4ae799ec39 | |||
| 6ea6d6756b | |||
| 3c33961395 | |||
| 94053f37ee | |||
| 424aa7cf80 | |||
| ef1322be57 | |||
| 95badeee62 | |||
| d9bd5a465b | |||
| 8ac4f0122b | |||
| b49a5ca04f | |||
| fdc9450f8c | |||
| 3528163175 | |||
| c47bfb4fcd | |||
| 3355332ebd | |||
| 27f5fb8688 | |||
| 6cabc23dad | |||
| 487dcc643c | |||
| 75a66a4f9b | |||
| ce02e30587 | |||
| 20f8c084c1 | |||
| 222c8a8252 | |||
| 052128a395 | |||
| cb00f3a5db | |||
| 7c7d0265d1 | |||
| 2b7ec78797 | |||
| b795213649 | |||
| 36a7e81f1b | |||
| 931583693d | |||
| 3e23807623 | |||
| 31d0e8c452 | |||
| 42be65a3d2 | |||
| e9172f7e5f | |||
| 5dada0d584 | |||
| b212d8afbb | |||
| 7ed7c66015 | |||
| dba14f8c74 | |||
| d62982b4b6 | |||
| 3e70fedb14 | |||
| cbb97c1d2e | |||
| 3bd5984480 | |||
| 894a4ab118 | |||
| 5b32305f43 | |||
| 965dd986f2 | |||
| 8eb8ed873c | |||
| 4d18c8b21d | |||
| 75db28c522 | |||
| 551d5cf4ca | |||
| 3e63dfb696 | |||
| c164253474 | |||
| 7746b65f9a | |||
| bb77ef8e4d | |||
| afe0f2d449 | |||
| e343b1d38c | |||
| 19c1261e81 | |||
| 2040d2b34a | |||
| d7d5911b93 | |||
| 8915b73953 | |||
| 07635ad828 | |||
| 3aa674fca0 | |||
| cf832af14b | |||
| 49028e2950 | |||
| 539be0f011 | |||
| 66c737a22d | |||
| 24b5ea14b1 | |||
| 3cfcf14a50 | |||
| 28b4087b69 | |||
| 1ca5b87db4 | |||
| 469466d3c9 | |||
| 9474830136 | |||
| 54e322ee3e | |||
| 853dab3f5c | |||
| f334ee2606 | |||
| f6477ed868 | |||
| 4935ae867d | |||
| 2246d790a4 | |||
| 1f9f8f5e30 | |||
| c10c453eac | |||
| 3d0678725e | |||
| cdf18dc972 | |||
| 76788d3ae2 | |||
| 658003080e | |||
| e803f36f78 | |||
| 9742d5bf07 | |||
| 3fe9b5273c | |||
| 3b1b038b51 | |||
| b27d924d82 | |||
| 24b3b485b7 | |||
| 467c22fcd3 | |||
| 1571119e0f | |||
| 634e68de5a | |||
| ab77d93950 | |||
| ddb90a046a | |||
| 33704abc0c | |||
| 5c62e339c1 | |||
| 9b188b4520 | |||
| 36944c1941 | |||
| 987c853448 | |||
| 8b930e81e9 | |||
| eb6b201a2a | |||
| a39d46238b | |||
| 65941368b8 | |||
| ed4824d959 | |||
| 9e0be76911 | |||
| 70c3d65863 | |||
| f733147517 | |||
| ec7b4b45ec | |||
| 7a2f71a6c1 | |||
| 22a3c2962d | |||
| 364749f281 | |||
| fbec74bd94 | |||
| 3bf59689fb | |||
| cd1c88b4d4 | |||
| 0affd8b619 | |||
| 163ccbbe59 | |||
| 42d433a92f | |||
| 2be34c42f4 | |||
| 0f05c10a38 | |||
| adb03b4ed8 | |||
| eb905267ab | |||
| 9ed0fe0b19 | |||
| d716f3d02a | |||
| 7207512dca | |||
| 5d0cb70df8 | |||
| 0ed79371a4 | |||
| ab4206cc93 | |||
| 4c206ec375 | |||
| 21c5813a96 | |||
| a9e5897f4e | |||
| e77d4eafc5 | |||
| 3564f19158 |
@@ -0,0 +1,15 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# CoAP is temporarily ignored since we don't have tests for it yet.
|
||||
coverage:
|
||||
ignore:
|
||||
- "tools/*"
|
||||
- "api/grpc/**"
|
||||
- "cmd/*"
|
||||
- "coap/**"
|
||||
- "**/mocks/*"
|
||||
- "*/middleware/*"
|
||||
- "pkg/sid/mock.go"
|
||||
- "pkg/tracing/utils.go"
|
||||
- "pkg/prometheus/*"
|
||||
+1
-1
@@ -1 +1 @@
|
||||
* @absmach/magistrala
|
||||
* @absmach/supermq
|
||||
|
||||
@@ -5,7 +5,7 @@ blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Google group
|
||||
url: https://groups.google.com/forum/#!forum/mainflux
|
||||
about: Join the Mainflux community on Google group.
|
||||
about: Join the SuperMQ community on Google group.
|
||||
- name: Gitter
|
||||
url: https://gitter.im/mainflux/mainflux
|
||||
about: Join the Mainflux community on Gitter.
|
||||
about: Join the SuperMQ community on Gitter.
|
||||
@@ -3,8 +3,8 @@ SPDX-License-Identifier: Apache-2.0 -->
|
||||
|
||||
<!--
|
||||
|
||||
Pull request title should be `MG-XXX - description` or `NOISSUE - description` where XXX is ID of the issue that this PR relate to.
|
||||
Please review the [CONTRIBUTING.md](https://github.com/absmach/magistrala/blob/master/CONTRIBUTING.md) file for detailed contributing guidelines.
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "./.github/workflows"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
day: "monday"
|
||||
timezone: "Europe/Paris"
|
||||
groups:
|
||||
gh-dependency:
|
||||
patterns:
|
||||
- "*"
|
||||
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "monday"
|
||||
timezone: "Europe/Paris"
|
||||
|
||||
- package-ecosystem: "docker"
|
||||
directory: "./docker"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
day: "monday"
|
||||
timezone: "Europe/Paris"
|
||||
groups:
|
||||
docker-dependency:
|
||||
patterns:
|
||||
- "*"
|
||||
@@ -1,19 +0,0 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "docker"
|
||||
directory: "./docker"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
@@ -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>SuperMQ 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>SuperMQ 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>
|
||||
@@ -0,0 +1,219 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
name: Property Based Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- ".github/workflows/api-tests.yaml"
|
||||
- "api/**"
|
||||
- "auth/api/http/**"
|
||||
- "channels/api/http/**"
|
||||
- "clients/api/http/**"
|
||||
- "domains/api/http/**"
|
||||
- "groups/api/http/**"
|
||||
- "http/api/**"
|
||||
- "journal/api/**"
|
||||
- "users/api/**"
|
||||
- "apidocs/openapi/**"
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- ".github/workflows/api-tests.yaml"
|
||||
- "api/**"
|
||||
- "auth/api/http/**"
|
||||
- "channels/api/http/**"
|
||||
- "clients/api/http/**"
|
||||
- "domains/api/http/**"
|
||||
- "groups/api/http/**"
|
||||
- "http/api/**"
|
||||
- "journal/api/**"
|
||||
- "users/api/**"
|
||||
- "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
|
||||
USER_SECRET: 12345678
|
||||
DOMAIN_NAME: demo-test
|
||||
USERS_URL: http://localhost:9002
|
||||
DOMAIN_URL: http://localhost:9003
|
||||
CLIENTS_URL: http://localhost:9006
|
||||
CHANNELS_URL: http://localhost:9005
|
||||
GROUPS_URL: http://localhost:9004
|
||||
HTTP_ADAPTER_URL: http://localhost:8008
|
||||
AUTH_URL: http://localhost:9001
|
||||
JOURNAL_URL: http://localhost:9021
|
||||
|
||||
jobs:
|
||||
api-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get Go version from go.mod
|
||||
id: go-version
|
||||
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ steps.go-version.outputs.version }}
|
||||
cache-dependency-path: "go.sum"
|
||||
|
||||
- name: Check for changes in specific paths
|
||||
uses: dorny/paths-filter@v3
|
||||
id: changes
|
||||
with:
|
||||
filters: |
|
||||
workflow:
|
||||
- ".github/workflows/api-tests.yaml"
|
||||
|
||||
journal:
|
||||
- "apidocs/openapi/journal.yaml"
|
||||
- "journal/api/**"
|
||||
|
||||
auth:
|
||||
- "apidocs/openapi/auth.yaml"
|
||||
- "auth/api/http/**"
|
||||
|
||||
domains:
|
||||
- "apidocs/openapi/domains.yaml"
|
||||
- "domains/api/http/**"
|
||||
|
||||
http:
|
||||
- "apidocs/openapi/http.yaml"
|
||||
- "http/api/**"
|
||||
|
||||
clients:
|
||||
- "apidocs/openapi/clients.yaml"
|
||||
- "clients/api/http/**"
|
||||
|
||||
channels:
|
||||
- "apidocs/openapi/channels.yaml"
|
||||
- "channels/api/http/**"
|
||||
|
||||
groups:
|
||||
- "apidocs/openapi/groups.yaml"
|
||||
- "groups/api/http/**"
|
||||
|
||||
users:
|
||||
- "apidocs/openapi/users.yaml"
|
||||
- "users/api/**"
|
||||
|
||||
- name: Build images
|
||||
run: make all -j $(nproc) && make dockers_dev -j $(nproc)
|
||||
|
||||
- name: Start containers
|
||||
run: make run_latest 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:9002/health > /dev/null 2>&1; then
|
||||
echo "Services are ready!"
|
||||
break
|
||||
fi
|
||||
echo "Waiting for services... ($i/30)"
|
||||
sleep 2
|
||||
done
|
||||
|
||||
- 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)
|
||||
echo "USER_TOKEN=$USER_TOKEN" >> $GITHUB_ENV
|
||||
export CLIENT_SECRET=$(supermq-cli provision test | /usr/bin/grep -Eo '"secret": "[^"]+"' | awk 'NR % 2 == 0' | sed 's/"secret": "\(.*\)"/\1/')
|
||||
echo "CLIENT_SECRET=$CLIENT_SECRET" >> $GITHUB_ENV
|
||||
|
||||
- name: Run Users API tests
|
||||
if: steps.changes.outputs.users == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
uses: schemathesis/action@v2.1.0
|
||||
with:
|
||||
schema: apidocs/openapi/users.yaml
|
||||
base-url: ${{ env.USERS_URL }}
|
||||
checks: all
|
||||
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --exclude-operation-id=requestPasswordReset --phases=examples'
|
||||
|
||||
- name: Run Groups API tests
|
||||
if: steps.changes.outputs.groups == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
uses: schemathesis/action@v2.1.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'
|
||||
|
||||
- name: Run Clients API tests
|
||||
if: steps.changes.outputs.clients == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
uses: schemathesis/action@v2.1.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'
|
||||
|
||||
- name: Run Channels API tests
|
||||
if: steps.changes.outputs.channels == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
uses: schemathesis/action@v2.1.0
|
||||
with:
|
||||
schema: apidocs/openapi/channels.yaml
|
||||
base-url: ${{ env.CHANNELS_URL }}
|
||||
checks: all
|
||||
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --phases=examples'
|
||||
|
||||
- name: Run HTTP Adapter API tests
|
||||
if: steps.changes.outputs.http == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
uses: schemathesis/action@v2.1.0
|
||||
with:
|
||||
schema: apidocs/openapi/http.yaml
|
||||
base-url: ${{ env.HTTP_ADAPTER_URL }}
|
||||
checks: all
|
||||
args: '--header "Authorization: Client ${{ env.CLIENT_SECRET }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --phases=examples'
|
||||
|
||||
- name: Run Auth API tests
|
||||
if: steps.changes.outputs.auth == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
uses: schemathesis/action@v2.1.0
|
||||
with:
|
||||
schema: apidocs/openapi/auth.yaml
|
||||
base-url: ${{ env.AUTH_URL }}
|
||||
checks: all
|
||||
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --phases=examples'
|
||||
|
||||
- name: Run Domains API tests
|
||||
if: steps.changes.outputs.domains == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
uses: schemathesis/action@v2.1.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'
|
||||
|
||||
- name: Run Journal API tests
|
||||
if: steps.changes.outputs.journal == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
uses: schemathesis/action@v2.1.0
|
||||
with:
|
||||
schema: apidocs/openapi/journal.yaml
|
||||
base-url: ${{ env.JOURNAL_URL }}
|
||||
checks: all
|
||||
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --phases=examples'
|
||||
|
||||
- name: Stop containers
|
||||
if: always()
|
||||
run: make run_latest down args="-v" && make run_addons down args="-v"
|
||||
@@ -0,0 +1,63 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
name: Continuous Delivery
|
||||
|
||||
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 Docker Images
|
||||
runs-on: ubuntu-latest
|
||||
needs: [lint-and-build]
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
|
||||
- name: Get Go version from go.mod
|
||||
id: go-version
|
||||
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ steps.go-version.outputs.version }}
|
||||
cache-dependency-path: "go.sum"
|
||||
|
||||
- name: Set up Docker Build
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: docker.io
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Build and push Docker images
|
||||
run: |
|
||||
make latest -j $(nproc)
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
name: Continuous Delivery
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
name: Build and Push
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
cache-dependency-path: "go.sum"
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
make test
|
||||
|
||||
- name: Upload coverage
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
token: ${{ secrets.CODECOV }}
|
||||
directory: ./coverage/
|
||||
name: codecov-umbrella
|
||||
verbose: true
|
||||
|
||||
- name: Set up Docker Build
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: docker.io
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Compile check for rabbitmq
|
||||
run: |
|
||||
MG_MESSAGE_BROKER_TYPE=rabbitmq make mqtt
|
||||
|
||||
- name: Compile check for redis
|
||||
run: |
|
||||
MG_ES_TYPE=redis make mqtt
|
||||
|
||||
- name: Build and push Dockers
|
||||
run: |
|
||||
make latest -j $(nproc)
|
||||
@@ -0,0 +1,132 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
name: Check the consistency of generated files
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
check-generated-files:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
PROTOC_VERSION: "33.0"
|
||||
PROTOC_GEN_GO_VERSION: "v1.36.11"
|
||||
PROTOC_GEN_GO_GRPC_VERSION: "v1.6.0"
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Get Go version from go.mod
|
||||
id: go-version
|
||||
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ steps.go-version.outputs.version }}
|
||||
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
|
||||
id: changes
|
||||
with:
|
||||
base: main
|
||||
filters: |
|
||||
proto:
|
||||
- ".github/workflows/check-generated-files.yaml"
|
||||
- "auth.proto"
|
||||
- "auth/*.pb.go"
|
||||
- "pkg/messaging/message.proto"
|
||||
- "pkg/messaging/*.pb.go"
|
||||
|
||||
mocks:
|
||||
- ".github/workflows/check-generated-files.yaml"
|
||||
- "pkg/sdk/sdk.go"
|
||||
- "users/postgres/clients.go"
|
||||
- "users/clients.go"
|
||||
- "pkg/clients/clients.go"
|
||||
- "pkg/messaging/pubsub.go"
|
||||
- "clients/postgres/clients.go"
|
||||
- "clients/clients.go"
|
||||
- "pkg/authz.go"
|
||||
- "pkg/authn.go"
|
||||
- "auth/domains.go"
|
||||
- "auth/keys.go"
|
||||
- "auth/service.go"
|
||||
- "pkg/events/events.go"
|
||||
- "pkg/groups/groups.go"
|
||||
- "users/emailer.go"
|
||||
- "users/hasher.go"
|
||||
- "journal/journal.go"
|
||||
- "consumers/notifier.go"
|
||||
|
||||
- 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: |
|
||||
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'
|
||||
run: |
|
||||
for p in $(find . -name "*.pb.go"); do
|
||||
mv $p $p.tmp
|
||||
done
|
||||
|
||||
make proto
|
||||
|
||||
for p in $(find . -name "*.pb.go"); do
|
||||
if ! cmp -s $p $p.tmp; then
|
||||
echo "Error: Proto file and generated Go file $p are out of sync!"
|
||||
echo "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_GO_VERSION and protoc-gen-go-grpc version $PROTOC_GEN_GO_GRPC_VERSION and commit the changes."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Check Mocks are up to Date
|
||||
if: steps.changes.outputs.mocks == 'true'
|
||||
run: |
|
||||
for f in $(find . -type f -path '*/mocks/*.go' ! -name 'doc.go'); do
|
||||
mv $f $f.tmp
|
||||
done
|
||||
|
||||
make mocks
|
||||
|
||||
check_mock_changes() {
|
||||
local file_path=$1
|
||||
local tmp_file_path=$1.tmp
|
||||
local entity_name=$2
|
||||
|
||||
if ! cmp -s "$file_path" "$tmp_file_path"; then
|
||||
echo "Error: Generated mocks for $entity_name are out of sync!"
|
||||
echo "Please run 'make mocks' with mockery version $MOCKERY_VERSION and commit the changes."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
for f in $(find . -type f -path '*/mocks/*.go' ! -name 'doc.go'); do
|
||||
check_mock_changes $f "$f"
|
||||
done
|
||||
@@ -1,150 +0,0 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
name: Check the consistency of generated files
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
check-generated-files:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
cache-dependency-path: "go.sum"
|
||||
|
||||
- name: Check for changes in specific paths
|
||||
uses: dorny/paths-filter@v2
|
||||
id: changes
|
||||
with:
|
||||
base: main
|
||||
filters: |
|
||||
proto:
|
||||
- ".github/workflows/check-generated-files.yml"
|
||||
- "auth.proto"
|
||||
- "auth/*.pb.go"
|
||||
- "pkg/messaging/message.proto"
|
||||
- "pkg/messaging/*.pb.go"
|
||||
|
||||
mocks:
|
||||
- ".github/workflows/check-generated-files.yml"
|
||||
- "pkg/sdk/go/sdk.go"
|
||||
- "users/postgres/clients.go"
|
||||
- "users/clients.go"
|
||||
- "pkg/clients/clients.go"
|
||||
- "pkg/messaging/pubsub.go"
|
||||
- "things/postgres/clients.go"
|
||||
- "things/things.go"
|
||||
- "auth/domains.go"
|
||||
- "auth/keys.go"
|
||||
- "auth/policies.go"
|
||||
- "auth/service.go"
|
||||
- "pkg/events/events.go"
|
||||
- "provision/service.go"
|
||||
- "pkg/groups/groups.go"
|
||||
|
||||
- name: Set up protoc
|
||||
if: steps.changes.outputs.proto == 'true'
|
||||
run: |
|
||||
PROTOC_VERSION=25.1
|
||||
PROTOC_GEN_VERSION=v1.31.0
|
||||
PROTOC_GRPC_VERSION=v1.3.0
|
||||
|
||||
# Download and install protoc
|
||||
PROTOC_ZIP=protoc-$PROTOC_VERSION-linux-x86_64.zip
|
||||
curl -0L -o $PROTOC_ZIP https://github.com/protocolbuffers/protobuf/releases/download/v$PROTOC_VERSION/$PROTOC_ZIP
|
||||
unzip -o $PROTOC_ZIP -d protoc3
|
||||
sudo mv protoc3/bin/* /usr/local/bin/
|
||||
sudo mv protoc3/include/* /usr/local/include/
|
||||
rm -rf $PROTOC_ZIP protoc3
|
||||
|
||||
# Install protoc-gen-go and protoc-gen-go-grpc
|
||||
go install google.golang.org/protobuf/cmd/protoc-gen-go@$PROTOC_GEN_VERSION
|
||||
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@$PROTOC_GRPC_VERSION
|
||||
|
||||
# Add protoc to the PATH
|
||||
export PATH=$PATH:/usr/local/bin/protoc
|
||||
|
||||
- name: Check Protobuf is up to Date
|
||||
if: steps.changes.outputs.proto == 'true'
|
||||
run: |
|
||||
for p in $(find . -name "*.pb.go"); do
|
||||
mv $p $p.tmp
|
||||
done
|
||||
|
||||
make proto
|
||||
|
||||
for p in $(find . -name "*.pb.go"); do
|
||||
if ! cmp -s $p $p.tmp; then
|
||||
echo "Error: Proto file and generated Go file $p are out of sync!"
|
||||
echo "Please run 'make proto' with protoc version $PROTOC_VERSION, protoc-gen-go version $PROTOC_GEN_VERSION and protoc-gen-go-grpc version $PROTOC_GRPC_VERSION and commit the changes."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Check Mocks are up to Date
|
||||
if: steps.changes.outputs.mocks == 'true'
|
||||
run: |
|
||||
MOCKERY_VERSION=v2.38.0
|
||||
go install github.com/vektra/mockery/v2@$MOCKERY_VERSION
|
||||
|
||||
mv ./pkg/sdk/mocks/sdk.go ./pkg/sdk/mocks/sdk.go.tmp
|
||||
mv ./users/mocks/repository.go ./users/mocks/repository.go.tmp
|
||||
mv ./users/mocks/service.go ./users/mocks/service.go.tmp
|
||||
mv ./pkg/messaging/mocks/pubsub.go ./pkg/messaging/mocks/pubsub.go.tmp
|
||||
mv ./things/mocks/repository.go ./things/mocks/repository.go.tmp
|
||||
mv ./things/mocks/service.go ./things/mocks/service.go.tmp
|
||||
mv ./things/mocks/cache.go ./things/mocks/cache.go.tmp
|
||||
mv ./auth/mocks/agent.go ./auth/mocks/agent.go.tmp
|
||||
mv ./auth/mocks/authz.go ./auth/mocks/authz.go.tmp
|
||||
mv ./auth/mocks/domains.go ./auth/mocks/domains.go.tmp
|
||||
mv ./auth/mocks/keys.go ./auth/mocks/keys.go.tmp
|
||||
mv ./auth/mocks/service.go ./auth/mocks/service.go.tmp
|
||||
mv ./pkg/events/mocks/publisher.go ./pkg/events/mocks/publisher.go.tmp
|
||||
mv ./pkg/events/mocks/subscriber.go ./pkg/events/mocks/subscriber.go.tmp
|
||||
mv ./provision/mocks/service.go ./provision/mocks/service.go.tmp
|
||||
mv ./pkg/groups/mocks/repository.go ./pkg/groups/mocks/repository.go.tmp
|
||||
mv ./pkg/groups/mocks/service.go ./pkg/groups/mocks/service.go.tmp
|
||||
|
||||
make mocks
|
||||
|
||||
check_mock_changes() {
|
||||
local file_path=$1
|
||||
local tmp_file_path=$1.tmp
|
||||
local entity_name=$2
|
||||
|
||||
if ! cmp -s "$file_path" "$tmp_file_path"; then
|
||||
echo "Error: Generated mocks for $entity_name are out of sync!"
|
||||
echo "Please run 'make mocks' with mockery version $MOCKERY_VERSION and commit the changes."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_mock_changes ./pkg/sdk/mocks/sdk.go "SDK ./pkg/sdk/mocks/sdk.go"
|
||||
check_mock_changes ./users/mocks/repository.go "Users Repository ./users/mocks/repository.go"
|
||||
check_mock_changes ./users/mocks/service.go "Users Service ./users/mocks/service.go"
|
||||
check_mock_changes ./pkg/messaging/mocks/pubsub.go "PubSub ./pkg/messaging/mocks/pubsub.go"
|
||||
check_mock_changes ./things/mocks/repository.go "Things Repository ./things/mocks/repository.go"
|
||||
check_mock_changes ./things/mocks/service.go "Things Service ./things/mocks/service.go"
|
||||
check_mock_changes ./things/mocks/cache.go "Things Cache ./things/mocks/cache.go"
|
||||
check_mock_changes ./auth/mocks/agent.go "Auth Agent ./auth/mocks/agent.go"
|
||||
check_mock_changes ./auth/mocks/authz.go "Auth Authz ./auth/mocks/authz.go"
|
||||
check_mock_changes ./auth/mocks/domains.go "Auth Domains ./auth/mocks/domains.go"
|
||||
check_mock_changes ./auth/mocks/keys.go "Auth Keys ./auth/mocks/keys.go"
|
||||
check_mock_changes ./auth/mocks/service.go "Auth Service ./auth/mocks/service.go"
|
||||
check_mock_changes ./pkg/events/mocks/publisher.go "ES Publisher ./pkg/events/mocks/publisher.go"
|
||||
check_mock_changes ./pkg/events/mocks/subscriber.go "EE Subscriber ./pkg/events/mocks/subscriber.go"
|
||||
check_mock_changes ./provision/mocks/service.go "Provision Service ./provision/mocks/service.go"
|
||||
check_mock_changes ./pkg/groups/mocks/repository.go "Groups Repository ./pkg/groups/mocks/repository.go"
|
||||
check_mock_changes ./pkg/groups/mocks/service.go "Groups Service ./pkg/groups/mocks/service.go"
|
||||
@@ -4,9 +4,6 @@
|
||||
name: Check License Header
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
@@ -16,16 +13,25 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Check License Header
|
||||
run: |
|
||||
CHECK=$(grep -rcL --exclude-dir={.git,build,**vernemq**} \
|
||||
CHECK=""
|
||||
for file in $(grep -rl --exclude-dir={.git,build} \
|
||||
--exclude=\*.{crt,key,pem,zed,hcl,md,json,csv,mod,sum,tmpl,args} \
|
||||
--exclude={CODEOWNERS,LICENSE,MAINTAINERS} \
|
||||
--regexp "Copyright (c) Abstract Machines" .)
|
||||
--exclude={CODEOWNERS,LICENSE,MAINTAINERS,enabled_plugins,rabbitmq.conf} \
|
||||
.); do
|
||||
|
||||
if ! head -n 5 "$file" | grep -q "Copyright (c) Abstract Machines"; then
|
||||
CHECK="$CHECK $file"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$CHECK" ]; then
|
||||
echo "License header check failed. Fix the following files:"
|
||||
echo "$CHECK"
|
||||
exit 1
|
||||
else
|
||||
echo "All files have the correct license header!"
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
# 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@v6
|
||||
|
||||
- name: Get Go version from go.mod
|
||||
id: go-version
|
||||
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ steps.go-version.outputs.version }}
|
||||
cache-dependency-path: "go.sum"
|
||||
|
||||
- name: Run linters
|
||||
uses: golangci/golangci-lint-action@v9.2.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@v6
|
||||
|
||||
- name: Get Go version from go.mod
|
||||
id: go-version
|
||||
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ steps.go-version.outputs.version }}
|
||||
cache-dependency-path: "go.sum"
|
||||
|
||||
- name: Build all binaries
|
||||
run: |
|
||||
make all -j $(nproc)
|
||||
|
||||
compile-check:
|
||||
name: Compile Check ${{ matrix.variant.name }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: lint
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
variant:
|
||||
- name: rabbitmq
|
||||
env: SMQ_MESSAGE_BROKER_TYPE=msg_rabbitmq
|
||||
target: mqtt
|
||||
- name: redis
|
||||
env: SMQ_ES_TYPE=es_redis
|
||||
target: mqtt
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Get Go version from go.mod
|
||||
id: go-version
|
||||
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ steps.go-version.outputs.version }}
|
||||
cache-dependency-path: "go.sum"
|
||||
|
||||
- name: Compile check for ${{ matrix.variant.name }}
|
||||
run: |
|
||||
${{ matrix.variant.env }} make ${{ matrix.variant.target }}
|
||||
@@ -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@v6
|
||||
|
||||
- name: Swagger UI action
|
||||
id: swagger-ui-action
|
||||
uses: blokovi/swagger-ui-action@main
|
||||
with:
|
||||
dir: "./api/openapi"
|
||||
pattern: "*.yml"
|
||||
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@v3
|
||||
uses: peaceiris/actions-gh-pages@v4
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: swagger-ui
|
||||
cname: api.mainflux.io
|
||||
publish_dir: ./swagger-ui
|
||||
cname: docs.api.supermq.absmach.eu
|
||||
|
||||
@@ -0,0 +1,379 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
name: CI Pipeline
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- 'docs/**'
|
||||
- 'LICENSE'
|
||||
- 'MAINTAINERS'
|
||||
- 'CODEOWNERS'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
check-certs:
|
||||
name: Check Certs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Fetch Certs
|
||||
run: |
|
||||
make fetch_certs
|
||||
if [[ -n $(git status --porcelain docker/addons/certs) ]]; then
|
||||
echo "Certs docker file is not up to date. Please update it"
|
||||
git diff docker/addons/certs
|
||||
exit 1
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
|
||||
lint-proto:
|
||||
name: Lint Proto
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Get Go version from go.mod
|
||||
id: go-version
|
||||
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ steps.go-version.outputs.version }}
|
||||
cache-dependency-path: "go.sum"
|
||||
|
||||
- name: Install protolint
|
||||
run: |
|
||||
go install github.com/yoheimuta/protolint/cmd/protolint@latest
|
||||
|
||||
- name: Lint Protobuf Files
|
||||
run: |
|
||||
protolint .
|
||||
|
||||
lint-and-build:
|
||||
needs: [check-certs, lint-proto]
|
||||
uses: ./.github/workflows/lint-and-build.yaml
|
||||
|
||||
|
||||
|
||||
detect-changes:
|
||||
name: Detect Changes
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
modules: ${{ steps.set-matrix.outputs.modules }}
|
||||
workflow_changed: ${{ steps.changes.outputs.workflow }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Check for changes in specific paths
|
||||
uses: dorny/paths-filter@v3
|
||||
id: changes
|
||||
with:
|
||||
filters: |
|
||||
workflow:
|
||||
- ".github/workflows/tests.yaml"
|
||||
|
||||
auth:
|
||||
- "auth/**"
|
||||
- "cmd/auth/**"
|
||||
- "auth.proto"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "pkg/ulid/**"
|
||||
- "pkg/uuid/**"
|
||||
|
||||
channels:
|
||||
- "channels/**"
|
||||
- "cmd/channels/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "auth/**"
|
||||
- "pkg/sdk/**"
|
||||
- "clients/api/grpc/**"
|
||||
- "groups/api/grpc/**"
|
||||
- "domains/api/grpc/**"
|
||||
- "internal/grpc/**"
|
||||
|
||||
cli:
|
||||
- "cli/**"
|
||||
- "cmd/cli/**"
|
||||
- "pkg/sdk/**"
|
||||
|
||||
clients:
|
||||
- "clients/**"
|
||||
- "cmd/clients/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "auth/**"
|
||||
- "pkg/ulid/**"
|
||||
- "pkg/uuid/**"
|
||||
- "pkg/events/**"
|
||||
- "groups/api/grpc/**"
|
||||
- "channels/api/grpc/**"
|
||||
- "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/**"
|
||||
- "channels/api/grpc/**"
|
||||
- "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-errors:
|
||||
- "pkg/errors/**"
|
||||
|
||||
pkg-events:
|
||||
- "pkg/events/**"
|
||||
- "pkg/messaging/**"
|
||||
|
||||
pkg-grpcclient:
|
||||
- "pkg/grpcclient/**"
|
||||
|
||||
pkg-messaging:
|
||||
- "pkg/messaging/**"
|
||||
|
||||
pkg-sdk:
|
||||
- "pkg/sdk/**"
|
||||
- "pkg/errors/**"
|
||||
- "pkg/groups/**"
|
||||
- "auth/**"
|
||||
- "http/**"
|
||||
- "internal/*"
|
||||
- "clients/**"
|
||||
- "users/**"
|
||||
- "channels/**"
|
||||
- "domains/**"
|
||||
- "groups/**"
|
||||
- "journal/**"
|
||||
- "api/http/**"
|
||||
|
||||
pkg-transformers:
|
||||
- "pkg/transformers/**"
|
||||
|
||||
pkg-ulid:
|
||||
- "pkg/ulid/**"
|
||||
|
||||
pkg-uuid:
|
||||
- "pkg/uuid/**"
|
||||
|
||||
users:
|
||||
- "users/**"
|
||||
- "cmd/users/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "auth/**"
|
||||
- "pkg/ulid/**"
|
||||
- "pkg/uuid/**"
|
||||
- "pkg/events/**"
|
||||
|
||||
notifications:
|
||||
- "notifications/**"
|
||||
- "cmd/notifications/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "consumers/notifier.go"
|
||||
- "pkg/events/**"
|
||||
|
||||
api:
|
||||
- "api/**"
|
||||
|
||||
consumers:
|
||||
- "consumers/**"
|
||||
|
||||
readers:
|
||||
- "readers/**"
|
||||
|
||||
- name: Set matrix for changed modules
|
||||
id: set-matrix
|
||||
run: |
|
||||
modules=()
|
||||
|
||||
if [[ "${{ steps.changes.outputs.workflow }}" == "true" || "${{ steps.changes.outputs.pkg-errors }}" == "true" ]]; then
|
||||
# If workflow or pkg/errors changed, test everything
|
||||
modules=("auth" "channels" "cli" "clients" "coap" "domains" "groups" "http" "internal" "journal" "logger" "mqtt" "pkg-errors" "pkg-events" "pkg-grpcclient" "pkg-messaging" "pkg-sdk" "pkg-transformers" "pkg-ulid" "pkg-uuid" "users" "notifications" "api" "consumers" "readers")
|
||||
else
|
||||
# Add only changed modules
|
||||
[[ "${{ steps.changes.outputs.auth }}" == "true" ]] && modules+=("auth")
|
||||
[[ "${{ steps.changes.outputs.channels }}" == "true" ]] && modules+=("channels")
|
||||
[[ "${{ steps.changes.outputs.cli }}" == "true" ]] && modules+=("cli")
|
||||
[[ "${{ steps.changes.outputs.clients }}" == "true" ]] && modules+=("clients")
|
||||
[[ "${{ steps.changes.outputs.coap }}" == "true" ]] && modules+=("coap")
|
||||
[[ "${{ steps.changes.outputs.domains }}" == "true" ]] && modules+=("domains")
|
||||
[[ "${{ steps.changes.outputs.groups }}" == "true" ]] && modules+=("groups")
|
||||
[[ "${{ steps.changes.outputs.http }}" == "true" ]] && modules+=("http")
|
||||
[[ "${{ steps.changes.outputs.internal }}" == "true" ]] && modules+=("internal")
|
||||
[[ "${{ steps.changes.outputs.journal }}" == "true" ]] && modules+=("journal")
|
||||
[[ "${{ steps.changes.outputs.logger }}" == "true" ]] && modules+=("logger")
|
||||
[[ "${{ steps.changes.outputs.mqtt }}" == "true" ]] && modules+=("mqtt")
|
||||
[[ "${{ steps.changes.outputs.pkg-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-sdk }}" == "true" ]] && modules+=("pkg-sdk")
|
||||
[[ "${{ steps.changes.outputs.pkg-transformers }}" == "true" ]] && modules+=("pkg-transformers")
|
||||
[[ "${{ steps.changes.outputs.pkg-ulid }}" == "true" ]] && modules+=("pkg-ulid")
|
||||
[[ "${{ steps.changes.outputs.pkg-uuid }}" == "true" ]] && modules+=("pkg-uuid")
|
||||
[[ "${{ steps.changes.outputs.users }}" == "true" ]] && modules+=("users")
|
||||
[[ "${{ steps.changes.outputs.notifications }}" == "true" ]] && modules+=("notifications")
|
||||
[[ "${{ steps.changes.outputs.api }}" == "true" ]] && modules+=("api")
|
||||
[[ "${{ steps.changes.outputs.consumers }}" == "true" ]] && modules+=("consumers")
|
||||
[[ "${{ steps.changes.outputs.readers }}" == "true" ]] && modules+=("readers")
|
||||
fi
|
||||
|
||||
# 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"
|
||||
|
||||
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) }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Get Go version from go.mod
|
||||
id: go-version
|
||||
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ steps.go-version.outputs.version }}
|
||||
cache-dependency-path: "go.sum"
|
||||
|
||||
- name: Verify dependencies
|
||||
run: |
|
||||
go mod download
|
||||
go mod verify
|
||||
|
||||
- name: Run ${{ matrix.module }} tests
|
||||
run: |
|
||||
# Map module names to directories
|
||||
case "${{ matrix.module }}" in
|
||||
pkg-errors) dir="pkg/errors" ;;
|
||||
pkg-events) dir="pkg/events" ;;
|
||||
pkg-grpcclient) dir="pkg/grpcclient" ;;
|
||||
pkg-messaging) dir="pkg/messaging" ;;
|
||||
pkg-sdk) dir="pkg/sdk" ;;
|
||||
pkg-transformers) dir="pkg/transformers" ;;
|
||||
pkg-ulid) dir="pkg/ulid" ;;
|
||||
pkg-uuid) dir="pkg/uuid" ;;
|
||||
*) dir="${{ matrix.module }}" ;;
|
||||
esac
|
||||
|
||||
go test -mod=readonly --race -v -count=1 -failfast -coverprofile=coverage-${{ matrix.module }}.out ./$dir/...
|
||||
|
||||
- name: Upload coverage
|
||||
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@v6
|
||||
|
||||
- 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@v5
|
||||
with:
|
||||
token: ${{ secrets.CODECOV }}
|
||||
directory: ./coverage
|
||||
files: ./coverage/*.out
|
||||
fail_ci_if_error: false
|
||||
verbose: true
|
||||
@@ -1,407 +0,0 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
name: CI Pipeline
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
lint-and-build: # Linting and building are combined to save time for setting up Go
|
||||
name: Lint and Build
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
cache-dependency-path: "go.sum"
|
||||
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
with:
|
||||
version: latest
|
||||
|
||||
- name: Build all Binaries
|
||||
run: |
|
||||
make all -j $(nproc)
|
||||
|
||||
- name: Compile check for rabbitmq
|
||||
run: |
|
||||
MG_MESSAGE_BROKER_TYPE=rabbitmq make mqtt
|
||||
|
||||
- name: Compile check for redis
|
||||
run: |
|
||||
MG_ES_TYPE=redis make mqtt
|
||||
|
||||
run-tests:
|
||||
name: Run tests
|
||||
runs-on: ubuntu-latest
|
||||
needs: lint-and-build
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
cache-dependency-path: "go.sum"
|
||||
|
||||
- name: Check for changes in specific paths
|
||||
uses: dorny/paths-filter@v2
|
||||
id: changes
|
||||
with:
|
||||
base: main
|
||||
filters: |
|
||||
workflow:
|
||||
- ".github/workflows/tests.yml"
|
||||
|
||||
auth:
|
||||
- "auth/**"
|
||||
- "cmd/auth/**"
|
||||
- "auth.proto"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "pkg/ulid/**"
|
||||
- "pkg/uuid/**"
|
||||
|
||||
bootstrap:
|
||||
- "bootstrap/**"
|
||||
- "cmd/bootstrap/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "auth/**"
|
||||
- "pkg/sdk/**"
|
||||
- "pkg/events/**"
|
||||
|
||||
certs:
|
||||
- "certs/**"
|
||||
- "cmd/certs/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "auth/**"
|
||||
- "pkg/sdk/**"
|
||||
|
||||
coap:
|
||||
- "coap/**"
|
||||
- "cmd/coap/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "things/**"
|
||||
- "pkg/messaging/**"
|
||||
|
||||
consumers:
|
||||
- "consumers/**"
|
||||
- "cmd/cassandra-writer/**"
|
||||
- "cmd/influxdb-writer/**"
|
||||
- "cmd/mongodb-writer/**"
|
||||
- "cmd/postgres-writer/**"
|
||||
- "cmd/timescale-writer/**"
|
||||
- "cmd/smpp-notifier/**"
|
||||
- "cmd/smtp-notifier/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "auth/**"
|
||||
- "pkg/ulid/**"
|
||||
- "pkg/uuid/**"
|
||||
- "pkg/messaging/**"
|
||||
|
||||
http:
|
||||
- "http/**"
|
||||
- "cmd/http/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "things/**"
|
||||
- "pkg/messaging/**"
|
||||
- "logger/**"
|
||||
|
||||
internal:
|
||||
- "internal/**"
|
||||
|
||||
invitations:
|
||||
- "invitations/**"
|
||||
- "cmd/invitations/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "auth/**"
|
||||
- "pkg/sdk/**"
|
||||
|
||||
lora:
|
||||
- "lora/**"
|
||||
- "cmd/lora/**"
|
||||
- "pkg/messaging/**"
|
||||
|
||||
logger:
|
||||
- "logger/**"
|
||||
|
||||
mqtt:
|
||||
- "mqtt/**"
|
||||
- "cmd/mqtt/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "things/**"
|
||||
- "pkg/messaging/**"
|
||||
- "logger/**"
|
||||
- "pkg/events/**"
|
||||
|
||||
opcua:
|
||||
- "opcua/**"
|
||||
- "cmd/opcua/**"
|
||||
- "logger/**"
|
||||
|
||||
pkg-auth:
|
||||
- "pkg/auth/**"
|
||||
|
||||
pkg-clients:
|
||||
- "pkg/clients/**"
|
||||
|
||||
pkg-errors:
|
||||
- "pkg/errors/**"
|
||||
|
||||
pkg-events:
|
||||
- "pkg/events/**"
|
||||
- "pkg/messaging/**"
|
||||
|
||||
pkg-messaging:
|
||||
- "pkg/messaging/**"
|
||||
|
||||
pkg-sdk:
|
||||
- "pkg/sdk/**"
|
||||
- "pkg/clients/**"
|
||||
- "pkg/errors/**"
|
||||
- "auth/**"
|
||||
- "bootstrap/**"
|
||||
- "certs/**"
|
||||
- "consumers/**"
|
||||
- "http/**"
|
||||
- "invitations/**"
|
||||
- "provision/**"
|
||||
- "readers/**"
|
||||
- "things/**"
|
||||
- "twins/**"
|
||||
- "users/**"
|
||||
|
||||
pkg-transformers:
|
||||
- "pkg/transformers/**"
|
||||
|
||||
pkg-ulid:
|
||||
- "pkg/ulid/**"
|
||||
|
||||
pkg-uuid:
|
||||
- "pkg/uuid/**"
|
||||
|
||||
provision:
|
||||
- "provision/**"
|
||||
- "cmd/provision/**"
|
||||
- "logger/**"
|
||||
- "pkg/sdk/**"
|
||||
|
||||
readers:
|
||||
- "readers/**"
|
||||
- "cmd/cassandra-reader/**"
|
||||
- "cmd/influxdb-reader/**"
|
||||
- "cmd/mongodb-reader/**"
|
||||
- "cmd/postgres-reader/**"
|
||||
- "cmd/timescale-reader/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "things/**"
|
||||
- "auth/**"
|
||||
|
||||
things:
|
||||
- "things/**"
|
||||
- "cmd/things/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "auth/**"
|
||||
- "pkg/clients/**"
|
||||
- "pkg/ulid/**"
|
||||
- "pkg/uuid/**"
|
||||
- "pkg/events/**"
|
||||
|
||||
twins:
|
||||
- "twins/**"
|
||||
- "cmd/twins/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "auth/**"
|
||||
- "pkg/messaging/**"
|
||||
- "pkg/ulid/**"
|
||||
- "pkg/uuid/**"
|
||||
- "logger/**"
|
||||
|
||||
users:
|
||||
- "users/**"
|
||||
- "cmd/users/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "auth/**"
|
||||
- "pkg/clients/**"
|
||||
- "pkg/ulid/**"
|
||||
- "pkg/uuid/**"
|
||||
- "pkg/events/**"
|
||||
|
||||
ws:
|
||||
- "ws/**"
|
||||
- "cmd/ws/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "things/**"
|
||||
- "pkg/messaging/**"
|
||||
|
||||
- name: Create coverage directory
|
||||
run: |
|
||||
mkdir coverage
|
||||
|
||||
- name: Run auth tests
|
||||
if: steps.changes.outputs.auth == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/auth.out ./auth/...
|
||||
|
||||
- name: Run bootstrap tests
|
||||
if: steps.changes.outputs.bootstrap == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/bootstrap.out ./bootstrap/...
|
||||
|
||||
- name: Run certs tests
|
||||
if: steps.changes.outputs.certs == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/certs.out ./certs/...
|
||||
|
||||
- name: Run CoAP tests
|
||||
if: steps.changes.outputs.coap == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/coap.out ./coap/...
|
||||
|
||||
- name: Run consumers tests
|
||||
if: steps.changes.outputs.consumers == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/consumers.out ./consumers/...
|
||||
|
||||
- name: Run HTTP tests
|
||||
if: steps.changes.outputs.http == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/http.out ./http/...
|
||||
|
||||
- name: Run internal tests
|
||||
if: steps.changes.outputs.internal == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/internal.out ./internal/...
|
||||
|
||||
- name: Run invitations tests
|
||||
if: steps.changes.outputs.invitations == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/invitations.out ./invitations/...
|
||||
|
||||
- name: Run logger tests
|
||||
if: steps.changes.outputs.logger == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/logger.out ./logger/...
|
||||
|
||||
- name: Run LoRa tests
|
||||
if: steps.changes.outputs.lora == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/lora.out ./lora/...
|
||||
|
||||
- name: Run MQTT tests
|
||||
if: steps.changes.outputs.mqtt == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/mqtt.out ./mqtt/...
|
||||
|
||||
- name: Run OPC-UA tests
|
||||
if: steps.changes.outputs.opcua == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/opcua.out ./opcua/...
|
||||
|
||||
- name: Run pkg auth tests
|
||||
if: steps.changes.outputs.pkg-auth == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/pkg-auth.out ./pkg/auth/...
|
||||
|
||||
- name: Run pkg clients tests
|
||||
if: steps.changes.outputs.pkg-clients == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/pkg-clients.out ./pkg/clients/...
|
||||
|
||||
- name: Run pkg errors tests
|
||||
if: steps.changes.outputs.pkg-errors == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/pkg-errors.out ./pkg/errors/...
|
||||
|
||||
- name: Run pkg events tests
|
||||
if: steps.changes.outputs.pkg-events == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/pkg-events.out ./pkg/events/...
|
||||
|
||||
- name: Run pkg messaging tests
|
||||
if: steps.changes.outputs.pkg-messaging == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/pkg-messaging.out ./pkg/messaging/...
|
||||
|
||||
- name: Run pkg sdk tests
|
||||
if: steps.changes.outputs.pkg-sdk == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/pkg-sdk.out ./pkg/sdk/...
|
||||
|
||||
- name: Run pkg transformers tests
|
||||
if: steps.changes.outputs.pkg-transformers == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/pkg-transformers.out ./pkg/transformers/...
|
||||
|
||||
- name: Run pkg ulid tests
|
||||
if: steps.changes.outputs.pkg-ulid == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/pkg-ulid.out ./pkg/ulid/...
|
||||
|
||||
- name: Run pkg uuid tests
|
||||
if: steps.changes.outputs.pkg-uuid == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/pkg-uuid.out ./pkg/uuid/...
|
||||
|
||||
- name: Run provision tests
|
||||
if: steps.changes.outputs.provision == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/provision.out ./provision/...
|
||||
|
||||
- name: Run readers tests
|
||||
if: steps.changes.outputs.readers == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/readers.out ./readers/...
|
||||
|
||||
- name: Run things tests
|
||||
if: steps.changes.outputs.things == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/things.out ./things/...
|
||||
|
||||
- name: Run twins tests
|
||||
if: steps.changes.outputs.twins == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/twins.out ./twins/...
|
||||
|
||||
- name: Run users tests
|
||||
if: steps.changes.outputs.users == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/users.out ./users/...
|
||||
|
||||
- name: Run WebSocket tests
|
||||
if: steps.changes.outputs.ws == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/ws.out ./ws/...
|
||||
|
||||
- name: Upload coverage
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
token: ${{ secrets.CODECOV }}
|
||||
directory: ./coverage/
|
||||
name: codecov-umbrella
|
||||
verbose: true
|
||||
@@ -12,3 +12,9 @@ tools/provision/mgconn.toml
|
||||
|
||||
# coverage files
|
||||
coverage
|
||||
|
||||
# Schemathesis
|
||||
.hypothesis
|
||||
|
||||
# Ignore Openbao data directory as it contains runtime-generated data
|
||||
docker/addons/certs/openbao/
|
||||
|
||||
-100
@@ -1,100 +0,0 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
run:
|
||||
timeout: 10m
|
||||
build-tags:
|
||||
- "nats"
|
||||
|
||||
issues:
|
||||
max-issues-per-linter: 100
|
||||
max-same-issues: 100
|
||||
exclude:
|
||||
- "string `Usage:\n` has (\\d+) occurrences, make it a constant"
|
||||
- "string `For example:\n` has (\\d+) occurrences, make it a constant"
|
||||
|
||||
linters-settings:
|
||||
importas:
|
||||
no-unaliased: true
|
||||
no-extra-aliases: false
|
||||
alias:
|
||||
- pkg: github.com/absmach/callhome/pkg/client
|
||||
alias: chclient
|
||||
- pkg: github.com/absmach/magistrala/logger
|
||||
alias: mglog
|
||||
- pkg: github.com/absmach/magistrala/pkg/errors/service
|
||||
alias: svcerr
|
||||
- pkg: github.com/absmach/magistrala/pkg/errors/repository
|
||||
alias: repoerr
|
||||
- pkg: github.com/absmach/magistrala/pkg/sdk/mocks
|
||||
alias: sdkmocks
|
||||
|
||||
gocritic:
|
||||
enabled-checks:
|
||||
- captLocal
|
||||
- singleCaseSwitch
|
||||
- switchTrue
|
||||
- importShadow
|
||||
- httpNoBody
|
||||
- paramTypeCombine
|
||||
- emptyStringTest
|
||||
- builtinShadow
|
||||
- exposedSyncMutex
|
||||
disabled-checks:
|
||||
- appendAssign
|
||||
enabled-tags:
|
||||
- diagnostic
|
||||
disabled-tags:
|
||||
- performance
|
||||
- style
|
||||
- experimental
|
||||
- opinionated
|
||||
misspell:
|
||||
ignore-words:
|
||||
- "mosquitto"
|
||||
stylecheck:
|
||||
checks: ["-ST1000", "-ST1003", "-ST1020", "-ST1021", "-ST1022"]
|
||||
goheader:
|
||||
template: |-
|
||||
Copyright (c) Abstract Machines
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- gocritic
|
||||
- gosimple
|
||||
- errcheck
|
||||
- govet
|
||||
- unused
|
||||
- goconst
|
||||
- godot
|
||||
- godox
|
||||
- ineffassign
|
||||
- misspell
|
||||
- stylecheck
|
||||
- whitespace
|
||||
- gci
|
||||
- gofmt
|
||||
- goimports
|
||||
- loggercheck
|
||||
- goheader
|
||||
- asasalint
|
||||
- asciicheck
|
||||
- bidichk
|
||||
- contextcheck
|
||||
- decorder
|
||||
- dogsled
|
||||
- errchkjson
|
||||
- errname
|
||||
- execinquery
|
||||
- exportloopref
|
||||
- ginkgolinter
|
||||
- gocheckcompilerdirectives
|
||||
- gofumpt
|
||||
- goprintffuncname
|
||||
- importas
|
||||
- makezero
|
||||
- mirror
|
||||
- nakedret
|
||||
- dupword
|
||||
+6
-6
@@ -1,12 +1,12 @@
|
||||
# Adopters
|
||||
|
||||
As Magistrala Community grows, we'd like to keep track of Magistrala adopters to grow the community, contact other users, share experiences and best practices.
|
||||
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.
|
||||
|
||||
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).
|
||||
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).
|
||||
Where users themselves directly maintain the list.
|
||||
|
||||
## Adding yourself as an adopter
|
||||
If you are using Magistrala, please consider adding yourself as an adopter with a brief description of your use case by opening a pull request to this file and adding a section describing your adoption of Magistrala technology.
|
||||
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.
|
||||
|
||||
**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 Magistrala:**
|
||||
**The list of organizations/users that have publicly shared the usage of SuperMQ:**
|
||||
|
||||
**Note**: Several other organizations/users couldn't publicly share their usage details but are active project contributors and Magistrala Community members.
|
||||
**Note**: Several other organizations/users couldn't publicly share their usage details but are active project contributors and SuperMQ Community members.
|
||||
|
||||
|
||||
## Adopters list (alphabetical)
|
||||
|
||||
|
||||
**Note:** The list is maintained by the users themselves. If you find yourself on this list, and you think it's inappropriate. Please contact [project maintainers](https://github.com/absmach/magistrala/blob/master/MAINTAINERS) and you will be permanently removed from the list.
|
||||
**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.
|
||||
|
||||
+11
-11
@@ -1,11 +1,11 @@
|
||||
# Contributing to Magistrala
|
||||
# Contributing to SuperMQ
|
||||
|
||||
The following is a set of guidelines to contribute to Magistrala and its libraries, which are
|
||||
The following is a set of guidelines to contribute to SuperMQ 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@magistrala.com](mailto:abuse@magistrala.com).
|
||||
[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/magistrala/issues) to determine if it already contains the
|
||||
list](https://github.com/absmach/supermq/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,23 +41,23 @@ 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>/magistrala.git
|
||||
cd magistrala
|
||||
git remote add upstream https://github.com/absmach/magistrala.git
|
||||
git clone https://github.com/<your-username>/supermq.git
|
||||
cd supermq
|
||||
git remote add upstream https://github.com/absmach/supermq.git
|
||||
```
|
||||
|
||||
If your cloned repository is behind the upstream commits, then get the latest changes from upstream:
|
||||
|
||||
```
|
||||
git checkout master
|
||||
git checkout main
|
||||
git pull --rebase upstream main
|
||||
```
|
||||
|
||||
Create a new topic branch from `master` using the naming convention `MG-[issue-number]`
|
||||
Create a new topic branch from `main` using the naming convention `SMQ-[issue-number]`
|
||||
to help us keep track of your contribution scope:
|
||||
|
||||
```
|
||||
git checkout -b MG-[issue-number]
|
||||
git checkout -b SMQ-[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 MG-[issue-number]
|
||||
git push origin SMQ-[issue-number]
|
||||
```
|
||||
|
||||
[Open a Pull Request](https://help.github.com/articles/using-pull-requests/) with a clear title
|
||||
|
||||
@@ -176,7 +176,7 @@
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015-2020 Magistrala
|
||||
Copyright 2015-2026 SuperMQ
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
+11
-26
@@ -1,30 +1,15 @@
|
||||
# Magistrala 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.
|
||||
# SuperMQ Maintainers
|
||||
|
||||
[bdfl]
|
||||
|
||||
[[drasko]]
|
||||
Name = "Drasko Draskovic"
|
||||
Email = "draasko.draskovic@abstractmachines.fr"
|
||||
GitHub = "drasko"
|
||||
SuperMQ 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 Magistrala 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) |
|
||||
|
||||
@@ -1,45 +1,52 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
MG_DOCKER_IMAGE_NAME_PREFIX ?= magistrala
|
||||
BUILD_DIR = build
|
||||
SERVICES = auth users things http coap ws lora influxdb-writer influxdb-reader mongodb-writer \
|
||||
mongodb-reader cassandra-writer cassandra-reader postgres-writer postgres-reader timescale-writer timescale-reader cli \
|
||||
bootstrap opcua twins mqtt provision certs smtp-notifier smpp-notifier invitations
|
||||
SMQ_DOCKER_IMAGE_NAME_PREFIX ?= supermq
|
||||
BUILD_DIR ?= build
|
||||
SERVICES = auth users clients groups channels domains http coap cli mqtt journal notifications
|
||||
TEST_API_SERVICES = journal auth certs http clients users channels groups domains
|
||||
TEST_API = $(addprefix test_api_,$(TEST_API_SERVICES))
|
||||
DOCKERS = $(addprefix docker_,$(SERVICES))
|
||||
DOCKERS_DEV = $(addprefix docker_dev_,$(SERVICES))
|
||||
CGO_ENABLED ?= 0
|
||||
GOARCH ?= amd64
|
||||
VERSION ?= $(shell git describe --abbrev=0 --tags)
|
||||
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)
|
||||
USER_REPO ?= $(shell git remote get-url origin | sed -e 's/.*\/\([^/]*\)\/\([^/]*\).*/\1_\2/' )
|
||||
USER_REPO ?= $(shell git remote get-url origin | sed -E 's@.*/([^/]+)/([^/.]+)(\.git)?@\1_\2@')
|
||||
empty:=
|
||||
space:= $(empty) $(empty)
|
||||
# Docker compose project name should follow this guidelines: https://docs.docker.com/compose/reference/#use--p-to-specify-a-project-name
|
||||
DOCKER_PROJECT ?= $(shell echo $(subst $(space),,$(USER_REPO)) | tr -c -s '[:alnum:][=-=]' '_' | tr '[:upper:]' '[:lower:]')
|
||||
DOCKER_COMPOSE_COMMANDS_SUPPORTED := up down config
|
||||
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
|
||||
GRPC_MTLS_CERT_FILES_EXISTS = 0
|
||||
MOCKERY_VERSION=v2.38.0
|
||||
ifneq ($(MG_MESSAGE_BROKER_TYPE),)
|
||||
MG_MESSAGE_BROKER_TYPE := $(MG_MESSAGE_BROKER_TYPE)
|
||||
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)
|
||||
else
|
||||
MG_MESSAGE_BROKER_TYPE=nats
|
||||
SMQ_MESSAGE_BROKER_TYPE=msg_nats
|
||||
endif
|
||||
|
||||
ifneq ($(MG_ES_TYPE),)
|
||||
MG_ES_TYPE := $(MG_ES_TYPE)
|
||||
ifneq ($(SMQ_ES_TYPE),)
|
||||
SMQ_ES_TYPE := $(SMQ_ES_TYPE)
|
||||
else
|
||||
MG_ES_TYPE=nats
|
||||
SMQ_ES_TYPE=es_nats
|
||||
endif
|
||||
|
||||
define compile_service
|
||||
CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) GOARCH=$(GOARCH) GOARM=$(GOARM) \
|
||||
go build -tags $(MG_MESSAGE_BROKER_TYPE) --tags $(MG_ES_TYPE) -ldflags "-s -w \
|
||||
-X 'github.com/absmach/magistrala.BuildTime=$(TIME)' \
|
||||
-X 'github.com/absmach/magistrala.Version=$(VERSION)' \
|
||||
-X 'github.com/absmach/magistrala.Commit=$(COMMIT)'" \
|
||||
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)'" \
|
||||
-o ${BUILD_DIR}/$(1) cmd/$(1)/main.go
|
||||
endef
|
||||
|
||||
@@ -54,7 +61,7 @@ define make_docker
|
||||
--build-arg VERSION=$(VERSION) \
|
||||
--build-arg COMMIT=$(COMMIT) \
|
||||
--build-arg TIME=$(TIME) \
|
||||
--tag=$(MG_DOCKER_IMAGE_NAME_PREFIX)/$(svc) \
|
||||
--tag=$(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$(svc) \
|
||||
-f docker/Dockerfile .
|
||||
endef
|
||||
|
||||
@@ -64,16 +71,53 @@ define make_docker_dev
|
||||
docker build \
|
||||
--no-cache \
|
||||
--build-arg SVC=$(svc) \
|
||||
--tag=$(MG_DOCKER_IMAGE_NAME_PREFIX)/$(svc) \
|
||||
--tag=$(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$(svc) \
|
||||
-f docker/Dockerfile.dev ./build
|
||||
endef
|
||||
|
||||
ADDON_SERVICES = bootstrap cassandra-reader cassandra-writer certs \
|
||||
influxdb-reader influxdb-writer lora-adapter mongodb-reader mongodb-writer \
|
||||
opcua-adapter postgres-reader postgres-writer provision smpp-notifier smtp-notifier \
|
||||
timescale-reader timescale-writer twins
|
||||
define run_with_arch_detection
|
||||
@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 supermq/$$svc supermq/$$svc:latest; \
|
||||
docker tag supermq/$$svc docker.io/supermq/$$svc:latest; \
|
||||
done; \
|
||||
sed -i.bak 's/^SMQ_RELEASE_TAG=.*/SMQ_RELEASE_TAG=latest/' docker/.env && rm -f docker/.env.bak; \
|
||||
docker compose -f docker/docker-compose.yaml --env-file docker/.env -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args); \
|
||||
else \
|
||||
echo "x86_64 architecture detected."; \
|
||||
git checkout $(1); \
|
||||
sed -i.bak 's/^SMQ_RELEASE_TAG=.*/SMQ_RELEASE_TAG=$(2)/' docker/.env && rm -f docker/.env.bak; \
|
||||
docker compose -f docker/docker-compose.yaml --env-file docker/.env -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args); \
|
||||
fi
|
||||
endef
|
||||
|
||||
EXTERNAL_SERVICES = vault prometheus
|
||||
ADDON_SERVICES = journal certs
|
||||
|
||||
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))
|
||||
@@ -97,41 +141,94 @@ 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
|
||||
.PHONY: all $(SERVICES) dockers dockers_dev latest release run_latest run_stable run_addons grpc_mtls_certs check_mtls check_certs test_api mocks
|
||||
|
||||
clean:
|
||||
rm -rf ${BUILD_DIR}
|
||||
|
||||
cleandocker:
|
||||
# Stops containers and removes containers, networks, volumes, and images created by up
|
||||
docker compose -f docker/docker-compose.yml -p $(DOCKER_PROJECT) down --rmi all -v --remove-orphans
|
||||
docker compose -f docker/docker-compose.yaml -p $(DOCKER_PROJECT) down --rmi all -v --remove-orphans
|
||||
|
||||
ifdef pv
|
||||
# Remove unused volumes
|
||||
docker volume ls -f name=$(MG_DOCKER_IMAGE_NAME_PREFIX) -f dangling=true -q | xargs -r docker volume rm
|
||||
docker volume ls -f name=$(SMQ_DOCKER_IMAGE_NAME_PREFIX) -f dangling=true -q | xargs -r docker volume rm
|
||||
endif
|
||||
|
||||
install:
|
||||
for file in $(BUILD_DIR)/*; do \
|
||||
cp $$file $(GOBIN)/magistrala-`basename $$file`; \
|
||||
cp $$file $(GOBIN)/supermq-`basename $$file`; \
|
||||
done
|
||||
|
||||
mocks:
|
||||
@which mockery > /dev/null || go install github.com/vektra/mockery/v2@$(MOCKERY_VERSION)
|
||||
@unset MOCKERY_VERSION && go generate ./...
|
||||
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 opcua
|
||||
DIRS = consumers readers postgres internal
|
||||
test: mocks
|
||||
mkdir -p coverage
|
||||
@for dir in $(DIRS); do \
|
||||
go test -v --race -count 1 -tags test -coverprofile=coverage/$$dir.out $$(go list ./... | grep $$dir | grep -v 'cmd'); \
|
||||
done
|
||||
go test -v --race -count 1 -tags test -coverprofile=coverage/coverage.out $$(go list ./... | grep -v 'consumers\|readers\|postgres\|internal\|opcua\|cmd')
|
||||
go test -v --race -failfast -count 1 -tags test -coverprofile=coverage/$$dir.out $$(go list ./... | grep $$dir | grep -v 'cmd'); \
|
||||
done
|
||||
go test -v --race -failfast -count 1 -tags test -coverprofile=coverage/coverage.out $$(go list ./... | grep -v 'consumers\|readers\|postgres\|internal\|cmd\|middleware')
|
||||
|
||||
define test_api_service
|
||||
$(eval svc=$(subst test_api_,,$(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; \
|
||||
fi
|
||||
|
||||
@if [ "$(svc)" = "http" ] && [ -z "$(CLIENT_SECRET)" ]; then \
|
||||
echo "CLIENT_SECRET is not set"; \
|
||||
echo "Please set it to a valid secret"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
@if [ "$(svc)" = "http" ]; then \
|
||||
uvx schemathesis run apidocs/openapi/$(svc).yaml \
|
||||
--checks all \
|
||||
--url $(2) \
|
||||
--header "Authorization: Client $(CLIENT_SECRET)" \
|
||||
--suppress-health-check=filter_too_much \
|
||||
--exclude-checks=positive_data_acceptance \
|
||||
--phases=examples,stateful; \
|
||||
else \
|
||||
uvx schemathesis run apidocs/openapi/$(svc).yaml \
|
||||
--checks all \
|
||||
--url $(2) \
|
||||
--header "Authorization: Bearer $(USER_TOKEN)" \
|
||||
--suppress-health-check=filter_too_much \
|
||||
--exclude-checks=positive_data_acceptance \
|
||||
--exclude-operation-id=requestPasswordReset \
|
||||
--phases=examples,stateful; \
|
||||
fi
|
||||
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_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))
|
||||
|
||||
proto:
|
||||
protoc -I. --go_out=. --go_opt=paths=source_relative pkg/messaging/*.proto
|
||||
protoc -I. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./*.proto
|
||||
mkdir -p $(PKG_PROTO_GEN_OUT_DIR)
|
||||
protoc -I $(INTERNAL_PROTO_DIR) --go_out=$(PKG_PROTO_GEN_OUT_DIR) --go_opt=paths=source_relative --go-grpc_out=$(PKG_PROTO_GEN_OUT_DIR) --go-grpc_opt=paths=source_relative $(INTERNAL_PROTO_FILES)
|
||||
|
||||
$(FILTERED_SERVICES):
|
||||
$(call compile_service,$(@))
|
||||
@@ -147,7 +244,7 @@ dockers_dev: $(DOCKERS_DEV)
|
||||
|
||||
define docker_push
|
||||
for svc in $(SERVICES); do \
|
||||
docker push $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(1); \
|
||||
docker push $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(1); \
|
||||
done
|
||||
endef
|
||||
|
||||
@@ -157,12 +254,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 $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(VERSION)-$(GOARCH); \
|
||||
docker tag $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc:latest-$(GOARCH); \
|
||||
docker push $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(VERSION)-$(GOARCH); \
|
||||
docker push $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc:latest-$(GOARCH); \
|
||||
done
|
||||
|
||||
release:
|
||||
$(eval version = $(shell git describe --abbrev=0 --tags))
|
||||
git checkout $(version)
|
||||
$(MAKE) dockers
|
||||
for svc in $(SERVICES); do \
|
||||
docker tag $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(version); \
|
||||
docker tag $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(version); \
|
||||
done
|
||||
$(call docker_push,$(version))
|
||||
|
||||
@@ -170,42 +276,57 @@ rundev:
|
||||
cd scripts && ./run.sh
|
||||
|
||||
grpc_mtls_certs:
|
||||
$(MAKE) -C docker/ssl auth_grpc_certs things_grpc_certs
|
||||
$(MAKE) -C docker/ssl auth_grpc_certs clients_grpc_certs
|
||||
|
||||
check_tls:
|
||||
ifeq ($(GRPC_TLS),true)
|
||||
@unset GRPC_MTLS
|
||||
@echo "gRPC TLS is enabled"
|
||||
GRPC_MTLS=
|
||||
$(eval GRPC_MTLS :=)
|
||||
else
|
||||
@unset GRPC_TLS
|
||||
GRPC_TLS=
|
||||
$(eval GRPC_TLS :=)
|
||||
endif
|
||||
|
||||
check_mtls:
|
||||
ifeq ($(GRPC_MTLS),true)
|
||||
@unset GRPC_TLS
|
||||
@echo "gRPC MTLS is enabled"
|
||||
GRPC_TLS=
|
||||
$(eval GRPC_TLS :=)
|
||||
else
|
||||
@unset GRPC_MTLS
|
||||
GRPC_MTLS=
|
||||
$(eval GRPC_MTLS :=)
|
||||
endif
|
||||
|
||||
check_certs: check_mtls check_tls
|
||||
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 things_grpc_certs
|
||||
$(MAKE) -C docker/ssl auth_grpc_certs clients_grpc_certs
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
run: check_certs
|
||||
docker compose -f docker/docker-compose.yml --env-file docker/.env -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args)
|
||||
fetch_certs:
|
||||
@./scripts/certs.sh
|
||||
|
||||
run_latest: check_certs
|
||||
git checkout main
|
||||
$(SED_INPLACE) 's/^SMQ_RELEASE_TAG=.*/SMQ_RELEASE_TAG=latest/' docker/.env
|
||||
$(DOCKER_PLATFORM) docker compose -f docker/docker-compose.yaml --env-file docker/.env -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args)
|
||||
|
||||
run_stable: check_certs
|
||||
$(eval version = $(shell git describe --abbrev=0 --tags))
|
||||
git checkout $(version)
|
||||
$(SED_INPLACE) 's/^SMQ_RELEASE_TAG=.*/SMQ_RELEASE_TAG=$(version)/' docker/.env
|
||||
$(DOCKER_PLATFORM) docker compose -f docker/docker-compose.yaml --env-file docker/.env -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args)
|
||||
|
||||
run_addons: check_certs
|
||||
$(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 --env-file ./docker/.env -p $(DOCKER_PROJECT) up -d auth domains jaeger
|
||||
@for SVC in $(RUN_ADDON_ARGS); do \
|
||||
MG_ADDONS_CERTS_PATH_PREFIX="../." docker compose -f docker/addons/$$SVC/docker-compose.yml -p $(DOCKER_PROJECT) --env-file ./docker/.env $(DOCKER_COMPOSE_COMMAND) $(args) & \
|
||||
if [ "$$SVC" = "certs" ]; then \
|
||||
$(DOCKER_PLATFORM) docker compose -f docker/addons/$$SVC/docker-compose.yaml -f docker/certs-docker-compose-override.yaml --env-file ./docker/.env --env-file ./docker/addons/$$SVC/.env -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args) & \
|
||||
else \
|
||||
SMQ_ADDONS_CERTS_PATH_PREFIX="../." $(DOCKER_PLATFORM) docker compose -f docker/addons/$$SVC/docker-compose.yaml -p $(DOCKER_PROJECT) --env-file ./docker/.env $(DOCKER_COMPOSE_COMMAND) $(args) & \
|
||||
fi; \
|
||||
done
|
||||
|
||||
run_live: check_certs
|
||||
GOPATH=$(go env GOPATH) $(DOCKER_PLATFORM) docker compose -f docker/docker-compose.yaml -f docker/docker-compose-live.yaml --env-file docker/.env -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args)
|
||||
|
||||
@@ -1,193 +1,153 @@
|
||||
# Magistrala
|
||||
<div align="center">
|
||||
|
||||
[](https://github.com/absmach/magistrala/actions/workflows/check-license.yaml)
|
||||
[](https://github.com/absmach/magistrala/actions/workflows/check-generated-files.yml)
|
||||
[](https://github.com/absmach/magistrala/actions/workflows/build.yml)
|
||||
[![go report card][grc-badge]][grc-url]
|
||||
[![coverage][cov-badge]][cov-url]
|
||||
[![license][license]](LICENSE)
|
||||
[![chat][gitter-badge]][gitter]
|
||||
# SuperMQ
|
||||
|
||||
### Planetary event-driven infrastructure
|
||||
|
||||
**Made with ❤️ by [Abstract Machines](https://absmach.eu/)**
|
||||
|
||||
![banner][banner]
|
||||
[](https://github.com/absmach/supermq/actions/workflows/build.yaml)
|
||||
[](https://goreportcard.com/report/github.com/absmach/supermq)
|
||||
[](https://deepwiki.com/absmach/supermq)
|
||||
[](https://github.com/absmach/supermq/actions/workflows/check-license.yaml)
|
||||
[](https://github.com/absmach/supermq/actions/workflows/check-generated-files.yaml)
|
||||
[](https://codecov.io/gh/absmach/supermq)
|
||||
[](LICENSE)
|
||||
[](https://matrix.to/#/#supermq:matrix.org)
|
||||
|
||||
### [Guide](https://docs.supermq.absmach.eu) | [Contributing](CONTRIBUTING.md) | [Website](https://absmach.eu/) | [Chat](https://matrix.to/#/#supermq:matrix.org)
|
||||
|
||||
Magistrala is modern, scalable, secure, open-source, and patent-free IoT cloud platform written in Go.
|
||||
</div>
|
||||
|
||||
It accepts user and thing (sensor, actuator, application) connections over various network protocols (i.e. HTTP, MQTT, WebSocket, CoAP), thus making a seamless bridge between them. It is used as the IoT middleware for building complex IoT solutions.
|
||||
## Introduction 📖
|
||||
|
||||
For more details, check out the [official documentation][docs].
|
||||
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.
|
||||
|
||||
## Features
|
||||
## Why SuperMQ Stands Out 🚀
|
||||
|
||||
- Multi-protocol connectivity and bridging (HTTP, MQTT, WebSocket and CoAP)
|
||||
- Device management and provisioning (Zero Touch provisioning)
|
||||
- Mutual TLS Authentication (mTLS) using X.509 Certificates
|
||||
- Fine-grained access control (policies, ABAC/RBAC)
|
||||
- Message persistence (Cassandra, InfluxDB, MongoDB and PostgresSQL)
|
||||
- Platform logging and instrumentation support (Prometheus and OpenTelemetry)
|
||||
- Event sourcing
|
||||
- Container-based deployment using [Docker][docker] and [Kubernetes][kubernetes]
|
||||
- [LoRaWAN][lora] network integration
|
||||
- [OPC UA][opcua] integration
|
||||
- Edge [Agent][agent] and [Export][export] services for remote IoT gateway management and edge computing
|
||||
- SDK
|
||||
- CLI
|
||||
- Small memory footprint and fast execution
|
||||
- Domain-driven design architecture, high-quality code and test coverage
|
||||
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. 🌐✨
|
||||
|
||||
## Prerequisites
|
||||
## Key Features 🌟
|
||||
|
||||
The following are needed to run Magistrala:
|
||||
- **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. 🐳☸️
|
||||
|
||||
- [Docker](https://docs.docker.com/install/) (version 24.0.7)
|
||||
- [Docker compose](https://docs.docker.com/compose/install/) (version 2.24.0)
|
||||
## Installation 🛠️
|
||||
|
||||
Developing Magistrala will also require:
|
||||
|
||||
- [Go](https://golang.org/doc/install) (version 1.21)
|
||||
- [Protobuf](https://github.com/protocolbuffers/protobuf#protocol-compiler-installation) (version 25.1)
|
||||
|
||||
## Install
|
||||
|
||||
Once the prerequisites are installed, execute the following commands from the project's root:
|
||||
There are multiple ways to run SuperMQ.
|
||||
First, clone the repository and position to it:
|
||||
|
||||
```bash
|
||||
docker compose -f docker/docker-compose.yml --env-file docker/.env -p git_github_com_absmach_magistrala_git_ up
|
||||
git clone https://github.com/absmach/supermq.git
|
||||
cd supermq
|
||||
```
|
||||
|
||||
This will bring up the Magistrala docker services and interconnect them. This command can also be executed using the project's included Makefile:
|
||||
To run the latest stable (tagged) version, use:
|
||||
|
||||
```bash
|
||||
make run
|
||||
# Run with latest stable tagged version
|
||||
make run_stable
|
||||
```
|
||||
|
||||
If you want to run services from specific release checkout code from github and make sure that
|
||||
`MG_RELEASE_TAG` in [.env](.env) is being set to match the release version
|
||||
To run the latest version, use:
|
||||
|
||||
```bash
|
||||
git checkout tags/<release_number> -b <release_number>
|
||||
# e.g. `git checkout tags/0.13.0 -b 0.13.0`
|
||||
# Run with latest development version (from main branch)
|
||||
make run_latest
|
||||
```
|
||||
|
||||
Check that `.env` file contains:
|
||||
The `make run_stable` command will:
|
||||
- Checkout the repository to the latest git tag
|
||||
- Update the version in the environment configuration
|
||||
- Start the services with the stable release
|
||||
|
||||
**Note:** After running `make run_stable`, you'll be on a detached HEAD state. To return to your working branch:
|
||||
|
||||
```bash
|
||||
MG_RELEASE_TAG=<release_number>
|
||||
git checkout main
|
||||
```
|
||||
|
||||
> `docker-compose` should be used for development and testing deployments. For production we suggest using [Kubernetes](https://docs.mainflux.io/kubernetes).
|
||||
### Running on Apple Silicon (M1/M2/M3) Macs
|
||||
|
||||
## Usage
|
||||
When running SuperMQ on Apple Silicon Macs, the Makefile will automatically detect your ARM64 architecture and build Docker images locally.
|
||||
|
||||
The quickest way to start using Magistrala is via the CLI. The latest version can be downloaded from the [official releases page][releases].
|
||||
**If using Docker Desktop:**
|
||||
|
||||
It can also be built and used from the project's root directory:
|
||||
1. **Enable Apple Virtualization Framework**: In Docker Desktop, go to:
|
||||
- Settings → General → Enable "Use the new Virtualization framework"
|
||||
|
||||
2. **Enable Rosetta for x86_64 Emulation**: In Docker Desktop, go to:
|
||||
- Settings → General → Enable "Use Rosetta for x86_64/amd64 emulation on Apple Silicon"
|
||||
|
||||
After enabling these options, restart Docker Desktop, then run `make run_stable` or `make run_latest` as usual.
|
||||
|
||||
To manually run SuperMQ, clone the repository and start all core services:
|
||||
|
||||
```bash
|
||||
docker compose -f docker/docker-compose.yaml --env-file docker/.env up
|
||||
```
|
||||
|
||||
### Usage 📤📥
|
||||
|
||||
**Using the CLI :**
|
||||
|
||||
```bash
|
||||
make cli
|
||||
./build/cli version
|
||||
./build/supermq-cli status
|
||||
```
|
||||
|
||||
Additional details on using the CLI can be found in the [CLI documentation](https://docs.mainflux.io/cli).
|
||||
This command retrieves the status of the SuperMQ server and outputs it to the console.
|
||||
|
||||
## Documentation
|
||||
**Using HTTP with Curl :**
|
||||
|
||||
Official documentation is hosted at [Magistrala official docs page][docs]. Documentation is auto-generated, checkout the instructions on [official docs repository](https://github.com/mainflux/docs):
|
||||
```bash
|
||||
curl -X GET http://localhost:8080/status
|
||||
```
|
||||
|
||||
If you spot an error or a need for corrections, please let us know - or even better: send us a PR.
|
||||
This request fetches the server status over HTTP and provides a JSON response.
|
||||
|
||||
## Authors
|
||||
See our [CLI documentation](https://docs.supermq.absmach.eu/cli) for more details.
|
||||
|
||||
Main architect and BDFL of Magistrala project is [@drasko][drasko].
|
||||
## Documentation 📚
|
||||
|
||||
Additionally, [@nmarcetic][nikola] and [@janko-isidorovic][janko] assured overall architecture and design, while [@manuio][manu] and [@darkodraskovic][darko] helped with crafting initial implementation and continuously worked on the project evolutions.
|
||||
The official documentation is hosted at [SuperMQ docs page](https://docs.supermq.absmach.eu/).
|
||||
|
||||
Besides them, Magistrala is constantly improved and actively developed by [@anovakovic01][alex], [@dusanb94][dusan], [@srados][sava], [@gsaleh][george], [@blokovi][iva], [@chombium][kole], [@mteodor][mirko], [@rodneyosodo][rodneyosodo] and a large set of contributors.
|
||||
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! 💌
|
||||
|
||||
Maintainers are listed in [MAINTAINERS](MAINTAINERS) file.
|
||||
## Community and Contributing 🤝
|
||||
|
||||
The Magistrala team would like to give special thanks to [@mijicd][dejan] for his monumental work on designing and implementing a highly improved and optimized version of the platform, and [@malidukica][dusanm] for his effort on implementing the initial user interface.
|
||||
Thank you for your interest in SuperMQ and the desire to contribute!
|
||||
|
||||
## Professional Support
|
||||
|
||||
There are many companies offering professional support for the Magistrala system.
|
||||
|
||||
If you need this kind of support, best is to reach out to [@drasko][drasko] directly, and he will point you out to the best-matching support team.
|
||||
|
||||
## Contributing
|
||||
|
||||
Thank you for your interest in Magistrala and the desire to contribute!
|
||||
|
||||
1. Take a look at our [open issues](https://github.com/absmach/magistrala/issues). The [good-first-issue](https://github.com/absmach/magistrala/labels/good-first-issue) label is specifically for issues that are great for getting started.
|
||||
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.
|
||||
|
||||
### We're Hiring
|
||||
Join our community:
|
||||
|
||||
You like Magistrala and you would like to make it your day job? We're always looking for talented engineers interested in open-source, IoT and distributed systems. If you recognize yourself, reach out to [@drasko][drasko] - he will contact you back.
|
||||
- [Matrix Room](https://matrix.to/#/#supermq\:matrix.org)
|
||||
|
||||
> The best way to grab our attention is, of course, by sending PRs :sunglasses:.
|
||||
## Professional Support 💼
|
||||
|
||||
## Community
|
||||
Need help deploying SuperMQ or integrating it into your system? Reach out to **[Abstract Machines](https://absmach.eu/)** for professional support and guidance.
|
||||
|
||||
- [Google group][forum]
|
||||
- [Gitter][gitter]
|
||||
- [Twitter][twitter]
|
||||
## License 📜
|
||||
|
||||
## License
|
||||
SuperMQ is open-source software licensed under the [Apache License 2.0](LICENSE). Contributions are welcome!
|
||||
|
||||
[Apache-2.0](LICENSE)
|
||||
## Acknowledgments 🙌
|
||||
|
||||
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fmainflux%2Fmainflux?ref=badge_large)
|
||||
Special thanks to the amazing contributors who make SuperMQ possible. Check out the [MAINTAINERS](MAINTAINERS) file to see the team behind the magic.
|
||||
|
||||
## Data Collection for Magistrala
|
||||
|
||||
Magistrala is committed to continuously improving its services and ensuring a seamless experience for its users. To achieve this, we collect certain data from your deployments. Rest assured, this data is collected solely for the purpose of enhancing Magistrala and is not used with any malicious intent. The deployment summary can be found on our [website][callhome].
|
||||
|
||||
The collected data includes:
|
||||
|
||||
- **IP Address** - Used for approximate location information on deployments.
|
||||
- **Services Used** - To understand which features are popular and prioritize future developments.
|
||||
- **Last Seen Time** - To ensure the stability and availability of Magistrala.
|
||||
- **Magistrala Version** - To track the software version and deliver relevant updates.
|
||||
|
||||
We take your privacy and data security seriously. All data collected is handled in accordance with our stringent privacy policies and industry best practices.
|
||||
|
||||
Data collection is on by default and can be disabled by setting the env variable:
|
||||
`MG_SEND_TELEMETRY=false`
|
||||
|
||||
By utilizing Magistrala, you actively contribute to its improvement. Together, we can build a more robust and efficient IoT platform. Thank you for your trust in Magistrala!
|
||||
|
||||
[banner]: https://github.com/mainflux/docs/blob/master/docs/img/gopherBanner.jpg
|
||||
[docs]: https://docs.mainflux.io
|
||||
[docker]: https://www.docker.com
|
||||
[forum]: https://groups.google.com/forum/#!forum/mainflux
|
||||
[gitter]: https://gitter.im/absmach/magistrala?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
||||
[gitter-badge]: https://badges.gitter.im/Join%20Chat.svg
|
||||
[grc-badge]: https://goreportcard.com/badge/github.com/absmach/magistrala
|
||||
[grc-url]: https://goreportcard.com/report/github.com/absmach/magistrala
|
||||
[cov-badge]: https://codecov.io/gh/absmach/magistrala/graph/badge.svg?token=SEMDAO3L09
|
||||
[cov-url]: https://codecov.io/gh/absmach/magistrala
|
||||
[license]: https://img.shields.io/badge/license-Apache%20v2.0-blue.svg
|
||||
[twitter]: https://twitter.com/mainflux
|
||||
[lora]: https://lora-alliance.org/
|
||||
[opcua]: https://opcfoundation.org/about/opc-technologies/opc-ua/
|
||||
[agent]: https://github.com/mainflux/agent
|
||||
[export]: https://github.com/mainflux/export
|
||||
[kubernetes]: https://kubernetes.io/
|
||||
[releases]: https://github.com/absmach/magistrala/releases
|
||||
[drasko]: https://github.com/drasko
|
||||
[nikola]: https://github.com/nmarcetic
|
||||
[dejan]: https://github.com/mijicd
|
||||
[manu]: https://github.com/manuIO
|
||||
[darko]: https://github.com/darkodraskovic
|
||||
[janko]: https://github.com/janko-isidorovic
|
||||
[alex]: https://github.com/anovakovic01
|
||||
[dusan]: https://github.com/dborovcanin
|
||||
[sava]: https://github.com/srados
|
||||
[george]: https://github.com/gesaleh
|
||||
[iva]: https://github.com/blokovi
|
||||
[kole]: https://github.com/chombium
|
||||
[dusanm]: https://github.com/malidukica
|
||||
[mirko]: https://github.com/mteodor
|
||||
[rodneyosodo]: https://github.com/rodneyosodo
|
||||
[callhome]: https://deployments.mainflux.io
|
||||
Ready to build the future of messaging and event-driven systems? Let's get started! 🚀
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package magistrala
|
||||
package supermq
|
||||
|
||||
// Response contains HTTP response specific methods.
|
||||
type Response interface {
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package api contains commonly used constants and functions
|
||||
// for the HTTP endpoints.
|
||||
// for the HTTP and gRPC API.
|
||||
package api
|
||||
@@ -0,0 +1,541 @@
|
||||
// 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 v6.33.0
|
||||
// source: auth/v1/auth.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)
|
||||
)
|
||||
|
||||
type AuthNReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *AuthNReq) Reset() {
|
||||
*x = AuthNReq{}
|
||||
mi := &file_auth_v1_auth_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *AuthNReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AuthNReq) ProtoMessage() {}
|
||||
|
||||
func (x *AuthNReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_auth_v1_auth_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 AuthNReq.ProtoReflect.Descriptor instead.
|
||||
func (*AuthNReq) Descriptor() ([]byte, []int) {
|
||||
return file_auth_v1_auth_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *AuthNReq) GetToken() string {
|
||||
if x != nil {
|
||||
return x.Token
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type AuthNRes struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
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"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *AuthNRes) Reset() {
|
||||
*x = AuthNRes{}
|
||||
mi := &file_auth_v1_auth_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *AuthNRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AuthNRes) ProtoMessage() {}
|
||||
|
||||
func (x *AuthNRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_auth_v1_auth_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 AuthNRes.ProtoReflect.Descriptor instead.
|
||||
func (*AuthNRes) Descriptor() ([]byte, []int) {
|
||||
return file_auth_v1_auth_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *AuthNRes) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AuthNRes) GetUserId() string {
|
||||
if x != nil {
|
||||
return x.UserId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AuthNRes) GetUserRole() uint32 {
|
||||
if x != nil {
|
||||
return x.UserRole
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *AuthNRes) GetVerified() bool {
|
||||
if x != nil {
|
||||
return x.Verified
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type PolicyReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
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[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *AuthZReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AuthZReq) ProtoMessage() {}
|
||||
|
||||
func (x *AuthZReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_auth_v1_auth_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 AuthZReq.ProtoReflect.Descriptor instead.
|
||||
func (*AuthZReq) Descriptor() ([]byte, []int) {
|
||||
return file_auth_v1_auth_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *AuthZReq) GetPolicyReq() *PolicyReq {
|
||||
if x != nil {
|
||||
return x.PolicyReq
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *AuthZReq) GetPatReq() *PATReq {
|
||||
if x != nil {
|
||||
return x.PatReq
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type AuthZRes struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Authorized bool `protobuf:"varint,1,opt,name=authorized,proto3" json:"authorized,omitempty"`
|
||||
Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *AuthZRes) Reset() {
|
||||
*x = AuthZRes{}
|
||||
mi := &file_auth_v1_auth_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *AuthZRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AuthZRes) ProtoMessage() {}
|
||||
|
||||
func (x *AuthZRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_auth_v1_auth_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 AuthZRes.ProtoReflect.Descriptor instead.
|
||||
func (*AuthZRes) Descriptor() ([]byte, []int) {
|
||||
return file_auth_v1_auth_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *AuthZRes) GetAuthorized() bool {
|
||||
if x != nil {
|
||||
return x.Authorized
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *AuthZRes) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_auth_v1_auth_proto protoreflect.FileDescriptor
|
||||
|
||||
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\"l\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\x12\x1a\n" +
|
||||
"\bverified\x18\x04 \x01(\bR\bverified\"\xa3\x02\n" +
|
||||
"\tPolicyReq\x12\x16\n" +
|
||||
"\x06domain\x18\x01 \x01(\tR\x06domain\x12!\n" +
|
||||
"\fsubject_type\x18\x02 \x01(\tR\vsubjectType\x12!\n" +
|
||||
"\fsubject_kind\x18\x03 \x01(\tR\vsubjectKind\x12)\n" +
|
||||
"\x10subject_relation\x18\x04 \x01(\tR\x0fsubjectRelation\x12\x18\n" +
|
||||
"\asubject\x18\x05 \x01(\tR\asubject\x12\x1a\n" +
|
||||
"\brelation\x18\x06 \x01(\tR\brelation\x12\x1e\n" +
|
||||
"\n" +
|
||||
"permission\x18\a \x01(\tR\n" +
|
||||
"permission\x12\x16\n" +
|
||||
"\x06object\x18\b \x01(\tR\x06object\x12\x1f\n" +
|
||||
"\vobject_type\x18\t \x01(\tR\n" +
|
||||
"objectType\"\xac\x01\n" +
|
||||
"\x06PATReq\x12\x15\n" +
|
||||
"\x06pat_id\x18\x01 \x01(\tR\x05patId\x12\x16\n" +
|
||||
"\x06domain\x18\x02 \x01(\tR\x06domain\x12\x1c\n" +
|
||||
"\toperation\x18\x03 \x01(\tR\toperation\x12\x17\n" +
|
||||
"\auser_id\x18\x04 \x01(\tR\x06userId\x12\x1b\n" +
|
||||
"\tentity_id\x18\x05 \x01(\tR\bentityId\x12\x1f\n" +
|
||||
"\ventity_type\x18\x06 \x01(\tR\n" +
|
||||
"entityType\"x\n" +
|
||||
"\bAuthZReq\x121\n" +
|
||||
"\n" +
|
||||
"policy_req\x18\x01 \x01(\v2\x12.auth.v1.PolicyReqR\tpolicyReq\x12-\n" +
|
||||
"\apat_req\x18\x02 \x01(\v2\x0f.auth.v1.PATReqH\x00R\x06patReq\x88\x01\x01B\n" +
|
||||
"\n" +
|
||||
"\b_pat_req\":\n" +
|
||||
"\bAuthZRes\x12\x1e\n" +
|
||||
"\n" +
|
||||
"authorized\x18\x01 \x01(\bR\n" +
|
||||
"authorized\x12\x0e\n" +
|
||||
"\x02id\x18\x02 \x01(\tR\x02id2z\n" +
|
||||
"\vAuthService\x123\n" +
|
||||
"\tAuthorize\x12\x11.auth.v1.AuthZReq\x1a\x11.auth.v1.AuthZRes\"\x00\x126\n" +
|
||||
"\fAuthenticate\x12\x11.auth.v1.AuthNReq\x1a\x11.auth.v1.AuthNRes\"\x00B-Z+github.com/absmach/supermq/api/grpc/auth/v1b\x06proto3"
|
||||
|
||||
var (
|
||||
file_auth_v1_auth_proto_rawDescOnce sync.Once
|
||||
file_auth_v1_auth_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_auth_v1_auth_proto_rawDescGZIP() []byte {
|
||||
file_auth_v1_auth_proto_rawDescOnce.Do(func() {
|
||||
file_auth_v1_auth_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_auth_v1_auth_proto_rawDesc), len(file_auth_v1_auth_proto_rawDesc)))
|
||||
})
|
||||
return file_auth_v1_auth_proto_rawDescData
|
||||
}
|
||||
|
||||
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
|
||||
(*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.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() }
|
||||
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: 6,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_auth_v1_auth_proto_goTypes,
|
||||
DependencyIndexes: file_auth_v1_auth_proto_depIdxs,
|
||||
MessageInfos: file_auth_v1_auth_proto_msgTypes,
|
||||
}.Build()
|
||||
File_auth_v1_auth_proto = out.File
|
||||
file_auth_v1_auth_proto_goTypes = nil
|
||||
file_auth_v1_auth_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
// 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.0
|
||||
// - protoc v6.33.0
|
||||
// source: auth/v1/auth.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 (
|
||||
AuthService_Authorize_FullMethodName = "/auth.v1.AuthService/Authorize"
|
||||
AuthService_Authenticate_FullMethodName = "/auth.v1.AuthService/Authenticate"
|
||||
)
|
||||
|
||||
// AuthServiceClient is the client API for AuthService 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.
|
||||
//
|
||||
// AuthService is a service that provides authentication
|
||||
// and authorization functionalities for SuperMQ services.
|
||||
type AuthServiceClient interface {
|
||||
Authorize(ctx context.Context, in *AuthZReq, opts ...grpc.CallOption) (*AuthZRes, error)
|
||||
Authenticate(ctx context.Context, in *AuthNReq, opts ...grpc.CallOption) (*AuthNRes, error)
|
||||
}
|
||||
|
||||
type authServiceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewAuthServiceClient(cc grpc.ClientConnInterface) AuthServiceClient {
|
||||
return &authServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *authServiceClient) Authorize(ctx context.Context, in *AuthZReq, opts ...grpc.CallOption) (*AuthZRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(AuthZRes)
|
||||
err := c.cc.Invoke(ctx, AuthService_Authorize_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)
|
||||
err := c.cc.Invoke(ctx, AuthService_Authenticate_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.
|
||||
type AuthServiceServer interface {
|
||||
Authorize(context.Context, *AuthZReq) (*AuthZRes, error)
|
||||
Authenticate(context.Context, *AuthNReq) (*AuthNRes, error)
|
||||
mustEmbedUnimplementedAuthServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedAuthServiceServer 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 UnimplementedAuthServiceServer struct{}
|
||||
|
||||
func (UnimplementedAuthServiceServer) Authorize(context.Context, *AuthZReq) (*AuthZRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method Authorize not implemented")
|
||||
}
|
||||
func (UnimplementedAuthServiceServer) Authenticate(context.Context, *AuthNReq) (*AuthNRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method Authenticate not implemented")
|
||||
}
|
||||
func (UnimplementedAuthServiceServer) mustEmbedUnimplementedAuthServiceServer() {}
|
||||
func (UnimplementedAuthServiceServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeAuthServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to AuthServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeAuthServiceServer interface {
|
||||
mustEmbedUnimplementedAuthServiceServer()
|
||||
}
|
||||
|
||||
func RegisterAuthServiceServer(s grpc.ServiceRegistrar, srv AuthServiceServer) {
|
||||
// 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.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&AuthService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _AuthService_Authorize_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(AuthZReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(AuthServiceServer).Authorize(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: AuthService_Authorize_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(AuthServiceServer).Authorize(ctx, req.(*AuthZReq))
|
||||
}
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(AuthServiceServer).Authenticate(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: AuthService_Authenticate_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(AuthServiceServer).Authenticate(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)
|
||||
var AuthService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "auth.v1.AuthService",
|
||||
HandlerType: (*AuthServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Authorize",
|
||||
Handler: _AuthService_Authorize_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Authenticate",
|
||||
Handler: _AuthService_Authenticate_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "auth/v1/auth.proto",
|
||||
}
|
||||
@@ -0,0 +1,402 @@
|
||||
// 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 v6.33.0
|
||||
// source: channels/v1/channels.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
v1 "github.com/absmach/supermq/api/grpc/common/v1"
|
||||
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)
|
||||
)
|
||||
|
||||
type RemoveClientConnectionsReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RemoveClientConnectionsReq) Reset() {
|
||||
*x = RemoveClientConnectionsReq{}
|
||||
mi := &file_channels_v1_channels_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *RemoveClientConnectionsReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RemoveClientConnectionsReq) ProtoMessage() {}
|
||||
|
||||
func (x *RemoveClientConnectionsReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_channels_v1_channels_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 RemoveClientConnectionsReq.ProtoReflect.Descriptor instead.
|
||||
func (*RemoveClientConnectionsReq) Descriptor() ([]byte, []int) {
|
||||
return file_channels_v1_channels_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *RemoveClientConnectionsReq) GetClientId() string {
|
||||
if x != nil {
|
||||
return x.ClientId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type RemoveClientConnectionsRes struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RemoveClientConnectionsRes) Reset() {
|
||||
*x = RemoveClientConnectionsRes{}
|
||||
mi := &file_channels_v1_channels_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *RemoveClientConnectionsRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RemoveClientConnectionsRes) ProtoMessage() {}
|
||||
|
||||
func (x *RemoveClientConnectionsRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_channels_v1_channels_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 RemoveClientConnectionsRes.ProtoReflect.Descriptor instead.
|
||||
func (*RemoveClientConnectionsRes) Descriptor() ([]byte, []int) {
|
||||
return file_channels_v1_channels_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
type UnsetParentGroupFromChannelsReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
ParentGroupId string `protobuf:"bytes,1,opt,name=parent_group_id,json=parentGroupId,proto3" json:"parent_group_id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *UnsetParentGroupFromChannelsReq) Reset() {
|
||||
*x = UnsetParentGroupFromChannelsReq{}
|
||||
mi := &file_channels_v1_channels_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *UnsetParentGroupFromChannelsReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*UnsetParentGroupFromChannelsReq) ProtoMessage() {}
|
||||
|
||||
func (x *UnsetParentGroupFromChannelsReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_channels_v1_channels_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 UnsetParentGroupFromChannelsReq.ProtoReflect.Descriptor instead.
|
||||
func (*UnsetParentGroupFromChannelsReq) Descriptor() ([]byte, []int) {
|
||||
return file_channels_v1_channels_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *UnsetParentGroupFromChannelsReq) GetParentGroupId() string {
|
||||
if x != nil {
|
||||
return x.ParentGroupId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type UnsetParentGroupFromChannelsRes struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *UnsetParentGroupFromChannelsRes) Reset() {
|
||||
*x = UnsetParentGroupFromChannelsRes{}
|
||||
mi := &file_channels_v1_channels_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *UnsetParentGroupFromChannelsRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*UnsetParentGroupFromChannelsRes) ProtoMessage() {}
|
||||
|
||||
func (x *UnsetParentGroupFromChannelsRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_channels_v1_channels_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 UnsetParentGroupFromChannelsRes.ProtoReflect.Descriptor instead.
|
||||
func (*UnsetParentGroupFromChannelsRes) Descriptor() ([]byte, []int) {
|
||||
return file_channels_v1_channels_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
type AuthzReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
DomainId string `protobuf:"bytes,1,opt,name=domain_id,json=domainId,proto3" json:"domain_id,omitempty"`
|
||||
ClientId string `protobuf:"bytes,2,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"`
|
||||
ClientType string `protobuf:"bytes,3,opt,name=client_type,json=clientType,proto3" json:"client_type,omitempty"`
|
||||
ChannelId string `protobuf:"bytes,4,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
|
||||
Type uint32 `protobuf:"varint,5,opt,name=type,proto3" json:"type,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *AuthzReq) Reset() {
|
||||
*x = AuthzReq{}
|
||||
mi := &file_channels_v1_channels_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *AuthzReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AuthzReq) ProtoMessage() {}
|
||||
|
||||
func (x *AuthzReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_channels_v1_channels_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 AuthzReq.ProtoReflect.Descriptor instead.
|
||||
func (*AuthzReq) Descriptor() ([]byte, []int) {
|
||||
return file_channels_v1_channels_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *AuthzReq) GetDomainId() string {
|
||||
if x != nil {
|
||||
return x.DomainId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AuthzReq) GetClientId() string {
|
||||
if x != nil {
|
||||
return x.ClientId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AuthzReq) GetClientType() string {
|
||||
if x != nil {
|
||||
return x.ClientType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AuthzReq) GetChannelId() string {
|
||||
if x != nil {
|
||||
return x.ChannelId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AuthzReq) GetType() uint32 {
|
||||
if x != nil {
|
||||
return x.Type
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type AuthzRes struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Authorized bool `protobuf:"varint,1,opt,name=authorized,proto3" json:"authorized,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *AuthzRes) Reset() {
|
||||
*x = AuthzRes{}
|
||||
mi := &file_channels_v1_channels_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *AuthzRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AuthzRes) ProtoMessage() {}
|
||||
|
||||
func (x *AuthzRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_channels_v1_channels_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 AuthzRes.ProtoReflect.Descriptor instead.
|
||||
func (*AuthzRes) Descriptor() ([]byte, []int) {
|
||||
return file_channels_v1_channels_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *AuthzRes) GetAuthorized() bool {
|
||||
if x != nil {
|
||||
return x.Authorized
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var File_channels_v1_channels_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_channels_v1_channels_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x1achannels/v1/channels.proto\x12\vchannels.v1\x1a\x16common/v1/common.proto\"9\n" +
|
||||
"\x1aRemoveClientConnectionsReq\x12\x1b\n" +
|
||||
"\tclient_id\x18\x01 \x01(\tR\bclientId\"\x1c\n" +
|
||||
"\x1aRemoveClientConnectionsRes\"I\n" +
|
||||
"\x1fUnsetParentGroupFromChannelsReq\x12&\n" +
|
||||
"\x0fparent_group_id\x18\x01 \x01(\tR\rparentGroupId\"!\n" +
|
||||
"\x1fUnsetParentGroupFromChannelsRes\"\x98\x01\n" +
|
||||
"\bAuthzReq\x12\x1b\n" +
|
||||
"\tdomain_id\x18\x01 \x01(\tR\bdomainId\x12\x1b\n" +
|
||||
"\tclient_id\x18\x02 \x01(\tR\bclientId\x12\x1f\n" +
|
||||
"\vclient_type\x18\x03 \x01(\tR\n" +
|
||||
"clientType\x12\x1d\n" +
|
||||
"\n" +
|
||||
"channel_id\x18\x04 \x01(\tR\tchannelId\x12\x12\n" +
|
||||
"\x04type\x18\x05 \x01(\rR\x04type\"*\n" +
|
||||
"\bAuthzRes\x12\x1e\n" +
|
||||
"\n" +
|
||||
"authorized\x18\x01 \x01(\bR\n" +
|
||||
"authorized2\xe1\x03\n" +
|
||||
"\x0fChannelsService\x12;\n" +
|
||||
"\tAuthorize\x12\x15.channels.v1.AuthzReq\x1a\x15.channels.v1.AuthzRes\"\x00\x12m\n" +
|
||||
"\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"
|
||||
|
||||
var (
|
||||
file_channels_v1_channels_proto_rawDescOnce sync.Once
|
||||
file_channels_v1_channels_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_channels_v1_channels_proto_rawDescGZIP() []byte {
|
||||
file_channels_v1_channels_proto_rawDescOnce.Do(func() {
|
||||
file_channels_v1_channels_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_channels_v1_channels_proto_rawDesc), len(file_channels_v1_channels_proto_rawDesc)))
|
||||
})
|
||||
return file_channels_v1_channels_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_channels_v1_channels_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
||||
var file_channels_v1_channels_proto_goTypes = []any{
|
||||
(*RemoveClientConnectionsReq)(nil), // 0: channels.v1.RemoveClientConnectionsReq
|
||||
(*RemoveClientConnectionsRes)(nil), // 1: channels.v1.RemoveClientConnectionsRes
|
||||
(*UnsetParentGroupFromChannelsReq)(nil), // 2: channels.v1.UnsetParentGroupFromChannelsReq
|
||||
(*UnsetParentGroupFromChannelsRes)(nil), // 3: channels.v1.UnsetParentGroupFromChannelsRes
|
||||
(*AuthzReq)(nil), // 4: channels.v1.AuthzReq
|
||||
(*AuthzRes)(nil), // 5: channels.v1.AuthzRes
|
||||
(*v1.RetrieveEntityReq)(nil), // 6: common.v1.RetrieveEntityReq
|
||||
(*v1.RetrieveIDByRouteReq)(nil), // 7: common.v1.RetrieveIDByRouteReq
|
||||
(*v1.RetrieveEntityRes)(nil), // 8: common.v1.RetrieveEntityRes
|
||||
}
|
||||
var file_channels_v1_channels_proto_depIdxs = []int32{
|
||||
4, // 0: channels.v1.ChannelsService.Authorize:input_type -> channels.v1.AuthzReq
|
||||
0, // 1: channels.v1.ChannelsService.RemoveClientConnections:input_type -> channels.v1.RemoveClientConnectionsReq
|
||||
2, // 2: channels.v1.ChannelsService.UnsetParentGroupFromChannels:input_type -> channels.v1.UnsetParentGroupFromChannelsReq
|
||||
6, // 3: channels.v1.ChannelsService.RetrieveEntity:input_type -> common.v1.RetrieveEntityReq
|
||||
7, // 4: channels.v1.ChannelsService.RetrieveIDByRoute:input_type -> common.v1.RetrieveIDByRouteReq
|
||||
5, // 5: channels.v1.ChannelsService.Authorize:output_type -> channels.v1.AuthzRes
|
||||
1, // 6: channels.v1.ChannelsService.RemoveClientConnections:output_type -> channels.v1.RemoveClientConnectionsRes
|
||||
3, // 7: channels.v1.ChannelsService.UnsetParentGroupFromChannels:output_type -> channels.v1.UnsetParentGroupFromChannelsRes
|
||||
8, // 8: channels.v1.ChannelsService.RetrieveEntity:output_type -> common.v1.RetrieveEntityRes
|
||||
8, // 9: channels.v1.ChannelsService.RetrieveIDByRoute:output_type -> common.v1.RetrieveEntityRes
|
||||
5, // [5:10] is the sub-list for method output_type
|
||||
0, // [0:5] 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_channels_v1_channels_proto_init() }
|
||||
func file_channels_v1_channels_proto_init() {
|
||||
if File_channels_v1_channels_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_channels_v1_channels_proto_rawDesc), len(file_channels_v1_channels_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 6,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_channels_v1_channels_proto_goTypes,
|
||||
DependencyIndexes: file_channels_v1_channels_proto_depIdxs,
|
||||
MessageInfos: file_channels_v1_channels_proto_msgTypes,
|
||||
}.Build()
|
||||
File_channels_v1_channels_proto = out.File
|
||||
file_channels_v1_channels_proto_goTypes = nil
|
||||
file_channels_v1_channels_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
// 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.0
|
||||
// - protoc v6.33.0
|
||||
// source: channels/v1/channels.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
context "context"
|
||||
v1 "github.com/absmach/supermq/api/grpc/common/v1"
|
||||
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 (
|
||||
ChannelsService_Authorize_FullMethodName = "/channels.v1.ChannelsService/Authorize"
|
||||
ChannelsService_RemoveClientConnections_FullMethodName = "/channels.v1.ChannelsService/RemoveClientConnections"
|
||||
ChannelsService_UnsetParentGroupFromChannels_FullMethodName = "/channels.v1.ChannelsService/UnsetParentGroupFromChannels"
|
||||
ChannelsService_RetrieveEntity_FullMethodName = "/channels.v1.ChannelsService/RetrieveEntity"
|
||||
ChannelsService_RetrieveIDByRoute_FullMethodName = "/channels.v1.ChannelsService/RetrieveIDByRoute"
|
||||
)
|
||||
|
||||
// ChannelsServiceClient is the client API for ChannelsService 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 ChannelsServiceClient interface {
|
||||
Authorize(ctx context.Context, in *AuthzReq, opts ...grpc.CallOption) (*AuthzRes, error)
|
||||
RemoveClientConnections(ctx context.Context, in *RemoveClientConnectionsReq, opts ...grpc.CallOption) (*RemoveClientConnectionsRes, error)
|
||||
UnsetParentGroupFromChannels(ctx context.Context, in *UnsetParentGroupFromChannelsReq, opts ...grpc.CallOption) (*UnsetParentGroupFromChannelsRes, error)
|
||||
RetrieveEntity(ctx context.Context, in *v1.RetrieveEntityReq, opts ...grpc.CallOption) (*v1.RetrieveEntityRes, error)
|
||||
RetrieveIDByRoute(ctx context.Context, in *v1.RetrieveIDByRouteReq, opts ...grpc.CallOption) (*v1.RetrieveEntityRes, error)
|
||||
}
|
||||
|
||||
type channelsServiceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewChannelsServiceClient(cc grpc.ClientConnInterface) ChannelsServiceClient {
|
||||
return &channelsServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *channelsServiceClient) Authorize(ctx context.Context, in *AuthzReq, opts ...grpc.CallOption) (*AuthzRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(AuthzRes)
|
||||
err := c.cc.Invoke(ctx, ChannelsService_Authorize_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *channelsServiceClient) RemoveClientConnections(ctx context.Context, in *RemoveClientConnectionsReq, opts ...grpc.CallOption) (*RemoveClientConnectionsRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(RemoveClientConnectionsRes)
|
||||
err := c.cc.Invoke(ctx, ChannelsService_RemoveClientConnections_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *channelsServiceClient) UnsetParentGroupFromChannels(ctx context.Context, in *UnsetParentGroupFromChannelsReq, opts ...grpc.CallOption) (*UnsetParentGroupFromChannelsRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(UnsetParentGroupFromChannelsRes)
|
||||
err := c.cc.Invoke(ctx, ChannelsService_UnsetParentGroupFromChannels_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *channelsServiceClient) RetrieveEntity(ctx context.Context, in *v1.RetrieveEntityReq, opts ...grpc.CallOption) (*v1.RetrieveEntityRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(v1.RetrieveEntityRes)
|
||||
err := c.cc.Invoke(ctx, ChannelsService_RetrieveEntity_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *channelsServiceClient) RetrieveIDByRoute(ctx context.Context, in *v1.RetrieveIDByRouteReq, opts ...grpc.CallOption) (*v1.RetrieveEntityRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(v1.RetrieveEntityRes)
|
||||
err := c.cc.Invoke(ctx, ChannelsService_RetrieveIDByRoute_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ChannelsServiceServer is the server API for ChannelsService service.
|
||||
// All implementations must embed UnimplementedChannelsServiceServer
|
||||
// for forward compatibility.
|
||||
type ChannelsServiceServer interface {
|
||||
Authorize(context.Context, *AuthzReq) (*AuthzRes, error)
|
||||
RemoveClientConnections(context.Context, *RemoveClientConnectionsReq) (*RemoveClientConnectionsRes, error)
|
||||
UnsetParentGroupFromChannels(context.Context, *UnsetParentGroupFromChannelsReq) (*UnsetParentGroupFromChannelsRes, error)
|
||||
RetrieveEntity(context.Context, *v1.RetrieveEntityReq) (*v1.RetrieveEntityRes, error)
|
||||
RetrieveIDByRoute(context.Context, *v1.RetrieveIDByRouteReq) (*v1.RetrieveEntityRes, error)
|
||||
mustEmbedUnimplementedChannelsServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedChannelsServiceServer 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 UnimplementedChannelsServiceServer struct{}
|
||||
|
||||
func (UnimplementedChannelsServiceServer) Authorize(context.Context, *AuthzReq) (*AuthzRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method Authorize not implemented")
|
||||
}
|
||||
func (UnimplementedChannelsServiceServer) RemoveClientConnections(context.Context, *RemoveClientConnectionsReq) (*RemoveClientConnectionsRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method RemoveClientConnections not implemented")
|
||||
}
|
||||
func (UnimplementedChannelsServiceServer) UnsetParentGroupFromChannels(context.Context, *UnsetParentGroupFromChannelsReq) (*UnsetParentGroupFromChannelsRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method UnsetParentGroupFromChannels not implemented")
|
||||
}
|
||||
func (UnimplementedChannelsServiceServer) RetrieveEntity(context.Context, *v1.RetrieveEntityReq) (*v1.RetrieveEntityRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method RetrieveEntity not implemented")
|
||||
}
|
||||
func (UnimplementedChannelsServiceServer) RetrieveIDByRoute(context.Context, *v1.RetrieveIDByRouteReq) (*v1.RetrieveEntityRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method RetrieveIDByRoute not implemented")
|
||||
}
|
||||
func (UnimplementedChannelsServiceServer) mustEmbedUnimplementedChannelsServiceServer() {}
|
||||
func (UnimplementedChannelsServiceServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeChannelsServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to ChannelsServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeChannelsServiceServer interface {
|
||||
mustEmbedUnimplementedChannelsServiceServer()
|
||||
}
|
||||
|
||||
func RegisterChannelsServiceServer(s grpc.ServiceRegistrar, srv ChannelsServiceServer) {
|
||||
// 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.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&ChannelsService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _ChannelsService_Authorize_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(AuthzReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ChannelsServiceServer).Authorize(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ChannelsService_Authorize_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ChannelsServiceServer).Authorize(ctx, req.(*AuthzReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ChannelsService_RemoveClientConnections_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(RemoveClientConnectionsReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ChannelsServiceServer).RemoveClientConnections(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ChannelsService_RemoveClientConnections_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ChannelsServiceServer).RemoveClientConnections(ctx, req.(*RemoveClientConnectionsReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ChannelsService_UnsetParentGroupFromChannels_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(UnsetParentGroupFromChannelsReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ChannelsServiceServer).UnsetParentGroupFromChannels(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ChannelsService_UnsetParentGroupFromChannels_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ChannelsServiceServer).UnsetParentGroupFromChannels(ctx, req.(*UnsetParentGroupFromChannelsReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ChannelsService_RetrieveEntity_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(v1.RetrieveEntityReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ChannelsServiceServer).RetrieveEntity(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ChannelsService_RetrieveEntity_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ChannelsServiceServer).RetrieveEntity(ctx, req.(*v1.RetrieveEntityReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ChannelsService_RetrieveIDByRoute_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(v1.RetrieveIDByRouteReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ChannelsServiceServer).RetrieveIDByRoute(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ChannelsService_RetrieveIDByRoute_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ChannelsServiceServer).RetrieveIDByRoute(ctx, req.(*v1.RetrieveIDByRouteReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// ChannelsService_ServiceDesc is the grpc.ServiceDesc for ChannelsService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var ChannelsService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "channels.v1.ChannelsService",
|
||||
HandlerType: (*ChannelsServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Authorize",
|
||||
Handler: _ChannelsService_Authorize_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "RemoveClientConnections",
|
||||
Handler: _ChannelsService_RemoveClientConnections_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "UnsetParentGroupFromChannels",
|
||||
Handler: _ChannelsService_UnsetParentGroupFromChannels_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "RetrieveEntity",
|
||||
Handler: _ChannelsService_RetrieveEntity_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "RetrieveIDByRoute",
|
||||
Handler: _ChannelsService_RetrieveIDByRoute_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "channels/v1/channels.proto",
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
// 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 v6.33.0
|
||||
// source: clients/v1/clients.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
v1 "github.com/absmach/supermq/api/grpc/common/v1"
|
||||
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)
|
||||
)
|
||||
|
||||
type AuthnReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *AuthnReq) Reset() {
|
||||
*x = AuthnReq{}
|
||||
mi := &file_clients_v1_clients_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *AuthnReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AuthnReq) ProtoMessage() {}
|
||||
|
||||
func (x *AuthnReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_clients_v1_clients_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 AuthnReq.ProtoReflect.Descriptor instead.
|
||||
func (*AuthnReq) Descriptor() ([]byte, []int) {
|
||||
return file_clients_v1_clients_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *AuthnReq) GetToken() string {
|
||||
if x != nil {
|
||||
return x.Token
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type AuthnRes struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Authenticated bool `protobuf:"varint,1,opt,name=authenticated,proto3" json:"authenticated,omitempty"`
|
||||
Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *AuthnRes) Reset() {
|
||||
*x = AuthnRes{}
|
||||
mi := &file_clients_v1_clients_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *AuthnRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AuthnRes) ProtoMessage() {}
|
||||
|
||||
func (x *AuthnRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_clients_v1_clients_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 AuthnRes.ProtoReflect.Descriptor instead.
|
||||
func (*AuthnRes) Descriptor() ([]byte, []int) {
|
||||
return file_clients_v1_clients_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *AuthnRes) GetAuthenticated() bool {
|
||||
if x != nil {
|
||||
return x.Authenticated
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *AuthnRes) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type RemoveChannelConnectionsReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
ChannelId string `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RemoveChannelConnectionsReq) Reset() {
|
||||
*x = RemoveChannelConnectionsReq{}
|
||||
mi := &file_clients_v1_clients_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *RemoveChannelConnectionsReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RemoveChannelConnectionsReq) ProtoMessage() {}
|
||||
|
||||
func (x *RemoveChannelConnectionsReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_clients_v1_clients_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 RemoveChannelConnectionsReq.ProtoReflect.Descriptor instead.
|
||||
func (*RemoveChannelConnectionsReq) Descriptor() ([]byte, []int) {
|
||||
return file_clients_v1_clients_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *RemoveChannelConnectionsReq) GetChannelId() string {
|
||||
if x != nil {
|
||||
return x.ChannelId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type RemoveChannelConnectionsRes struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RemoveChannelConnectionsRes) Reset() {
|
||||
*x = RemoveChannelConnectionsRes{}
|
||||
mi := &file_clients_v1_clients_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *RemoveChannelConnectionsRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RemoveChannelConnectionsRes) ProtoMessage() {}
|
||||
|
||||
func (x *RemoveChannelConnectionsRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_clients_v1_clients_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 RemoveChannelConnectionsRes.ProtoReflect.Descriptor instead.
|
||||
func (*RemoveChannelConnectionsRes) Descriptor() ([]byte, []int) {
|
||||
return file_clients_v1_clients_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
type UnsetParentGroupFromClientReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
ParentGroupId string `protobuf:"bytes,1,opt,name=parent_group_id,json=parentGroupId,proto3" json:"parent_group_id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *UnsetParentGroupFromClientReq) Reset() {
|
||||
*x = UnsetParentGroupFromClientReq{}
|
||||
mi := &file_clients_v1_clients_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *UnsetParentGroupFromClientReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*UnsetParentGroupFromClientReq) ProtoMessage() {}
|
||||
|
||||
func (x *UnsetParentGroupFromClientReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_clients_v1_clients_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 UnsetParentGroupFromClientReq.ProtoReflect.Descriptor instead.
|
||||
func (*UnsetParentGroupFromClientReq) Descriptor() ([]byte, []int) {
|
||||
return file_clients_v1_clients_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *UnsetParentGroupFromClientReq) GetParentGroupId() string {
|
||||
if x != nil {
|
||||
return x.ParentGroupId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type UnsetParentGroupFromClientRes struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *UnsetParentGroupFromClientRes) Reset() {
|
||||
*x = UnsetParentGroupFromClientRes{}
|
||||
mi := &file_clients_v1_clients_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *UnsetParentGroupFromClientRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*UnsetParentGroupFromClientRes) ProtoMessage() {}
|
||||
|
||||
func (x *UnsetParentGroupFromClientRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_clients_v1_clients_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 UnsetParentGroupFromClientRes.ProtoReflect.Descriptor instead.
|
||||
func (*UnsetParentGroupFromClientRes) Descriptor() ([]byte, []int) {
|
||||
return file_clients_v1_clients_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
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\" \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" +
|
||||
"\x1bRemoveChannelConnectionsReq\x12\x1d\n" +
|
||||
"\n" +
|
||||
"channel_id\x18\x01 \x01(\tR\tchannelId\"\x1d\n" +
|
||||
"\x1bRemoveChannelConnectionsRes\"G\n" +
|
||||
"\x1dUnsetParentGroupFromClientReq\x12&\n" +
|
||||
"\x0fparent_group_id\x18\x01 \x01(\tR\rparentGroupId\"\x1f\n" +
|
||||
"\x1dUnsetParentGroupFromClientRes2\x83\x05\n" +
|
||||
"\x0eClientsService\x12<\n" +
|
||||
"\fAuthenticate\x12\x14.clients.v1.AuthnReq\x1a\x14.clients.v1.AuthnRes\"\x00\x12N\n" +
|
||||
"\x0eRetrieveEntity\x12\x1c.common.v1.RetrieveEntityReq\x1a\x1c.common.v1.RetrieveEntityRes\"\x00\x12T\n" +
|
||||
"\x10RetrieveEntities\x12\x1e.common.v1.RetrieveEntitiesReq\x1a\x1e.common.v1.RetrieveEntitiesRes\"\x00\x12N\n" +
|
||||
"\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"
|
||||
|
||||
var (
|
||||
file_clients_v1_clients_proto_rawDescOnce sync.Once
|
||||
file_clients_v1_clients_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_clients_v1_clients_proto_rawDescGZIP() []byte {
|
||||
file_clients_v1_clients_proto_rawDescOnce.Do(func() {
|
||||
file_clients_v1_clients_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_clients_v1_clients_proto_rawDesc), len(file_clients_v1_clients_proto_rawDesc)))
|
||||
})
|
||||
return file_clients_v1_clients_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_clients_v1_clients_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
||||
var file_clients_v1_clients_proto_goTypes = []any{
|
||||
(*AuthnReq)(nil), // 0: clients.v1.AuthnReq
|
||||
(*AuthnRes)(nil), // 1: clients.v1.AuthnRes
|
||||
(*RemoveChannelConnectionsReq)(nil), // 2: clients.v1.RemoveChannelConnectionsReq
|
||||
(*RemoveChannelConnectionsRes)(nil), // 3: clients.v1.RemoveChannelConnectionsRes
|
||||
(*UnsetParentGroupFromClientReq)(nil), // 4: clients.v1.UnsetParentGroupFromClientReq
|
||||
(*UnsetParentGroupFromClientRes)(nil), // 5: clients.v1.UnsetParentGroupFromClientRes
|
||||
(*v1.RetrieveEntityReq)(nil), // 6: common.v1.RetrieveEntityReq
|
||||
(*v1.RetrieveEntitiesReq)(nil), // 7: common.v1.RetrieveEntitiesReq
|
||||
(*v1.AddConnectionsReq)(nil), // 8: common.v1.AddConnectionsReq
|
||||
(*v1.RemoveConnectionsReq)(nil), // 9: common.v1.RemoveConnectionsReq
|
||||
(*v1.RetrieveEntityRes)(nil), // 10: common.v1.RetrieveEntityRes
|
||||
(*v1.RetrieveEntitiesRes)(nil), // 11: common.v1.RetrieveEntitiesRes
|
||||
(*v1.AddConnectionsRes)(nil), // 12: common.v1.AddConnectionsRes
|
||||
(*v1.RemoveConnectionsRes)(nil), // 13: common.v1.RemoveConnectionsRes
|
||||
}
|
||||
var file_clients_v1_clients_proto_depIdxs = []int32{
|
||||
0, // 0: clients.v1.ClientsService.Authenticate:input_type -> clients.v1.AuthnReq
|
||||
6, // 1: clients.v1.ClientsService.RetrieveEntity:input_type -> common.v1.RetrieveEntityReq
|
||||
7, // 2: clients.v1.ClientsService.RetrieveEntities:input_type -> common.v1.RetrieveEntitiesReq
|
||||
8, // 3: clients.v1.ClientsService.AddConnections:input_type -> common.v1.AddConnectionsReq
|
||||
9, // 4: clients.v1.ClientsService.RemoveConnections:input_type -> common.v1.RemoveConnectionsReq
|
||||
2, // 5: clients.v1.ClientsService.RemoveChannelConnections:input_type -> clients.v1.RemoveChannelConnectionsReq
|
||||
4, // 6: clients.v1.ClientsService.UnsetParentGroupFromClient:input_type -> clients.v1.UnsetParentGroupFromClientReq
|
||||
1, // 7: clients.v1.ClientsService.Authenticate:output_type -> clients.v1.AuthnRes
|
||||
10, // 8: clients.v1.ClientsService.RetrieveEntity:output_type -> common.v1.RetrieveEntityRes
|
||||
11, // 9: clients.v1.ClientsService.RetrieveEntities:output_type -> common.v1.RetrieveEntitiesRes
|
||||
12, // 10: clients.v1.ClientsService.AddConnections:output_type -> common.v1.AddConnectionsRes
|
||||
13, // 11: clients.v1.ClientsService.RemoveConnections:output_type -> common.v1.RemoveConnectionsRes
|
||||
3, // 12: clients.v1.ClientsService.RemoveChannelConnections:output_type -> clients.v1.RemoveChannelConnectionsRes
|
||||
5, // 13: clients.v1.ClientsService.UnsetParentGroupFromClient:output_type -> clients.v1.UnsetParentGroupFromClientRes
|
||||
7, // [7:14] is the sub-list for method output_type
|
||||
0, // [0:7] 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_clients_v1_clients_proto_init() }
|
||||
func file_clients_v1_clients_proto_init() {
|
||||
if File_clients_v1_clients_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_clients_v1_clients_proto_rawDesc), len(file_clients_v1_clients_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 6,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_clients_v1_clients_proto_goTypes,
|
||||
DependencyIndexes: file_clients_v1_clients_proto_depIdxs,
|
||||
MessageInfos: file_clients_v1_clients_proto_msgTypes,
|
||||
}.Build()
|
||||
File_clients_v1_clients_proto = out.File
|
||||
file_clients_v1_clients_proto_goTypes = nil
|
||||
file_clients_v1_clients_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
// 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.0
|
||||
// - protoc v6.33.0
|
||||
// source: clients/v1/clients.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
context "context"
|
||||
v1 "github.com/absmach/supermq/api/grpc/common/v1"
|
||||
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 (
|
||||
ClientsService_Authenticate_FullMethodName = "/clients.v1.ClientsService/Authenticate"
|
||||
ClientsService_RetrieveEntity_FullMethodName = "/clients.v1.ClientsService/RetrieveEntity"
|
||||
ClientsService_RetrieveEntities_FullMethodName = "/clients.v1.ClientsService/RetrieveEntities"
|
||||
ClientsService_AddConnections_FullMethodName = "/clients.v1.ClientsService/AddConnections"
|
||||
ClientsService_RemoveConnections_FullMethodName = "/clients.v1.ClientsService/RemoveConnections"
|
||||
ClientsService_RemoveChannelConnections_FullMethodName = "/clients.v1.ClientsService/RemoveChannelConnections"
|
||||
ClientsService_UnsetParentGroupFromClient_FullMethodName = "/clients.v1.ClientsService/UnsetParentGroupFromClient"
|
||||
)
|
||||
|
||||
// ClientsServiceClient is the client API for ClientsService 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.
|
||||
//
|
||||
// ClientsService is a service that provides clients
|
||||
// authorization functionalities for SuperMQ services.
|
||||
type ClientsServiceClient interface {
|
||||
// Authorize checks if the client is authorized to perform
|
||||
Authenticate(ctx context.Context, in *AuthnReq, opts ...grpc.CallOption) (*AuthnRes, error)
|
||||
RetrieveEntity(ctx context.Context, in *v1.RetrieveEntityReq, opts ...grpc.CallOption) (*v1.RetrieveEntityRes, error)
|
||||
RetrieveEntities(ctx context.Context, in *v1.RetrieveEntitiesReq, opts ...grpc.CallOption) (*v1.RetrieveEntitiesRes, error)
|
||||
AddConnections(ctx context.Context, in *v1.AddConnectionsReq, opts ...grpc.CallOption) (*v1.AddConnectionsRes, error)
|
||||
RemoveConnections(ctx context.Context, in *v1.RemoveConnectionsReq, opts ...grpc.CallOption) (*v1.RemoveConnectionsRes, error)
|
||||
RemoveChannelConnections(ctx context.Context, in *RemoveChannelConnectionsReq, opts ...grpc.CallOption) (*RemoveChannelConnectionsRes, error)
|
||||
UnsetParentGroupFromClient(ctx context.Context, in *UnsetParentGroupFromClientReq, opts ...grpc.CallOption) (*UnsetParentGroupFromClientRes, error)
|
||||
}
|
||||
|
||||
type clientsServiceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewClientsServiceClient(cc grpc.ClientConnInterface) ClientsServiceClient {
|
||||
return &clientsServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *clientsServiceClient) Authenticate(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, ClientsService_Authenticate_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *clientsServiceClient) RetrieveEntity(ctx context.Context, in *v1.RetrieveEntityReq, opts ...grpc.CallOption) (*v1.RetrieveEntityRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(v1.RetrieveEntityRes)
|
||||
err := c.cc.Invoke(ctx, ClientsService_RetrieveEntity_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *clientsServiceClient) RetrieveEntities(ctx context.Context, in *v1.RetrieveEntitiesReq, opts ...grpc.CallOption) (*v1.RetrieveEntitiesRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(v1.RetrieveEntitiesRes)
|
||||
err := c.cc.Invoke(ctx, ClientsService_RetrieveEntities_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *clientsServiceClient) AddConnections(ctx context.Context, in *v1.AddConnectionsReq, opts ...grpc.CallOption) (*v1.AddConnectionsRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(v1.AddConnectionsRes)
|
||||
err := c.cc.Invoke(ctx, ClientsService_AddConnections_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *clientsServiceClient) RemoveConnections(ctx context.Context, in *v1.RemoveConnectionsReq, opts ...grpc.CallOption) (*v1.RemoveConnectionsRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(v1.RemoveConnectionsRes)
|
||||
err := c.cc.Invoke(ctx, ClientsService_RemoveConnections_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *clientsServiceClient) RemoveChannelConnections(ctx context.Context, in *RemoveChannelConnectionsReq, opts ...grpc.CallOption) (*RemoveChannelConnectionsRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(RemoveChannelConnectionsRes)
|
||||
err := c.cc.Invoke(ctx, ClientsService_RemoveChannelConnections_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *clientsServiceClient) UnsetParentGroupFromClient(ctx context.Context, in *UnsetParentGroupFromClientReq, opts ...grpc.CallOption) (*UnsetParentGroupFromClientRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(UnsetParentGroupFromClientRes)
|
||||
err := c.cc.Invoke(ctx, ClientsService_UnsetParentGroupFromClient_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ClientsServiceServer is the server API for ClientsService service.
|
||||
// All implementations must embed UnimplementedClientsServiceServer
|
||||
// for forward compatibility.
|
||||
//
|
||||
// ClientsService is a service that provides clients
|
||||
// authorization functionalities for SuperMQ services.
|
||||
type ClientsServiceServer interface {
|
||||
// Authorize checks if the client is authorized to perform
|
||||
Authenticate(context.Context, *AuthnReq) (*AuthnRes, error)
|
||||
RetrieveEntity(context.Context, *v1.RetrieveEntityReq) (*v1.RetrieveEntityRes, error)
|
||||
RetrieveEntities(context.Context, *v1.RetrieveEntitiesReq) (*v1.RetrieveEntitiesRes, error)
|
||||
AddConnections(context.Context, *v1.AddConnectionsReq) (*v1.AddConnectionsRes, error)
|
||||
RemoveConnections(context.Context, *v1.RemoveConnectionsReq) (*v1.RemoveConnectionsRes, error)
|
||||
RemoveChannelConnections(context.Context, *RemoveChannelConnectionsReq) (*RemoveChannelConnectionsRes, error)
|
||||
UnsetParentGroupFromClient(context.Context, *UnsetParentGroupFromClientReq) (*UnsetParentGroupFromClientRes, error)
|
||||
mustEmbedUnimplementedClientsServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedClientsServiceServer 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 UnimplementedClientsServiceServer struct{}
|
||||
|
||||
func (UnimplementedClientsServiceServer) Authenticate(context.Context, *AuthnReq) (*AuthnRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method Authenticate not implemented")
|
||||
}
|
||||
func (UnimplementedClientsServiceServer) RetrieveEntity(context.Context, *v1.RetrieveEntityReq) (*v1.RetrieveEntityRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method RetrieveEntity not implemented")
|
||||
}
|
||||
func (UnimplementedClientsServiceServer) RetrieveEntities(context.Context, *v1.RetrieveEntitiesReq) (*v1.RetrieveEntitiesRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method RetrieveEntities not implemented")
|
||||
}
|
||||
func (UnimplementedClientsServiceServer) AddConnections(context.Context, *v1.AddConnectionsReq) (*v1.AddConnectionsRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method AddConnections not implemented")
|
||||
}
|
||||
func (UnimplementedClientsServiceServer) RemoveConnections(context.Context, *v1.RemoveConnectionsReq) (*v1.RemoveConnectionsRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method RemoveConnections not implemented")
|
||||
}
|
||||
func (UnimplementedClientsServiceServer) RemoveChannelConnections(context.Context, *RemoveChannelConnectionsReq) (*RemoveChannelConnectionsRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method RemoveChannelConnections not implemented")
|
||||
}
|
||||
func (UnimplementedClientsServiceServer) UnsetParentGroupFromClient(context.Context, *UnsetParentGroupFromClientReq) (*UnsetParentGroupFromClientRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method UnsetParentGroupFromClient not implemented")
|
||||
}
|
||||
func (UnimplementedClientsServiceServer) mustEmbedUnimplementedClientsServiceServer() {}
|
||||
func (UnimplementedClientsServiceServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeClientsServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to ClientsServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeClientsServiceServer interface {
|
||||
mustEmbedUnimplementedClientsServiceServer()
|
||||
}
|
||||
|
||||
func RegisterClientsServiceServer(s grpc.ServiceRegistrar, srv ClientsServiceServer) {
|
||||
// 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.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&ClientsService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _ClientsService_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 {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ClientsServiceServer).Authenticate(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ClientsService_Authenticate_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ClientsServiceServer).Authenticate(ctx, req.(*AuthnReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ClientsService_RetrieveEntity_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(v1.RetrieveEntityReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ClientsServiceServer).RetrieveEntity(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ClientsService_RetrieveEntity_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ClientsServiceServer).RetrieveEntity(ctx, req.(*v1.RetrieveEntityReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ClientsService_RetrieveEntities_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(v1.RetrieveEntitiesReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ClientsServiceServer).RetrieveEntities(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ClientsService_RetrieveEntities_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ClientsServiceServer).RetrieveEntities(ctx, req.(*v1.RetrieveEntitiesReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ClientsService_AddConnections_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(v1.AddConnectionsReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ClientsServiceServer).AddConnections(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ClientsService_AddConnections_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ClientsServiceServer).AddConnections(ctx, req.(*v1.AddConnectionsReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ClientsService_RemoveConnections_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(v1.RemoveConnectionsReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ClientsServiceServer).RemoveConnections(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ClientsService_RemoveConnections_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ClientsServiceServer).RemoveConnections(ctx, req.(*v1.RemoveConnectionsReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ClientsService_RemoveChannelConnections_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(RemoveChannelConnectionsReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ClientsServiceServer).RemoveChannelConnections(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ClientsService_RemoveChannelConnections_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ClientsServiceServer).RemoveChannelConnections(ctx, req.(*RemoveChannelConnectionsReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ClientsService_UnsetParentGroupFromClient_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(UnsetParentGroupFromClientReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ClientsServiceServer).UnsetParentGroupFromClient(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ClientsService_UnsetParentGroupFromClient_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ClientsServiceServer).UnsetParentGroupFromClient(ctx, req.(*UnsetParentGroupFromClientReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// ClientsService_ServiceDesc is the grpc.ServiceDesc for ClientsService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var ClientsService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "clients.v1.ClientsService",
|
||||
HandlerType: (*ClientsServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Authenticate",
|
||||
Handler: _ClientsService_Authenticate_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "RetrieveEntity",
|
||||
Handler: _ClientsService_RetrieveEntity_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "RetrieveEntities",
|
||||
Handler: _ClientsService_RetrieveEntities_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "AddConnections",
|
||||
Handler: _ClientsService_AddConnections_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "RemoveConnections",
|
||||
Handler: _ClientsService_RemoveConnections_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "RemoveChannelConnections",
|
||||
Handler: _ClientsService_RemoveChannelConnections_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "UnsetParentGroupFromClient",
|
||||
Handler: _ClientsService_UnsetParentGroupFromClient_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "clients/v1/clients.proto",
|
||||
}
|
||||
@@ -0,0 +1,691 @@
|
||||
// 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 v6.33.0
|
||||
// source: common/v1/common.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)
|
||||
)
|
||||
|
||||
type RetrieveEntitiesReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Ids []string `protobuf:"bytes,1,rep,name=ids,proto3" json:"ids,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RetrieveEntitiesReq) Reset() {
|
||||
*x = RetrieveEntitiesReq{}
|
||||
mi := &file_common_v1_common_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *RetrieveEntitiesReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RetrieveEntitiesReq) ProtoMessage() {}
|
||||
|
||||
func (x *RetrieveEntitiesReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_common_v1_common_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 RetrieveEntitiesReq.ProtoReflect.Descriptor instead.
|
||||
func (*RetrieveEntitiesReq) Descriptor() ([]byte, []int) {
|
||||
return file_common_v1_common_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *RetrieveEntitiesReq) GetIds() []string {
|
||||
if x != nil {
|
||||
return x.Ids
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type RetrieveEntitiesRes 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"`
|
||||
Entities []*EntityBasic `protobuf:"bytes,4,rep,name=entities,proto3" json:"entities,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RetrieveEntitiesRes) Reset() {
|
||||
*x = RetrieveEntitiesRes{}
|
||||
mi := &file_common_v1_common_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *RetrieveEntitiesRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RetrieveEntitiesRes) ProtoMessage() {}
|
||||
|
||||
func (x *RetrieveEntitiesRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_common_v1_common_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 RetrieveEntitiesRes.ProtoReflect.Descriptor instead.
|
||||
func (*RetrieveEntitiesRes) Descriptor() ([]byte, []int) {
|
||||
return file_common_v1_common_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *RetrieveEntitiesRes) GetTotal() uint64 {
|
||||
if x != nil {
|
||||
return x.Total
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *RetrieveEntitiesRes) GetLimit() uint64 {
|
||||
if x != nil {
|
||||
return x.Limit
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *RetrieveEntitiesRes) GetOffset() uint64 {
|
||||
if x != nil {
|
||||
return x.Offset
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *RetrieveEntitiesRes) GetEntities() []*EntityBasic {
|
||||
if x != nil {
|
||||
return x.Entities
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type RetrieveEntityReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RetrieveEntityReq) Reset() {
|
||||
*x = RetrieveEntityReq{}
|
||||
mi := &file_common_v1_common_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *RetrieveEntityReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RetrieveEntityReq) ProtoMessage() {}
|
||||
|
||||
func (x *RetrieveEntityReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_common_v1_common_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 RetrieveEntityReq.ProtoReflect.Descriptor instead.
|
||||
func (*RetrieveEntityReq) Descriptor() ([]byte, []int) {
|
||||
return file_common_v1_common_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *RetrieveEntityReq) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type RetrieveEntityRes struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Entity *EntityBasic `protobuf:"bytes,1,opt,name=entity,proto3" json:"entity,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RetrieveEntityRes) Reset() {
|
||||
*x = RetrieveEntityRes{}
|
||||
mi := &file_common_v1_common_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *RetrieveEntityRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RetrieveEntityRes) ProtoMessage() {}
|
||||
|
||||
func (x *RetrieveEntityRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_common_v1_common_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 RetrieveEntityRes.ProtoReflect.Descriptor instead.
|
||||
func (*RetrieveEntityRes) Descriptor() ([]byte, []int) {
|
||||
return file_common_v1_common_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *RetrieveEntityRes) GetEntity() *EntityBasic {
|
||||
if x != nil {
|
||||
return x.Entity
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type EntityBasic struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
DomainId string `protobuf:"bytes,2,opt,name=domain_id,json=domainId,proto3" json:"domain_id,omitempty"`
|
||||
ParentGroupId string `protobuf:"bytes,3,opt,name=parent_group_id,json=parentGroupId,proto3" json:"parent_group_id,omitempty"`
|
||||
Status uint32 `protobuf:"varint,4,opt,name=status,proto3" json:"status,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *EntityBasic) Reset() {
|
||||
*x = EntityBasic{}
|
||||
mi := &file_common_v1_common_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *EntityBasic) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*EntityBasic) ProtoMessage() {}
|
||||
|
||||
func (x *EntityBasic) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_common_v1_common_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 EntityBasic.ProtoReflect.Descriptor instead.
|
||||
func (*EntityBasic) Descriptor() ([]byte, []int) {
|
||||
return file_common_v1_common_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *EntityBasic) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *EntityBasic) GetDomainId() string {
|
||||
if x != nil {
|
||||
return x.DomainId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *EntityBasic) GetParentGroupId() string {
|
||||
if x != nil {
|
||||
return x.ParentGroupId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *EntityBasic) GetStatus() uint32 {
|
||||
if x != nil {
|
||||
return x.Status
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type AddConnectionsReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Connections []*Connection `protobuf:"bytes,1,rep,name=connections,proto3" json:"connections,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *AddConnectionsReq) Reset() {
|
||||
*x = AddConnectionsReq{}
|
||||
mi := &file_common_v1_common_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *AddConnectionsReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AddConnectionsReq) ProtoMessage() {}
|
||||
|
||||
func (x *AddConnectionsReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_common_v1_common_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 AddConnectionsReq.ProtoReflect.Descriptor instead.
|
||||
func (*AddConnectionsReq) Descriptor() ([]byte, []int) {
|
||||
return file_common_v1_common_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *AddConnectionsReq) GetConnections() []*Connection {
|
||||
if x != nil {
|
||||
return x.Connections
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type AddConnectionsRes struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Ok bool `protobuf:"varint,1,opt,name=ok,proto3" json:"ok,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *AddConnectionsRes) Reset() {
|
||||
*x = AddConnectionsRes{}
|
||||
mi := &file_common_v1_common_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *AddConnectionsRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AddConnectionsRes) ProtoMessage() {}
|
||||
|
||||
func (x *AddConnectionsRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_common_v1_common_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 AddConnectionsRes.ProtoReflect.Descriptor instead.
|
||||
func (*AddConnectionsRes) Descriptor() ([]byte, []int) {
|
||||
return file_common_v1_common_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *AddConnectionsRes) GetOk() bool {
|
||||
if x != nil {
|
||||
return x.Ok
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type RemoveConnectionsReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Connections []*Connection `protobuf:"bytes,1,rep,name=connections,proto3" json:"connections,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RemoveConnectionsReq) Reset() {
|
||||
*x = RemoveConnectionsReq{}
|
||||
mi := &file_common_v1_common_proto_msgTypes[7]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *RemoveConnectionsReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RemoveConnectionsReq) ProtoMessage() {}
|
||||
|
||||
func (x *RemoveConnectionsReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_common_v1_common_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 RemoveConnectionsReq.ProtoReflect.Descriptor instead.
|
||||
func (*RemoveConnectionsReq) Descriptor() ([]byte, []int) {
|
||||
return file_common_v1_common_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
func (x *RemoveConnectionsReq) GetConnections() []*Connection {
|
||||
if x != nil {
|
||||
return x.Connections
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type RemoveConnectionsRes struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Ok bool `protobuf:"varint,1,opt,name=ok,proto3" json:"ok,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RemoveConnectionsRes) Reset() {
|
||||
*x = RemoveConnectionsRes{}
|
||||
mi := &file_common_v1_common_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *RemoveConnectionsRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RemoveConnectionsRes) ProtoMessage() {}
|
||||
|
||||
func (x *RemoveConnectionsRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_common_v1_common_proto_msgTypes[8]
|
||||
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 RemoveConnectionsRes.ProtoReflect.Descriptor instead.
|
||||
func (*RemoveConnectionsRes) Descriptor() ([]byte, []int) {
|
||||
return file_common_v1_common_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *RemoveConnectionsRes) GetOk() bool {
|
||||
if x != nil {
|
||||
return x.Ok
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type Connection struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"`
|
||||
ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
|
||||
DomainId string `protobuf:"bytes,3,opt,name=domain_id,json=domainId,proto3" json:"domain_id,omitempty"`
|
||||
Type uint32 `protobuf:"varint,4,opt,name=type,proto3" json:"type,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Connection) Reset() {
|
||||
*x = Connection{}
|
||||
mi := &file_common_v1_common_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Connection) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Connection) ProtoMessage() {}
|
||||
|
||||
func (x *Connection) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_common_v1_common_proto_msgTypes[9]
|
||||
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 Connection.ProtoReflect.Descriptor instead.
|
||||
func (*Connection) Descriptor() ([]byte, []int) {
|
||||
return file_common_v1_common_proto_rawDescGZIP(), []int{9}
|
||||
}
|
||||
|
||||
func (x *Connection) GetClientId() string {
|
||||
if x != nil {
|
||||
return x.ClientId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Connection) GetChannelId() string {
|
||||
if x != nil {
|
||||
return x.ChannelId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Connection) GetDomainId() string {
|
||||
if x != nil {
|
||||
return x.DomainId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Connection) GetType() uint32 {
|
||||
if x != nil {
|
||||
return x.Type
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type RetrieveIDByRouteReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Route string `protobuf:"bytes,1,opt,name=route,proto3" json:"route,omitempty"`
|
||||
DomainId string `protobuf:"bytes,2,opt,name=domain_id,json=domainId,proto3" json:"domain_id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RetrieveIDByRouteReq) Reset() {
|
||||
*x = RetrieveIDByRouteReq{}
|
||||
mi := &file_common_v1_common_proto_msgTypes[10]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *RetrieveIDByRouteReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RetrieveIDByRouteReq) ProtoMessage() {}
|
||||
|
||||
func (x *RetrieveIDByRouteReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_common_v1_common_proto_msgTypes[10]
|
||||
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 RetrieveIDByRouteReq.ProtoReflect.Descriptor instead.
|
||||
func (*RetrieveIDByRouteReq) Descriptor() ([]byte, []int) {
|
||||
return file_common_v1_common_proto_rawDescGZIP(), []int{10}
|
||||
}
|
||||
|
||||
func (x *RetrieveIDByRouteReq) GetRoute() string {
|
||||
if x != nil {
|
||||
return x.Route
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *RetrieveIDByRouteReq) GetDomainId() string {
|
||||
if x != nil {
|
||||
return x.DomainId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_common_v1_common_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_common_v1_common_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x16common/v1/common.proto\x12\tcommon.v1\"'\n" +
|
||||
"\x13RetrieveEntitiesReq\x12\x10\n" +
|
||||
"\x03ids\x18\x01 \x03(\tR\x03ids\"\x8d\x01\n" +
|
||||
"\x13RetrieveEntitiesRes\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\x122\n" +
|
||||
"\bentities\x18\x04 \x03(\v2\x16.common.v1.EntityBasicR\bentities\"#\n" +
|
||||
"\x11RetrieveEntityReq\x12\x0e\n" +
|
||||
"\x02id\x18\x01 \x01(\tR\x02id\"C\n" +
|
||||
"\x11RetrieveEntityRes\x12.\n" +
|
||||
"\x06entity\x18\x01 \x01(\v2\x16.common.v1.EntityBasicR\x06entity\"z\n" +
|
||||
"\vEntityBasic\x12\x0e\n" +
|
||||
"\x02id\x18\x01 \x01(\tR\x02id\x12\x1b\n" +
|
||||
"\tdomain_id\x18\x02 \x01(\tR\bdomainId\x12&\n" +
|
||||
"\x0fparent_group_id\x18\x03 \x01(\tR\rparentGroupId\x12\x16\n" +
|
||||
"\x06status\x18\x04 \x01(\rR\x06status\"L\n" +
|
||||
"\x11AddConnectionsReq\x127\n" +
|
||||
"\vconnections\x18\x01 \x03(\v2\x15.common.v1.ConnectionR\vconnections\"#\n" +
|
||||
"\x11AddConnectionsRes\x12\x0e\n" +
|
||||
"\x02ok\x18\x01 \x01(\bR\x02ok\"O\n" +
|
||||
"\x14RemoveConnectionsReq\x127\n" +
|
||||
"\vconnections\x18\x01 \x03(\v2\x15.common.v1.ConnectionR\vconnections\"&\n" +
|
||||
"\x14RemoveConnectionsRes\x12\x0e\n" +
|
||||
"\x02ok\x18\x01 \x01(\bR\x02ok\"y\n" +
|
||||
"\n" +
|
||||
"Connection\x12\x1b\n" +
|
||||
"\tclient_id\x18\x01 \x01(\tR\bclientId\x12\x1d\n" +
|
||||
"\n" +
|
||||
"channel_id\x18\x02 \x01(\tR\tchannelId\x12\x1b\n" +
|
||||
"\tdomain_id\x18\x03 \x01(\tR\bdomainId\x12\x12\n" +
|
||||
"\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"
|
||||
|
||||
var (
|
||||
file_common_v1_common_proto_rawDescOnce sync.Once
|
||||
file_common_v1_common_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_common_v1_common_proto_rawDescGZIP() []byte {
|
||||
file_common_v1_common_proto_rawDescOnce.Do(func() {
|
||||
file_common_v1_common_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_common_v1_common_proto_rawDesc), len(file_common_v1_common_proto_rawDesc)))
|
||||
})
|
||||
return file_common_v1_common_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_common_v1_common_proto_msgTypes = make([]protoimpl.MessageInfo, 11)
|
||||
var file_common_v1_common_proto_goTypes = []any{
|
||||
(*RetrieveEntitiesReq)(nil), // 0: common.v1.RetrieveEntitiesReq
|
||||
(*RetrieveEntitiesRes)(nil), // 1: common.v1.RetrieveEntitiesRes
|
||||
(*RetrieveEntityReq)(nil), // 2: common.v1.RetrieveEntityReq
|
||||
(*RetrieveEntityRes)(nil), // 3: common.v1.RetrieveEntityRes
|
||||
(*EntityBasic)(nil), // 4: common.v1.EntityBasic
|
||||
(*AddConnectionsReq)(nil), // 5: common.v1.AddConnectionsReq
|
||||
(*AddConnectionsRes)(nil), // 6: common.v1.AddConnectionsRes
|
||||
(*RemoveConnectionsReq)(nil), // 7: common.v1.RemoveConnectionsReq
|
||||
(*RemoveConnectionsRes)(nil), // 8: common.v1.RemoveConnectionsRes
|
||||
(*Connection)(nil), // 9: common.v1.Connection
|
||||
(*RetrieveIDByRouteReq)(nil), // 10: common.v1.RetrieveIDByRouteReq
|
||||
}
|
||||
var file_common_v1_common_proto_depIdxs = []int32{
|
||||
4, // 0: common.v1.RetrieveEntitiesRes.entities:type_name -> common.v1.EntityBasic
|
||||
4, // 1: common.v1.RetrieveEntityRes.entity:type_name -> common.v1.EntityBasic
|
||||
9, // 2: common.v1.AddConnectionsReq.connections:type_name -> common.v1.Connection
|
||||
9, // 3: common.v1.RemoveConnectionsReq.connections:type_name -> common.v1.Connection
|
||||
4, // [4:4] is the sub-list for method output_type
|
||||
4, // [4:4] is the sub-list for method input_type
|
||||
4, // [4:4] is the sub-list for extension type_name
|
||||
4, // [4:4] is the sub-list for extension extendee
|
||||
0, // [0:4] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_common_v1_common_proto_init() }
|
||||
func file_common_v1_common_proto_init() {
|
||||
if File_common_v1_common_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_common_v1_common_proto_rawDesc), len(file_common_v1_common_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 11,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_common_v1_common_proto_goTypes,
|
||||
DependencyIndexes: file_common_v1_common_proto_depIdxs,
|
||||
MessageInfos: file_common_v1_common_proto_msgTypes,
|
||||
}.Build()
|
||||
File_common_v1_common_proto = out.File
|
||||
file_common_v1_common_proto_goTypes = nil
|
||||
file_common_v1_common_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
// 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 v6.33.0
|
||||
// source: domains/v1/domains.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
v1 "github.com/absmach/supermq/api/grpc/common/v1"
|
||||
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)
|
||||
)
|
||||
|
||||
type DeleteUserRes struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Deleted bool `protobuf:"varint,1,opt,name=deleted,proto3" json:"deleted,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *DeleteUserRes) Reset() {
|
||||
*x = DeleteUserRes{}
|
||||
mi := &file_domains_v1_domains_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *DeleteUserRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*DeleteUserRes) ProtoMessage() {}
|
||||
|
||||
func (x *DeleteUserRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_domains_v1_domains_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 DeleteUserRes.ProtoReflect.Descriptor instead.
|
||||
func (*DeleteUserRes) Descriptor() ([]byte, []int) {
|
||||
return file_domains_v1_domains_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *DeleteUserRes) GetDeleted() bool {
|
||||
if x != nil {
|
||||
return x.Deleted
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type DeleteUserReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *DeleteUserReq) Reset() {
|
||||
*x = DeleteUserReq{}
|
||||
mi := &file_domains_v1_domains_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *DeleteUserReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*DeleteUserReq) ProtoMessage() {}
|
||||
|
||||
func (x *DeleteUserReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_domains_v1_domains_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 DeleteUserReq.ProtoReflect.Descriptor instead.
|
||||
func (*DeleteUserReq) Descriptor() ([]byte, []int) {
|
||||
return file_domains_v1_domains_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *DeleteUserReq) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_domains_v1_domains_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_domains_v1_domains_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x18domains/v1/domains.proto\x12\n" +
|
||||
"domains.v1\x1a\x16common/v1/common.proto\")\n" +
|
||||
"\rDeleteUserRes\x12\x18\n" +
|
||||
"\adeleted\x18\x01 \x01(\bR\adeleted\"\x1f\n" +
|
||||
"\rDeleteUserReq\x12\x0e\n" +
|
||||
"\x02id\x18\x01 \x01(\tR\x02id2\x87\x02\n" +
|
||||
"\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"
|
||||
|
||||
var (
|
||||
file_domains_v1_domains_proto_rawDescOnce sync.Once
|
||||
file_domains_v1_domains_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_domains_v1_domains_proto_rawDescGZIP() []byte {
|
||||
file_domains_v1_domains_proto_rawDescOnce.Do(func() {
|
||||
file_domains_v1_domains_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_domains_v1_domains_proto_rawDesc), len(file_domains_v1_domains_proto_rawDesc)))
|
||||
})
|
||||
return file_domains_v1_domains_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_domains_v1_domains_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_domains_v1_domains_proto_goTypes = []any{
|
||||
(*DeleteUserRes)(nil), // 0: domains.v1.DeleteUserRes
|
||||
(*DeleteUserReq)(nil), // 1: domains.v1.DeleteUserReq
|
||||
(*v1.RetrieveEntityReq)(nil), // 2: common.v1.RetrieveEntityReq
|
||||
(*v1.RetrieveIDByRouteReq)(nil), // 3: common.v1.RetrieveIDByRouteReq
|
||||
(*v1.RetrieveEntityRes)(nil), // 4: common.v1.RetrieveEntityRes
|
||||
}
|
||||
var file_domains_v1_domains_proto_depIdxs = []int32{
|
||||
1, // 0: domains.v1.DomainsService.DeleteUserFromDomains:input_type -> domains.v1.DeleteUserReq
|
||||
2, // 1: domains.v1.DomainsService.RetrieveStatus:input_type -> common.v1.RetrieveEntityReq
|
||||
3, // 2: domains.v1.DomainsService.RetrieveIDByRoute:input_type -> common.v1.RetrieveIDByRouteReq
|
||||
0, // 3: domains.v1.DomainsService.DeleteUserFromDomains:output_type -> domains.v1.DeleteUserRes
|
||||
4, // 4: domains.v1.DomainsService.RetrieveStatus:output_type -> common.v1.RetrieveEntityRes
|
||||
4, // 5: domains.v1.DomainsService.RetrieveIDByRoute:output_type -> common.v1.RetrieveEntityRes
|
||||
3, // [3:6] is the sub-list for method output_type
|
||||
0, // [0:3] 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_domains_v1_domains_proto_init() }
|
||||
func file_domains_v1_domains_proto_init() {
|
||||
if File_domains_v1_domains_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_domains_v1_domains_proto_rawDesc), len(file_domains_v1_domains_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_domains_v1_domains_proto_goTypes,
|
||||
DependencyIndexes: file_domains_v1_domains_proto_depIdxs,
|
||||
MessageInfos: file_domains_v1_domains_proto_msgTypes,
|
||||
}.Build()
|
||||
File_domains_v1_domains_proto = out.File
|
||||
file_domains_v1_domains_proto_goTypes = nil
|
||||
file_domains_v1_domains_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
// 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.0
|
||||
// - protoc v6.33.0
|
||||
// source: domains/v1/domains.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
context "context"
|
||||
v1 "github.com/absmach/supermq/api/grpc/common/v1"
|
||||
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 (
|
||||
DomainsService_DeleteUserFromDomains_FullMethodName = "/domains.v1.DomainsService/DeleteUserFromDomains"
|
||||
DomainsService_RetrieveStatus_FullMethodName = "/domains.v1.DomainsService/RetrieveStatus"
|
||||
DomainsService_RetrieveIDByRoute_FullMethodName = "/domains.v1.DomainsService/RetrieveIDByRoute"
|
||||
)
|
||||
|
||||
// DomainsServiceClient is the client API for DomainsService 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.
|
||||
//
|
||||
// DomainsService is a service that provides access to
|
||||
// domains functionalities for SuperMQ 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)
|
||||
RetrieveIDByRoute(ctx context.Context, in *v1.RetrieveIDByRouteReq, opts ...grpc.CallOption) (*v1.RetrieveEntityRes, error)
|
||||
}
|
||||
|
||||
type domainsServiceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewDomainsServiceClient(cc grpc.ClientConnInterface) DomainsServiceClient {
|
||||
return &domainsServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *domainsServiceClient) DeleteUserFromDomains(ctx context.Context, in *DeleteUserReq, opts ...grpc.CallOption) (*DeleteUserRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(DeleteUserRes)
|
||||
err := c.cc.Invoke(ctx, DomainsService_DeleteUserFromDomains_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *domainsServiceClient) RetrieveStatus(ctx context.Context, in *v1.RetrieveEntityReq, opts ...grpc.CallOption) (*v1.RetrieveEntityRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(v1.RetrieveEntityRes)
|
||||
err := c.cc.Invoke(ctx, DomainsService_RetrieveStatus_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *domainsServiceClient) RetrieveIDByRoute(ctx context.Context, in *v1.RetrieveIDByRouteReq, opts ...grpc.CallOption) (*v1.RetrieveEntityRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(v1.RetrieveEntityRes)
|
||||
err := c.cc.Invoke(ctx, DomainsService_RetrieveIDByRoute_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// DomainsServiceServer is the server API for DomainsService service.
|
||||
// All implementations must embed UnimplementedDomainsServiceServer
|
||||
// for forward compatibility.
|
||||
//
|
||||
// DomainsService is a service that provides access to
|
||||
// domains functionalities for SuperMQ services.
|
||||
type DomainsServiceServer interface {
|
||||
DeleteUserFromDomains(context.Context, *DeleteUserReq) (*DeleteUserRes, error)
|
||||
RetrieveStatus(context.Context, *v1.RetrieveEntityReq) (*v1.RetrieveEntityRes, error)
|
||||
RetrieveIDByRoute(context.Context, *v1.RetrieveIDByRouteReq) (*v1.RetrieveEntityRes, error)
|
||||
mustEmbedUnimplementedDomainsServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedDomainsServiceServer 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 UnimplementedDomainsServiceServer struct{}
|
||||
|
||||
func (UnimplementedDomainsServiceServer) DeleteUserFromDomains(context.Context, *DeleteUserReq) (*DeleteUserRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method DeleteUserFromDomains not implemented")
|
||||
}
|
||||
func (UnimplementedDomainsServiceServer) RetrieveStatus(context.Context, *v1.RetrieveEntityReq) (*v1.RetrieveEntityRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method RetrieveStatus not implemented")
|
||||
}
|
||||
func (UnimplementedDomainsServiceServer) RetrieveIDByRoute(context.Context, *v1.RetrieveIDByRouteReq) (*v1.RetrieveEntityRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method RetrieveIDByRoute not implemented")
|
||||
}
|
||||
func (UnimplementedDomainsServiceServer) mustEmbedUnimplementedDomainsServiceServer() {}
|
||||
func (UnimplementedDomainsServiceServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeDomainsServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to DomainsServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeDomainsServiceServer interface {
|
||||
mustEmbedUnimplementedDomainsServiceServer()
|
||||
}
|
||||
|
||||
func RegisterDomainsServiceServer(s grpc.ServiceRegistrar, srv DomainsServiceServer) {
|
||||
// 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.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&DomainsService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _DomainsService_DeleteUserFromDomains_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(DeleteUserReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(DomainsServiceServer).DeleteUserFromDomains(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: DomainsService_DeleteUserFromDomains_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(DomainsServiceServer).DeleteUserFromDomains(ctx, req.(*DeleteUserReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _DomainsService_RetrieveStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(v1.RetrieveEntityReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(DomainsServiceServer).RetrieveStatus(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: DomainsService_RetrieveStatus_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(DomainsServiceServer).RetrieveStatus(ctx, req.(*v1.RetrieveEntityReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _DomainsService_RetrieveIDByRoute_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(v1.RetrieveIDByRouteReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(DomainsServiceServer).RetrieveIDByRoute(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: DomainsService_RetrieveIDByRoute_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(DomainsServiceServer).RetrieveIDByRoute(ctx, req.(*v1.RetrieveIDByRouteReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// DomainsService_ServiceDesc is the grpc.ServiceDesc for DomainsService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var DomainsService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "domains.v1.DomainsService",
|
||||
HandlerType: (*DomainsServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "DeleteUserFromDomains",
|
||||
Handler: _DomainsService_DeleteUserFromDomains_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "RetrieveStatus",
|
||||
Handler: _DomainsService_RetrieveStatus_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "RetrieveIDByRoute",
|
||||
Handler: _DomainsService_RetrieveIDByRoute_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "domains/v1/domains.proto",
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
// 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 v6.33.0
|
||||
// source: groups/v1/groups.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
v1 "github.com/absmach/supermq/api/grpc/common/v1"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
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)
|
||||
)
|
||||
|
||||
var File_groups_v1_groups_proto protoreflect.FileDescriptor
|
||||
|
||||
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"
|
||||
|
||||
var file_groups_v1_groups_proto_goTypes = []any{
|
||||
(*v1.RetrieveEntityReq)(nil), // 0: common.v1.RetrieveEntityReq
|
||||
(*v1.RetrieveEntityRes)(nil), // 1: common.v1.RetrieveEntityRes
|
||||
}
|
||||
var file_groups_v1_groups_proto_depIdxs = []int32{
|
||||
0, // 0: groups.v1.GroupsService.RetrieveEntity:input_type -> common.v1.RetrieveEntityReq
|
||||
1, // 1: groups.v1.GroupsService.RetrieveEntity:output_type -> common.v1.RetrieveEntityRes
|
||||
1, // [1:2] is the sub-list for method output_type
|
||||
0, // [0:1] 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_groups_v1_groups_proto_init() }
|
||||
func file_groups_v1_groups_proto_init() {
|
||||
if File_groups_v1_groups_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_groups_v1_groups_proto_rawDesc), len(file_groups_v1_groups_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 0,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_groups_v1_groups_proto_goTypes,
|
||||
DependencyIndexes: file_groups_v1_groups_proto_depIdxs,
|
||||
}.Build()
|
||||
File_groups_v1_groups_proto = out.File
|
||||
file_groups_v1_groups_proto_goTypes = nil
|
||||
file_groups_v1_groups_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
// 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.0
|
||||
// - protoc v6.33.0
|
||||
// source: groups/v1/groups.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
context "context"
|
||||
v1 "github.com/absmach/supermq/api/grpc/common/v1"
|
||||
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 (
|
||||
GroupsService_RetrieveEntity_FullMethodName = "/groups.v1.GroupsService/RetrieveEntity"
|
||||
)
|
||||
|
||||
// GroupsServiceClient is the client API for GroupsService 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.
|
||||
//
|
||||
// GroupssService is a service that provides groups
|
||||
// functionalities for SuperMQ services.
|
||||
type GroupsServiceClient interface {
|
||||
RetrieveEntity(ctx context.Context, in *v1.RetrieveEntityReq, opts ...grpc.CallOption) (*v1.RetrieveEntityRes, error)
|
||||
}
|
||||
|
||||
type groupsServiceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewGroupsServiceClient(cc grpc.ClientConnInterface) GroupsServiceClient {
|
||||
return &groupsServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *groupsServiceClient) RetrieveEntity(ctx context.Context, in *v1.RetrieveEntityReq, opts ...grpc.CallOption) (*v1.RetrieveEntityRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(v1.RetrieveEntityRes)
|
||||
err := c.cc.Invoke(ctx, GroupsService_RetrieveEntity_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// GroupsServiceServer is the server API for GroupsService service.
|
||||
// All implementations must embed UnimplementedGroupsServiceServer
|
||||
// for forward compatibility.
|
||||
//
|
||||
// GroupssService is a service that provides groups
|
||||
// functionalities for SuperMQ services.
|
||||
type GroupsServiceServer interface {
|
||||
RetrieveEntity(context.Context, *v1.RetrieveEntityReq) (*v1.RetrieveEntityRes, error)
|
||||
mustEmbedUnimplementedGroupsServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedGroupsServiceServer 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 UnimplementedGroupsServiceServer struct{}
|
||||
|
||||
func (UnimplementedGroupsServiceServer) RetrieveEntity(context.Context, *v1.RetrieveEntityReq) (*v1.RetrieveEntityRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method RetrieveEntity not implemented")
|
||||
}
|
||||
func (UnimplementedGroupsServiceServer) mustEmbedUnimplementedGroupsServiceServer() {}
|
||||
func (UnimplementedGroupsServiceServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeGroupsServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to GroupsServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeGroupsServiceServer interface {
|
||||
mustEmbedUnimplementedGroupsServiceServer()
|
||||
}
|
||||
|
||||
func RegisterGroupsServiceServer(s grpc.ServiceRegistrar, srv GroupsServiceServer) {
|
||||
// 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.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&GroupsService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _GroupsService_RetrieveEntity_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(v1.RetrieveEntityReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(GroupsServiceServer).RetrieveEntity(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: GroupsService_RetrieveEntity_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(GroupsServiceServer).RetrieveEntity(ctx, req.(*v1.RetrieveEntityReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// GroupsService_ServiceDesc is the grpc.ServiceDesc for GroupsService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var GroupsService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "groups.v1.GroupsService",
|
||||
HandlerType: (*GroupsServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "RetrieveEntity",
|
||||
Handler: _GroupsService_RetrieveEntity_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "groups/v1/groups.proto",
|
||||
}
|
||||
@@ -0,0 +1,547 @@
|
||||
// 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 v6.33.0
|
||||
// source: token/v1/token.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)
|
||||
)
|
||||
|
||||
type IssueReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
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
|
||||
}
|
||||
|
||||
func (x *IssueReq) Reset() {
|
||||
*x = IssueReq{}
|
||||
mi := &file_token_v1_token_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *IssueReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*IssueReq) ProtoMessage() {}
|
||||
|
||||
func (x *IssueReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_token_v1_token_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 IssueReq.ProtoReflect.Descriptor instead.
|
||||
func (*IssueReq) Descriptor() ([]byte, []int) {
|
||||
return file_token_v1_token_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *IssueReq) GetUserId() string {
|
||||
if x != nil {
|
||||
return x.UserId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *IssueReq) GetUserRole() uint32 {
|
||||
if x != nil {
|
||||
return x.UserRole
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *IssueReq) GetType() uint32 {
|
||||
if x != nil {
|
||||
return x.Type
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
func (x *RefreshReq) Reset() {
|
||||
*x = RefreshReq{}
|
||||
mi := &file_token_v1_token_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *RefreshReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RefreshReq) ProtoMessage() {}
|
||||
|
||||
func (x *RefreshReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_token_v1_token_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 RefreshReq.ProtoReflect.Descriptor instead.
|
||||
func (*RefreshReq) Descriptor() ([]byte, []int) {
|
||||
return file_token_v1_token_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *RefreshReq) GetRefreshToken() string {
|
||||
if x != nil {
|
||||
return x.RefreshToken
|
||||
}
|
||||
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.
|
||||
type Token struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
AccessToken string `protobuf:"bytes,1,opt,name=access_token,json=accessToken,proto3" json:"access_token,omitempty"`
|
||||
RefreshToken *string `protobuf:"bytes,2,opt,name=refresh_token,json=refreshToken,proto3,oneof" json:"refresh_token,omitempty"`
|
||||
AccessType string `protobuf:"bytes,3,opt,name=access_type,json=accessType,proto3" json:"access_type,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Token) Reset() {
|
||||
*x = Token{}
|
||||
mi := &file_token_v1_token_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Token) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Token) ProtoMessage() {}
|
||||
|
||||
func (x *Token) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_token_v1_token_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 Token.ProtoReflect.Descriptor instead.
|
||||
func (*Token) Descriptor() ([]byte, []int) {
|
||||
return file_token_v1_token_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *Token) GetAccessToken() string {
|
||||
if x != nil {
|
||||
return x.AccessToken
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Token) GetRefreshToken() string {
|
||||
if x != nil && x.RefreshToken != nil {
|
||||
return *x.RefreshToken
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Token) GetAccessType() string {
|
||||
if x != nil {
|
||||
return x.AccessType
|
||||
}
|
||||
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\"\x92\x01\n" +
|
||||
"\bIssueReq\x12\x17\n" +
|
||||
"\auser_id\x18\x01 \x01(\tR\x06userId\x12\x1b\n" +
|
||||
"\tuser_role\x18\x02 \x01(\rR\buserRole\x12\x12\n" +
|
||||
"\x04type\x18\x03 \x01(\rR\x04type\x12\x1a\n" +
|
||||
"\bverified\x18\x04 \x01(\bR\bverified\x12 \n" +
|
||||
"\vdescription\x18\x05 \x01(\tR\vdescription\"M\n" +
|
||||
"\n" +
|
||||
"RefreshReq\x12#\n" +
|
||||
"\rrefresh_token\x18\x01 \x01(\tR\frefreshToken\x12\x1a\n" +
|
||||
"\bverified\x18\x02 \x01(\bR\bverified\"?\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_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\"\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\"\x00B.Z,github.com/absmach/supermq/api/grpc/token/v1b\x06proto3"
|
||||
|
||||
var (
|
||||
file_token_v1_token_proto_rawDescOnce sync.Once
|
||||
file_token_v1_token_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_token_v1_token_proto_rawDescGZIP() []byte {
|
||||
file_token_v1_token_proto_rawDescOnce.Do(func() {
|
||||
file_token_v1_token_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_token_v1_token_proto_rawDesc), len(file_token_v1_token_proto_rawDesc)))
|
||||
})
|
||||
return file_token_v1_token_proto_rawDescData
|
||||
}
|
||||
|
||||
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
|
||||
(*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{
|
||||
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() }
|
||||
func file_token_v1_token_proto_init() {
|
||||
if File_token_v1_token_proto != nil {
|
||||
return
|
||||
}
|
||||
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: 8,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_token_v1_token_proto_goTypes,
|
||||
DependencyIndexes: file_token_v1_token_proto_depIdxs,
|
||||
MessageInfos: file_token_v1_token_proto_msgTypes,
|
||||
}.Build()
|
||||
File_token_v1_token_proto = out.File
|
||||
file_token_v1_token_proto_goTypes = nil
|
||||
file_token_v1_token_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
// 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.0
|
||||
// - protoc v6.33.0
|
||||
// source: token/v1/token.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 (
|
||||
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.
|
||||
//
|
||||
// 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 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 {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewTokenServiceClient(cc grpc.ClientConnInterface) TokenServiceClient {
|
||||
return &tokenServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *tokenServiceClient) Issue(ctx context.Context, in *IssueReq, opts ...grpc.CallOption) (*Token, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(Token)
|
||||
err := c.cc.Invoke(ctx, TokenService_Issue_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *tokenServiceClient) Refresh(ctx context.Context, in *RefreshReq, opts ...grpc.CallOption) (*Token, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(Token)
|
||||
err := c.cc.Invoke(ctx, TokenService_Refresh_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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()
|
||||
}
|
||||
|
||||
// UnimplementedTokenServiceServer 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 UnimplementedTokenServiceServer struct{}
|
||||
|
||||
func (UnimplementedTokenServiceServer) Issue(context.Context, *IssueReq) (*Token, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method Issue not implemented")
|
||||
}
|
||||
func (UnimplementedTokenServiceServer) Refresh(context.Context, *RefreshReq) (*Token, error) {
|
||||
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() {}
|
||||
|
||||
// UnsafeTokenServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to TokenServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeTokenServiceServer interface {
|
||||
mustEmbedUnimplementedTokenServiceServer()
|
||||
}
|
||||
|
||||
func RegisterTokenServiceServer(s grpc.ServiceRegistrar, srv TokenServiceServer) {
|
||||
// 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.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&TokenService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _TokenService_Issue_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(IssueReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(TokenServiceServer).Issue(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: TokenService_Issue_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(TokenServiceServer).Issue(ctx, req.(*IssueReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _TokenService_Refresh_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(RefreshReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(TokenServiceServer).Refresh(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: TokenService_Refresh_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(TokenServiceServer).Refresh(ctx, req.(*RefreshReq))
|
||||
}
|
||||
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)
|
||||
var TokenService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "token.v1.TokenService",
|
||||
HandlerType: (*TokenServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Issue",
|
||||
Handler: _TokenService_Issue_Handler,
|
||||
},
|
||||
{
|
||||
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",
|
||||
}
|
||||
@@ -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 v6.33.0
|
||||
// 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\"\x00B.Z,github.com/absmach/supermq/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
|
||||
}
|
||||
@@ -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.0
|
||||
// - protoc v6.33.0
|
||||
// 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",
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package http
|
||||
|
||||
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/clients"
|
||||
"github.com/absmach/supermq/groups"
|
||||
"github.com/absmach/supermq/pkg/errors"
|
||||
"github.com/absmach/supermq/users"
|
||||
"github.com/gofrs/uuid/v5"
|
||||
)
|
||||
|
||||
const (
|
||||
OffsetKey = "offset"
|
||||
DirKey = "dir"
|
||||
OrderKey = "order"
|
||||
LimitKey = "limit"
|
||||
OnlyTotal = "only_total"
|
||||
|
||||
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"
|
||||
ChannelKey = "channel"
|
||||
ConnTypeKey = "connection_type"
|
||||
GroupKey = "group"
|
||||
DomainKey = "domain"
|
||||
|
||||
StartLevelKey = "start_level"
|
||||
EndLevelKey = "end_level"
|
||||
TreeKey = "tree"
|
||||
ParentKey = "parent_id"
|
||||
LevelKey = "level"
|
||||
RootGroupKey = "root_group"
|
||||
|
||||
TokenKey = "token"
|
||||
SubjectKey = "subject"
|
||||
ObjectKey = "object"
|
||||
|
||||
RolesKey = "roles"
|
||||
ActionKey = "action"
|
||||
ActionsKey = "actions"
|
||||
RoleIDKey = "role_id"
|
||||
RoleNameKey = "role_name"
|
||||
AccessProviderIDKey = "access_provider_id"
|
||||
AccessTypeKey = "access_type"
|
||||
|
||||
UsernameKey = "username"
|
||||
UserKey = "user"
|
||||
EmailKey = "email"
|
||||
FirstNameKey = "first_name"
|
||||
LastNameKey = "last_name"
|
||||
|
||||
DefTotal = uint64(100)
|
||||
DefOffset = 0
|
||||
DefOrder = "updated_at"
|
||||
DefDir = "desc"
|
||||
DefLimit = 10
|
||||
DefLevel = 0
|
||||
DefStartLevel = 1
|
||||
DefEndLevel = 0
|
||||
DefStatus = "enabled"
|
||||
DefClientStatus = clients.Enabled
|
||||
DefUserStatus = users.Enabled
|
||||
DefGroupStatus = groups.Enabled
|
||||
|
||||
// ContentType represents JSON content type.
|
||||
ContentType = "application/json"
|
||||
|
||||
// MaxNameSize limits name size to prevent making them too complex.
|
||||
MaxLimitSize = 100
|
||||
MaxNameSize = 1024
|
||||
MaxIDSize = 36
|
||||
)
|
||||
|
||||
var (
|
||||
nameRegExp = regexp.MustCompile(`^[a-z0-9][a-z0-9_-]{34}[a-z0-9]$`)
|
||||
routeRegExp = regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9_-]{0,35}$`)
|
||||
userNameRegExp = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9_-]{0,31}$`)
|
||||
errUnreadableName = errors.New("name containing double underscores or double dashes not allowed")
|
||||
)
|
||||
|
||||
// ValidateUUID validates UUID format.
|
||||
func ValidateUUID(extID string) (err error) {
|
||||
id, err := uuid.FromString(extID)
|
||||
if id.String() != extID || err != nil {
|
||||
return apiutil.ErrInvalidIDFormat
|
||||
}
|
||||
|
||||
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) {
|
||||
return apiutil.ErrInvalidNameFormat
|
||||
}
|
||||
// Names containing double underscores or double dashes are invalid due to similarity concerns.
|
||||
if strings.Contains(id, "__") || strings.Contains(id, "--") {
|
||||
return errors.Wrap(apiutil.ErrInvalidNameFormat, errUnreadableName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateRoute validates route format.
|
||||
func ValidateRoute(route string) error {
|
||||
if !routeRegExp.MatchString(route) {
|
||||
return apiutil.ErrInvalidRouteFormat
|
||||
}
|
||||
|
||||
if strings.Contains(route, "__") || strings.Contains(route, "--") {
|
||||
return errors.Wrap(apiutil.ErrInvalidRouteFormat, errUnreadableName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateUserName validates user name format.
|
||||
func ValidateUserName(name string) error {
|
||||
if !userNameRegExp.MatchString(name) {
|
||||
return apiutil.ErrInvalidUsername
|
||||
}
|
||||
|
||||
if strings.Contains(name, "__") || strings.Contains(name, "--") {
|
||||
return errors.Wrap(apiutil.ErrInvalidUsername, errUnreadableName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeResponse encodes successful response.
|
||||
func EncodeResponse(_ context.Context, w http.ResponseWriter, response any) error {
|
||||
if ar, ok := response.(supermq.Response); ok {
|
||||
for k, v := range ar.Headers() {
|
||||
w.Header().Set(k, v)
|
||||
}
|
||||
w.Header().Set("Content-Type", ContentType)
|
||||
w.WriteHeader(ar.Code())
|
||||
|
||||
if ar.Empty() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
// EncodeError encodes an error response.
|
||||
func EncodeError(_ context.Context, err error, w http.ResponseWriter) {
|
||||
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
|
||||
}
|
||||
|
||||
switch retErr := err.(type) {
|
||||
case *errors.RequestError:
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package api_test
|
||||
package http_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -10,16 +10,16 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/magistrala"
|
||||
"github.com/absmach/magistrala/internal/api"
|
||||
"github.com/absmach/magistrala/internal/apiutil"
|
||||
"github.com/absmach/magistrala/internal/testsutil"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
"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/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var _ magistrala.Response = (*response)(nil)
|
||||
var _ supermq.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,104 @@ 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.ErrInvalidSecret,
|
||||
svcerr.ErrMalformedEntity,
|
||||
errors.ErrMalformedEntity,
|
||||
apiutil.ErrMissingID,
|
||||
apiutil.ErrEmptyList,
|
||||
apiutil.ErrMissingMemberType,
|
||||
apiutil.ErrMissingMemberKind,
|
||||
apiutil.ErrLimitSize,
|
||||
apiutil.ErrNameSize,
|
||||
},
|
||||
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.ErrInvalidSecret),
|
||||
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,
|
||||
errors.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,
|
||||
errors.ErrConflict,
|
||||
},
|
||||
code: http.StatusConflict,
|
||||
desc: "RequestError - Conflict",
|
||||
err: svcerr.ErrConflict,
|
||||
code: http.StatusBadRequest,
|
||||
hasBody: true,
|
||||
},
|
||||
{
|
||||
desc: "Forbidden",
|
||||
errs: []error{
|
||||
svcerr.ErrAuthorization,
|
||||
errors.ErrAuthorization,
|
||||
errors.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: "InternalServerError",
|
||||
errs: []error{
|
||||
svcerr.ErrCreateEntity,
|
||||
svcerr.ErrUpdateEntity,
|
||||
svcerr.ErrViewEntity,
|
||||
svcerr.ErrRemoveEntity,
|
||||
},
|
||||
code: http.StatusInternalServerError,
|
||||
desc: "AuthZError - Authorization Failed",
|
||||
err: svcerr.ErrAuthorization,
|
||||
code: http.StatusForbidden,
|
||||
hasBody: true,
|
||||
},
|
||||
{
|
||||
desc: "InternalServerError",
|
||||
errs: []error{
|
||||
errors.New("test"),
|
||||
},
|
||||
code: http.StatusInternalServerError,
|
||||
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)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package http contains implementation of kit service HTTP API.
|
||||
// Package api contains commonly used constants and functions
|
||||
// for the HTTP API.
|
||||
package http
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/absmach/supermq"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
)
|
||||
|
||||
func RequestIDMiddleware(idp supermq.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()
|
||||
if err != nil {
|
||||
EncodeError(r.Context(), err, w)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), middleware.RequestIDKey, requestID)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package util
|
||||
|
||||
import "github.com/absmach/supermq/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.NewRequestError("something went wrong with the request")
|
||||
|
||||
// ErrBearerToken indicates 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.NewAuthNError("missing or invalid bearer entity key")
|
||||
|
||||
// ErrMissingID indicates missing entity ID.
|
||||
ErrMissingID = errors.NewRequestError("missing entity id")
|
||||
|
||||
// ErrMissingEntityID indicates missing entity ID.
|
||||
ErrMissingEntityID = errors.NewRequestError("missing entity id")
|
||||
|
||||
// ErrMissingClientID indicates missing client ID.
|
||||
ErrMissingClientID = errors.NewRequestError("missing client id")
|
||||
|
||||
// ErrMissingChannelID indicates missing client ID.
|
||||
ErrMissingChannelID = errors.NewRequestError("missing channel id")
|
||||
|
||||
// ErrMissingConnectionType indicates missing connection tpye.
|
||||
ErrMissingConnectionType = errors.NewRequestError("missing connection type")
|
||||
|
||||
// ErrMissingParentGroupID indicates missing parent group ID.
|
||||
ErrMissingParentGroupID = errors.NewRequestError("missing parent group id")
|
||||
|
||||
// ErrMissingChildrenGroupIDs indicates missing children group IDs.
|
||||
ErrMissingChildrenGroupIDs = errors.NewRequestError("missing children group ids")
|
||||
|
||||
// ErrSelfParentingNotAllowed indicates child id is same as parent id.
|
||||
ErrSelfParentingNotAllowed = errors.NewRequestError("self parenting not allowed")
|
||||
|
||||
// ErrInvalidChildGroupID indicates 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.NewRequestError("invalid id format provided")
|
||||
|
||||
// ErrNameSize indicates that name size exceeds the max.
|
||||
ErrNameSize = errors.NewRequestError("invalid name size")
|
||||
|
||||
// ErrEmailSize indicates that email size exceeds the max.
|
||||
ErrEmailSize = errors.NewRequestError("invalid email size")
|
||||
|
||||
// ErrInvalidRole indicates that an invalid role.
|
||||
ErrInvalidRole = errors.NewRequestError("invalid client role")
|
||||
|
||||
// ErrLimitSize indicates that an invalid limit.
|
||||
ErrLimitSize = errors.NewRequestError("invalid limit size")
|
||||
|
||||
// ErrLevel indicates that an invalid level.
|
||||
ErrLevel = errors.NewRequestError("invalid level")
|
||||
|
||||
// ErrOffsetSize indicates an invalid offset.
|
||||
ErrOffsetSize = errors.NewRequestError("invalid offset size")
|
||||
|
||||
// ErrInvalidOrder indicates an invalid list order.
|
||||
ErrInvalidOrder = errors.NewRequestError("invalid list order provided")
|
||||
|
||||
// ErrInvalidDirection indicates an invalid list direction.
|
||||
ErrInvalidDirection = errors.NewRequestError("invalid list direction provided")
|
||||
|
||||
// ErrInvalidMemberKind indicates an invalid member kind.
|
||||
ErrInvalidMemberKind = errors.NewRequestError("invalid member kind")
|
||||
|
||||
// ErrEmptyList indicates that entity data is empty.
|
||||
ErrEmptyList = errors.NewRequestError("empty list provided")
|
||||
|
||||
// ErrMissingRoleName indicates that role name is empty.
|
||||
ErrMissingRoleName = errors.NewRequestError("empty role name")
|
||||
|
||||
// ErrMissingRoleID indicates that role id is empty.
|
||||
ErrMissingRoleID = errors.NewRequestError("empty role id")
|
||||
|
||||
// ErrMissingRoleOperations indicates that role operations are empty.
|
||||
ErrMissingRoleOperations = errors.NewRequestError("empty role operations")
|
||||
|
||||
// ErrMissingRoleMembers indicates that role members are empty.
|
||||
ErrMissingRoleMembers = errors.NewRequestError("empty role members")
|
||||
|
||||
// ErrMalformedPolicy indicates that policies are malformed.
|
||||
ErrMalformedPolicy = errors.NewRequestError("malformed policy")
|
||||
|
||||
// ErrMissingPolicySub indicates that policies are subject.
|
||||
ErrMissingPolicySub = errors.NewRequestError("malformed policy subject")
|
||||
|
||||
// ErrMissingPolicyObj indicates missing policies object.
|
||||
ErrMissingPolicyObj = errors.NewRequestError("malformed policy object")
|
||||
|
||||
// ErrMalformedPolicyAct indicates missing policies action.
|
||||
ErrMalformedPolicyAct = errors.NewRequestError("malformed policy action")
|
||||
|
||||
// ErrMissingPolicyEntityType indicates missing policies entity type.
|
||||
ErrMissingPolicyEntityType = errors.NewRequestError("missing policy entity type")
|
||||
|
||||
// ErrMalformedPolicyPer indicates missing policies relation.
|
||||
ErrMalformedPolicyPer = errors.NewRequestError("malformed policy permission")
|
||||
|
||||
// ErrMissingCertData indicates missing cert data (ttl).
|
||||
ErrMissingCertData = errors.NewRequestError("missing certificate data")
|
||||
|
||||
// ErrInvalidCertData indicates invalid cert data (ttl).
|
||||
ErrInvalidCertData = errors.NewRequestError("invalid certificate data")
|
||||
|
||||
// ErrInvalidTopic indicates an invalid subscription topic.
|
||||
ErrInvalidTopic = errors.NewRequestError("invalid Subscription topic")
|
||||
|
||||
// ErrInvalidContact indicates an invalid subscription contract.
|
||||
ErrInvalidContact = errors.NewRequestError("invalid Subscription contact")
|
||||
|
||||
// ErrMissingEmail indicates missing email.
|
||||
ErrMissingEmail = errors.NewRequestError("missing email")
|
||||
|
||||
// ErrInvalidEmail indicates missing email.
|
||||
ErrInvalidEmail = errors.NewRequestError("invalid email")
|
||||
|
||||
// ErrMissingHost indicates missing host.
|
||||
ErrMissingHost = errors.NewRequestError("missing host")
|
||||
|
||||
// ErrMissingPass indicates missing password.
|
||||
ErrMissingPass = errors.NewRequestError("missing password")
|
||||
|
||||
// ErrMissingConfPass indicates missing conf password.
|
||||
ErrMissingConfPass = errors.NewRequestError("missing conf password")
|
||||
|
||||
// ErrInvalidResetPass indicates an invalid reset password.
|
||||
ErrInvalidResetPass = errors.NewRequestError("invalid reset password")
|
||||
|
||||
// ErrInvalidComparator indicates an invalid comparator.
|
||||
ErrInvalidComparator = errors.NewRequestError("invalid comparator")
|
||||
|
||||
// ErrMissingMemberIDs indicates missing member ids.
|
||||
ErrMissingMemberIDs = errors.NewRequestError("missing member ids")
|
||||
|
||||
// ErrMissingMemberType indicates missing group member type.
|
||||
ErrMissingMemberType = errors.NewRequestError("missing group member type")
|
||||
|
||||
// ErrMissingMemberKind indicates missing group member kind.
|
||||
ErrMissingMemberKind = errors.NewRequestError("missing group member kind")
|
||||
|
||||
// ErrMissingRelation indicates missing relation.
|
||||
ErrMissingRelation = errors.NewRequestError("missing relation")
|
||||
|
||||
// ErrInvalidRelation indicates an invalid relation.
|
||||
ErrInvalidRelation = errors.NewRequestError("invalid relation")
|
||||
|
||||
// ErrInvalidAPIKey indicates an invalid API key type.
|
||||
ErrInvalidAPIKey = errors.NewRequestError("invalid api key type")
|
||||
|
||||
// ErrInvitationState indicates an invalid invitation state.
|
||||
ErrInvitationState = errors.NewRequestError("invalid invitation state")
|
||||
|
||||
// ErrMissingIdentity indicates missing entity Identity.
|
||||
ErrMissingIdentity = errors.NewRequestError("missing entity identity")
|
||||
|
||||
// ErrMissingSecret indicates missing secret.
|
||||
ErrMissingSecret = errors.NewRequestError("missing secret")
|
||||
|
||||
// ErrPasswordFormat indicates weak password.
|
||||
ErrPasswordFormat = errors.NewRequestError("password does not meet the requirements")
|
||||
|
||||
// ErrMissingName indicates missing identity name.
|
||||
ErrMissingName = errors.NewRequestError("missing identity name")
|
||||
|
||||
// ErrMissingRoute indicates missing route.
|
||||
ErrMissingRoute = errors.NewRequestError("missing route")
|
||||
|
||||
// ErrInvalidLevel indicates an invalid group level.
|
||||
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.NewRequestError("parameter not found in the query")
|
||||
|
||||
// ErrInvalidQueryParams indicates invalid query parameters.
|
||||
ErrInvalidQueryParams = errors.NewRequestError("invalid query parameters")
|
||||
|
||||
// ErrInvalidVisibilityType indicates invalid visibility type.
|
||||
ErrInvalidVisibilityType = errors.NewRequestError("invalid visibility type")
|
||||
|
||||
// ErrUnsupportedContentType indicates unacceptable or lack of Content-Type.
|
||||
ErrUnsupportedContentType = errors.NewMediaTypeError("unsupported content type")
|
||||
|
||||
// ErrRollbackTx indicates failed to rollback transaction.
|
||||
ErrRollbackTx = errors.NewRequestError("failed to rollback transaction")
|
||||
|
||||
// ErrInvalidAggregation indicates invalid aggregation value.
|
||||
ErrInvalidAggregation = errors.NewRequestError("invalid aggregation value")
|
||||
|
||||
// ErrInvalidInterval indicates invalid interval value.
|
||||
ErrInvalidInterval = errors.NewRequestError("invalid interval value")
|
||||
|
||||
// ErrMissingFrom indicates missing from value.
|
||||
ErrMissingFrom = errors.NewRequestError("missing from time value")
|
||||
|
||||
// ErrMissingTo indicates missing to value.
|
||||
ErrMissingTo = errors.NewRequestError("missing to time value")
|
||||
|
||||
// ErrEmptyMessage indicates empty message.
|
||||
ErrEmptyMessage = errors.NewRequestError("empty message")
|
||||
|
||||
// ErrMissingEntityType indicates missing entity type.
|
||||
ErrMissingEntityType = errors.NewRequestError("missing entity type")
|
||||
|
||||
// ErrInvalidEntityType indicates invalid entity type.
|
||||
ErrInvalidEntityType = errors.NewRequestError("invalid entity type")
|
||||
|
||||
// ErrInvalidTimeFormat indicates invalid time format i.e not unix time.
|
||||
ErrInvalidTimeFormat = errors.NewRequestError("invalid time format use unix time")
|
||||
|
||||
// ErrEmptySearchQuery indicates search query should not be empty.
|
||||
ErrEmptySearchQuery = errors.NewRequestError("search query must not be empty")
|
||||
|
||||
// ErrLenSearchQuery indicates search query length.
|
||||
ErrLenSearchQuery = errors.NewRequestError("search query must be at least 3 characters")
|
||||
|
||||
// ErrMissingDomainID indicates missing domainID.
|
||||
ErrMissingDomainID = errors.NewRequestError("missing domainID")
|
||||
|
||||
// ErrMissingUsername indicates missing user name.
|
||||
ErrMissingUsername = errors.NewRequestError("missing username")
|
||||
|
||||
// ErrInvalidUsername indicates invalid user name.
|
||||
ErrInvalidUsername = errors.NewRequestError("invalid username")
|
||||
|
||||
// ErrMissingFirstName indicates missing first name.
|
||||
ErrMissingFirstName = errors.NewRequestError("missing first name")
|
||||
|
||||
// ErrMissingLastName indicates missing last name.
|
||||
ErrMissingLastName = errors.NewRequestError("missing last name")
|
||||
|
||||
// ErrInvalidProfilePictureURL indicates that the profile picture url is invalid.
|
||||
ErrInvalidProfilePictureURL = errors.NewRequestError("invalid profile picture url")
|
||||
|
||||
ErrMultipleEntitiesFilter = errors.NewRequestError("multiple entities are provided in filter are not supported")
|
||||
|
||||
// ErrMissingDescription indicates missing description.
|
||||
ErrMissingDescription = errors.NewRequestError("missing description")
|
||||
|
||||
// ErrUnsupportedTokenType indicates that this type of token is not supported.
|
||||
ErrUnsupportedTokenType = errors.NewRequestError("unsupported content token type")
|
||||
|
||||
// ErrMissingUserID indicates missing user ID.
|
||||
ErrMissingUserID = errors.NewRequestError("missing user id")
|
||||
|
||||
// ErrMissingPATID indicates missing pat ID.
|
||||
ErrMissingPATID = errors.NewRequestError("missing pat id")
|
||||
|
||||
// ErrInvalidNameFormat indicates invalid name format.
|
||||
ErrInvalidNameFormat = errors.NewRequestError("invalid name format")
|
||||
|
||||
// ErrInvalidRouteFormat indicates invalid route format.
|
||||
ErrInvalidRouteFormat = errors.NewRequestError("invalid route format")
|
||||
|
||||
// ErrMissingUsernameEmail indicates missing user name / 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")
|
||||
)
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package apiutil
|
||||
package util
|
||||
|
||||
// ErrorRes represents the HTTP error response body.
|
||||
type ErrorRes struct {
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// BearerPrefix represents the token prefix for Bearer authentication scheme.
|
||||
BearerPrefix = "Bearer "
|
||||
|
||||
// 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 {
|
||||
token := r.Header.Get("Authorization")
|
||||
|
||||
if !strings.HasPrefix(token, BearerPrefix) {
|
||||
return ""
|
||||
}
|
||||
|
||||
return strings.TrimPrefix(token, BearerPrefix)
|
||||
}
|
||||
|
||||
// ExtractClientSecret returns value of the client secret. If it's not present - an empty value is returned.
|
||||
func ExtractClientSecret(r *http.Request) string {
|
||||
token := r.Header.Get("Authorization")
|
||||
|
||||
if !strings.HasPrefix(token, ClientPrefix) {
|
||||
return ""
|
||||
}
|
||||
|
||||
return strings.TrimPrefix(token, ClientPrefix)
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package apiutil_test
|
||||
package util_test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/absmach/magistrala/internal/apiutil"
|
||||
apiutil "github.com/absmach/supermq/api/http/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -61,7 +61,7 @@ func TestExtractBearerToken(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractThingKey(t *testing.T) {
|
||||
func TestExtractClientSecret(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
request *http.Request
|
||||
@@ -71,7 +71,7 @@ func TestExtractThingKey(t *testing.T) {
|
||||
desc: "valid bearer token",
|
||||
request: &http.Request{
|
||||
Header: map[string][]string{
|
||||
"Authorization": {"Thing 123"},
|
||||
"Authorization": {"Client 123"},
|
||||
},
|
||||
},
|
||||
token: "123",
|
||||
@@ -105,7 +105,7 @@ func TestExtractThingKey(t *testing.T) {
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.desc, func(t *testing.T) {
|
||||
token := apiutil.ExtractThingKey(c.request)
|
||||
token := apiutil.ExtractClientSecret(c.request)
|
||||
assert.Equal(t, c.token, token)
|
||||
})
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package apiutil
|
||||
package util
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/absmach/supermq/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)
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package apiutil_test
|
||||
package util_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -11,9 +11,10 @@ import (
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/absmach/magistrala/internal/apiutil"
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
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"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -66,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,
|
||||
},
|
||||
{
|
||||
@@ -176,7 +177,7 @@ func TestReadNumQuery(t *testing.T) {
|
||||
url string
|
||||
key string
|
||||
numType string
|
||||
ret interface{}
|
||||
ret any
|
||||
err error
|
||||
}{
|
||||
{
|
||||
@@ -315,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)
|
||||
@@ -339,11 +340,11 @@ func TestLoggingErrorEncoder(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
desc: "error contains ErrValidation",
|
||||
err: errors.Wrap(apiutil.ErrValidation, errors.ErrAuthentication),
|
||||
err: errors.Wrap(apiutil.ErrValidation, svcerr.ErrAuthentication),
|
||||
},
|
||||
{
|
||||
desc: "error does not contain ErrValidation",
|
||||
err: errors.ErrAuthentication,
|
||||
err: svcerr.ErrAuthentication,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -354,7 +355,7 @@ func TestLoggingErrorEncoder(t *testing.T) {
|
||||
encCalled = true
|
||||
}
|
||||
|
||||
errorEncoder := apiutil.LoggingErrorEncoder(mglog.NewMock(), encFunc)
|
||||
errorEncoder := apiutil.LoggingErrorEncoder(smqlog.NewMock(), encFunc)
|
||||
errorEncoder(context.Background(), c.err, httptest.NewRecorder())
|
||||
|
||||
assert.True(t, encCalled)
|
||||
@@ -1,5 +0,0 @@
|
||||
# Magistrala OpenAPI Specification
|
||||
|
||||
This folder contains an OpenAPI specifications for Magistrala API.
|
||||
|
||||
View specification in Swagger UI at [api.mainflux.io](https://api.mainflux.io)
|
||||
@@ -1,887 +0,0 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
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 Magistrala repository](https://github.com/absmach/magistrala)
|
||||
contact:
|
||||
email: info@mainflux.com
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/absmach/magistrala/blob/master/LICENSE
|
||||
version: 0.14.0
|
||||
|
||||
servers:
|
||||
- url: http://localhost:8180
|
||||
- url: https://localhost:8180
|
||||
|
||||
tags:
|
||||
- name: Auth
|
||||
description: Everything about your Authentication and Authorization.
|
||||
externalDocs:
|
||||
description: Find out more about auth
|
||||
url: https://docs.magistrala.abstractmachines.fr/
|
||||
- name: Keys
|
||||
description: Everything about your Keys.
|
||||
externalDocs:
|
||||
description: Find out more about keys
|
||||
url: https://docs.magistrala.abstractmachines.fr/
|
||||
|
||||
paths:
|
||||
/domains:
|
||||
post:
|
||||
tags:
|
||||
- Domains
|
||||
summary: Adds new domain
|
||||
description: |
|
||||
Adds new domain.
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/DomainCreateReq"
|
||||
responses:
|
||||
"201":
|
||||
$ref: "#/components/responses/DomainCreateRes"
|
||||
"400":
|
||||
description: Failed due to malformed JSON.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"409":
|
||||
description: Failed due to using an existing alias.
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
get:
|
||||
summary: Retrieves list of domains.
|
||||
description: |
|
||||
Retrieves list of domains that the user have access.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Limit"
|
||||
- $ref: "#/components/parameters/Offset"
|
||||
- $ref: "#/components/parameters/Metadata"
|
||||
- $ref: "#/components/parameters/Status"
|
||||
- $ref: "#/components/parameters/DomainName"
|
||||
- $ref: "#/components/parameters/Permission"
|
||||
tags:
|
||||
- Domains
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/DomainsPageRes"
|
||||
"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"
|
||||
|
||||
/domains/{domainID}:
|
||||
get:
|
||||
summary: Retrieves domain information
|
||||
description: |
|
||||
Retrieves a specific domain that is identified by the domain ID.
|
||||
tags:
|
||||
- Domains
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/DomainID"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/DomainRes"
|
||||
"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"
|
||||
|
||||
patch:
|
||||
summary: Updates name, metadata, tags and alias of the domain.
|
||||
description: |
|
||||
Updates name, metadata, tags and alias of the domain.
|
||||
tags:
|
||||
- Domains
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/DomainID"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/DomainUpdateReq"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/DomainRes"
|
||||
"400":
|
||||
description: Failed due to malformed JSON.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"403":
|
||||
description: Unauthorized access to domain id.
|
||||
"404":
|
||||
description: Failed due to non existing domain.
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
delete:
|
||||
summary: Delete domain for a domain with the given id.
|
||||
description: |
|
||||
Delete domain removes a domain with the given id from repo
|
||||
and removes all the things, channels, assigned users, policies related to this domain.
|
||||
tags:
|
||||
- Domains
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/DomainID"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"204":
|
||||
description: Domain deleted.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"403":
|
||||
description: Unauthorized access to domain id.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/domains/{domainID}/permissions:
|
||||
get:
|
||||
summary: Retrieves user permissions on domain.
|
||||
description: |
|
||||
Retrieves user permissions on domain that is identified by the domain ID.
|
||||
tags:
|
||||
- Domains
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/DomainID"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/DomainPermissionRes"
|
||||
"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"
|
||||
/domains/{domainID}/enable:
|
||||
post:
|
||||
summary: Enables a domain
|
||||
description: |
|
||||
Enables a specific domain that is identified by the domain ID.
|
||||
tags:
|
||||
- Domains
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/DomainID"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
description: Successfully enabled domain.
|
||||
"400":
|
||||
description: Failed due to malformed domain's ID.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"403":
|
||||
description: Unauthorized access the domain ID.
|
||||
"404":
|
||||
description: A non-existent entity request.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/domains/{domainID}/disable:
|
||||
post:
|
||||
summary: Disable a domain
|
||||
description: |
|
||||
Disable a specific domain that is identified by the domain ID.
|
||||
tags:
|
||||
- Domains
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/DomainID"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
description: Successfully disabled domain.
|
||||
"400":
|
||||
description: Failed due to malformed domain's ID.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"403":
|
||||
description: Unauthorized access the domain ID.
|
||||
"404":
|
||||
description: A non-existent entity request.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/domains/{domainID}/freeze:
|
||||
post:
|
||||
summary: Freeze a domain
|
||||
description: |
|
||||
Freeze a specific domain that is identified by the domain ID.
|
||||
tags:
|
||||
- Domains
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/DomainID"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
description: Successfully freezed domain.
|
||||
"400":
|
||||
description: Failed due to malformed domain's ID.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"403":
|
||||
description: Unauthorized access the domain ID.
|
||||
"404":
|
||||
description: A non-existent entity request.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/domains/{domainID}/users/assign:
|
||||
post:
|
||||
summary: Assign users to domain
|
||||
description: |
|
||||
Assign users to domain that is identified by the domain ID.
|
||||
tags:
|
||||
- Domains
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/DomainID"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/AssignUserReq"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
description: Users successfully assigned to domain.
|
||||
"400":
|
||||
description: Failed due to malformed domain's ID.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"403":
|
||||
description: Unauthorized access the domain ID.
|
||||
"404":
|
||||
description: A non-existent entity request.
|
||||
"409":
|
||||
description: Conflict of data.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/domains/{domainID}/users/unassign:
|
||||
post:
|
||||
summary: Unassign users from domain
|
||||
description: |
|
||||
Unassign users from domain that is identified by the domain ID.
|
||||
tags:
|
||||
- Domains
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/DomainID"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/UnassignUsersReq"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
description: Users successfully unassigned from domain.
|
||||
"400":
|
||||
description: Failed due to malformed domain's ID.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"403":
|
||||
description: Unauthorized access the domain ID.
|
||||
"404":
|
||||
description: A non-existent entity request.
|
||||
"409":
|
||||
description: Conflict of data.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/keys:
|
||||
post:
|
||||
tags:
|
||||
- Keys
|
||||
summary: Issue API key
|
||||
description: |
|
||||
Generates a new API key. Thew new API key will
|
||||
be uniquely identified by its ID.
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/KeyRequest"
|
||||
responses:
|
||||
"201":
|
||||
description: Issued new key.
|
||||
"400":
|
||||
description: Failed due to malformed JSON.
|
||||
"409":
|
||||
description: Failed due to using already existing ID.
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/keys/{keyID}:
|
||||
get:
|
||||
summary: Gets API key details.
|
||||
description: |
|
||||
Gets API key details for the given key.
|
||||
tags:
|
||||
- Keys
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ApiKeyId"
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/KeyRes"
|
||||
"400":
|
||||
description: Failed due to malformed query parameters.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
delete:
|
||||
summary: Revoke API key
|
||||
description: |
|
||||
Revoke API key identified by the given ID.
|
||||
tags:
|
||||
- Keys
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ApiKeyId"
|
||||
responses:
|
||||
"204":
|
||||
description: Key revoked.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/policies:
|
||||
post:
|
||||
summary: Creates new policies.
|
||||
description: |
|
||||
Creates new policies. Only admin can use this endpoint. Therefore, you need an authentication token for the admin.
|
||||
Also, only policies defined on the system are allowed to add. For more details, please see the docs for Authorization.
|
||||
tags:
|
||||
- Auth
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/PoliciesReq"
|
||||
responses:
|
||||
"201":
|
||||
description: Policies created.
|
||||
"400":
|
||||
description: Failed due to malformed JSON.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"403":
|
||||
description: Unauthorized access token provided.
|
||||
"409":
|
||||
description: Failed due to using an existing email address.
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/policies/delete:
|
||||
post:
|
||||
summary: Deletes policies.
|
||||
description: |
|
||||
Deletes policies. Only admin can use this endpoint. Therefore, you need an authentication token for the admin.
|
||||
Also, only policies defined on the system are allowed to delete. For more details, please see the docs for Authorization.
|
||||
tags:
|
||||
- Auth
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/PoliciesReq"
|
||||
responses:
|
||||
"204":
|
||||
description: Policies deleted.
|
||||
"400":
|
||||
description: Failed due to malformed JSON.
|
||||
"409":
|
||||
description: Failed due to using an existing email address.
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/users/{memberID}/domains:
|
||||
get:
|
||||
tags:
|
||||
- Domains
|
||||
summary: List users in a group
|
||||
description: |
|
||||
Retrieves a list of users in a domain. 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: "users.yml#/components/parameters/MemberID"
|
||||
- $ref: "#/components/parameters/Limit"
|
||||
- $ref: "#/components/parameters/Offset"
|
||||
- $ref: "#/components/parameters/Metadata"
|
||||
- $ref: "#/components/parameters/Status"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
$ref: "users.yml#/components/responses/UserPageRes"
|
||||
"400":
|
||||
description: Failed due to malformed query parameters.
|
||||
"401":
|
||||
description: |
|
||||
Missing or invalid access token provided.
|
||||
This endpoint is available only for administrators.
|
||||
"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
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/HealthRes"
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
schemas:
|
||||
DomainReqObj:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
example: domainName
|
||||
description: Domain name.
|
||||
tags:
|
||||
type: array
|
||||
minItems: 0
|
||||
items:
|
||||
type: string
|
||||
example: ["tag1", "tag2"]
|
||||
description: domain tags.
|
||||
metadata:
|
||||
type: object
|
||||
example: { "domain": "example.com" }
|
||||
description: Arbitrary, object-encoded domain's data.
|
||||
alias:
|
||||
type: string
|
||||
example: domain alias
|
||||
description: Domain alias.
|
||||
required:
|
||||
- name
|
||||
- alias
|
||||
Domain:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
description: Domain unique identifier.
|
||||
name:
|
||||
type: string
|
||||
example: domainName
|
||||
description: Domain name.
|
||||
tags:
|
||||
type: array
|
||||
minItems: 0
|
||||
items:
|
||||
type: string
|
||||
example: ["tag1", "tag2"]
|
||||
description: domain tags.
|
||||
metadata:
|
||||
type: object
|
||||
example: { "domain": "example.com" }
|
||||
description: Arbitrary, object-encoded domain's data.
|
||||
alias:
|
||||
type: string
|
||||
example: domain alias
|
||||
description: Domain alias.
|
||||
status:
|
||||
type: string
|
||||
description: Domain Status
|
||||
format: string
|
||||
example: enabled
|
||||
created_by:
|
||||
type: string
|
||||
format: uuid
|
||||
example: "0d837f56-3f8a-4e2a-9359-6347d0fc9f06 "
|
||||
description: User ID of the user who created the domain.
|
||||
created_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2019-11-26 13:31:52"
|
||||
description: Time when the domain was created.
|
||||
updated_by:
|
||||
type: string
|
||||
format: uuid
|
||||
example: "80f66b77-ed74-4e74-9f88-6cce9a0a3049"
|
||||
description: User ID of the user who last updated the domain.
|
||||
updated_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2019-11-26 13:31:52"
|
||||
description: Time when the domain was last updated.
|
||||
xml:
|
||||
name: domain
|
||||
|
||||
DomainsPage:
|
||||
type: object
|
||||
properties:
|
||||
domains:
|
||||
type: array
|
||||
minItems: 0
|
||||
uniqueItems: true
|
||||
items:
|
||||
$ref: "#/components/schemas/Domain"
|
||||
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:
|
||||
- domain
|
||||
- total
|
||||
- offset
|
||||
DomainUpdate:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
example: domainName
|
||||
description: Domain name.
|
||||
tags:
|
||||
type: array
|
||||
minItems: 0
|
||||
items:
|
||||
type: string
|
||||
example: ["tag1", "tag2"]
|
||||
description: domain tags.
|
||||
metadata:
|
||||
type: object
|
||||
example: { "domain": "example.com" }
|
||||
description: Arbitrary, object-encoded thing's data.
|
||||
alias:
|
||||
type: string
|
||||
example: domain alias
|
||||
description: Domain alias.
|
||||
Permissions:
|
||||
type: object
|
||||
properties:
|
||||
permissions:
|
||||
type: array
|
||||
minItems: 0
|
||||
items:
|
||||
type: string
|
||||
description: Permissions
|
||||
|
||||
UserDomainRelationReq:
|
||||
type: object
|
||||
properties:
|
||||
users_ids:
|
||||
type: array
|
||||
minItems: 1
|
||||
items:
|
||||
type: string
|
||||
description: Users IDs
|
||||
example:
|
||||
[
|
||||
"5dc1ce4b-7cc9-4f12-98a6-9d74cc4980bb",
|
||||
"c01ed106-e52d-4aa4-bed3-39f360177cfa",
|
||||
]
|
||||
relation:
|
||||
type: string
|
||||
enum: ["administrator", "editor","viewer","member"]
|
||||
example: "administrator"
|
||||
description: Policy relations.
|
||||
required:
|
||||
- users_ids
|
||||
- relation
|
||||
Key:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: "c5747f2f-2a7c-4fe1-b41a-51a5ae290945"
|
||||
description: API key unique identifier
|
||||
issuer_id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: "9118de62-c680-46b7-ad0a-21748a52833a"
|
||||
description: In ID of the entity that issued the token.
|
||||
type:
|
||||
type: integer
|
||||
example: 0
|
||||
description: API key type. Keys of different type are processed differently.
|
||||
subject:
|
||||
type: string
|
||||
format: string
|
||||
example: "test@example.com"
|
||||
description: User's email or service identifier of API key subject.
|
||||
issued_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2019-11-26 13:31:52"
|
||||
description: Time when the key is generated.
|
||||
expires_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2019-11-26 13:31:52"
|
||||
description: Time when the Key expires. If this field is missing,
|
||||
that means that Key is valid indefinitely.
|
||||
|
||||
PoliciesReqSchema:
|
||||
type: object
|
||||
properties:
|
||||
object:
|
||||
type: string
|
||||
description: |
|
||||
Specifies an object field for the field.
|
||||
Object indicates application objects such as ThingID.
|
||||
subjects:
|
||||
type: array
|
||||
minItems: 1
|
||||
uniqueItems: true
|
||||
items:
|
||||
type: string
|
||||
policies:
|
||||
type: array
|
||||
minItems: 1
|
||||
uniqueItems: true
|
||||
items:
|
||||
type: string
|
||||
|
||||
parameters:
|
||||
DomainID:
|
||||
name: domainID
|
||||
description: Unique domain identifier.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
Status:
|
||||
name: status
|
||||
description: Domain status.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
default: enabled
|
||||
required: false
|
||||
example: enabled
|
||||
DomainName:
|
||||
name: name
|
||||
description: Domain's name.
|
||||
in: query
|
||||
schema:
|
||||
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.
|
||||
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
|
||||
Metadata:
|
||||
name: metadata
|
||||
description: Metadata filter. Filtering is performed matching the parameter with metadata on top level. Parameter is json.
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
Type:
|
||||
name: type
|
||||
description: The type of the API Key.
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 0
|
||||
minimum: 0
|
||||
required: false
|
||||
Subject:
|
||||
name: subject
|
||||
description: The subject of an API Key
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
|
||||
requestBodies:
|
||||
DomainCreateReq:
|
||||
description: JSON-formatted document describing the new domain to be registered
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/DomainReqObj"
|
||||
DomainUpdateReq:
|
||||
description: JSON-formated document describing the name, alias, tags, and metadata of the domain to be updated
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/DomainUpdate"
|
||||
AssignUserReq:
|
||||
description: JSON-formated document describing the policy related to assigning users to a domain
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/UserDomainRelationReq"
|
||||
|
||||
UnassignUsersReq:
|
||||
description: JSON-formated document describing the policy related to unassigning users to a domain
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/UserDomainRelationReq"
|
||||
|
||||
KeyRequest:
|
||||
description: JSON-formatted document describing key request.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
type: integer
|
||||
example: 0
|
||||
description: API key type. Keys of different type are processed differently.
|
||||
duration:
|
||||
type: number
|
||||
format: integer
|
||||
example: 23456
|
||||
description: Number of seconds issued token is valid for.
|
||||
|
||||
PoliciesReq:
|
||||
description: JSON-formatted document describing adding policies request.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/PoliciesReqSchema"
|
||||
|
||||
responses:
|
||||
ServiceError:
|
||||
description: Unexpected server-side error occurred.
|
||||
|
||||
DomainCreateRes:
|
||||
description: Create new domain.
|
||||
headers:
|
||||
Location:
|
||||
schema:
|
||||
type: string
|
||||
format: url
|
||||
description: Registered domain relative URL in the format `/domains/<domainID_id>`
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Domain"
|
||||
|
||||
DomainRes:
|
||||
description: Data retrieved.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Domain"
|
||||
DomainPermissionRes:
|
||||
description: Data retrieved.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Permissions"
|
||||
DomainsPageRes:
|
||||
description: Data retrieved.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/DomainsPage"
|
||||
|
||||
KeyRes:
|
||||
description: Data retrieved.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Key"
|
||||
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas/HealthInfo.yml"
|
||||
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
description: |
|
||||
* Users access: "Authorization: Bearer <user_token>"
|
||||
|
||||
security:
|
||||
- bearerAuth: []
|
||||
@@ -1,597 +0,0 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: Magistrala Bootstrap service
|
||||
description: |
|
||||
HTTP API for managing platform things configuration.
|
||||
Some useful links:
|
||||
- [The Magistrala repository](https://github.com/absmach/magistrala)
|
||||
contact:
|
||||
email: info@mainflux.com
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/absmach/magistrala/blob/master/LICENSE
|
||||
version: 0.14.0
|
||||
|
||||
servers:
|
||||
- url: http://localhost:9013
|
||||
- url: https://localhost:9013
|
||||
|
||||
tags:
|
||||
- name: configs
|
||||
description: Everything about your Configs
|
||||
externalDocs:
|
||||
description: Find out more about Configs
|
||||
url: https://docs.magistrala.abstractmachines.fr/
|
||||
|
||||
paths:
|
||||
/things/configs:
|
||||
post:
|
||||
summary: Adds new config
|
||||
description: |
|
||||
Adds new config to the list of config owned by user identified using
|
||||
the provided access token.
|
||||
tags:
|
||||
- configs
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/ConfigCreateReq"
|
||||
responses:
|
||||
'201':
|
||||
$ref: "#/components/responses/ConfigCreateRes"
|
||||
'400':
|
||||
description: Failed due to malformed JSON.
|
||||
'401':
|
||||
description: Missing or invalid access token provided.
|
||||
'415':
|
||||
description: Missing or invalid content type.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
get:
|
||||
summary: Retrieves managed configs
|
||||
description: |
|
||||
Retrieves a list of managed configs. Due to performance concerns, data
|
||||
is retrieved in subsets. The API configs must ensure that the entire
|
||||
dataset is consumed either by making subsequent requests, or by
|
||||
increasing the subset size of the initial request.
|
||||
tags:
|
||||
- configs
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Limit"
|
||||
- $ref: "#/components/parameters/Offset"
|
||||
- $ref: "#/components/parameters/State"
|
||||
- $ref: "#/components/parameters/Name"
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/ConfigListRes"
|
||||
'400':
|
||||
description: Failed due to malformed query parameters.
|
||||
'401':
|
||||
description: Missing or invalid access token provided.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/things/configs/{configId}:
|
||||
get:
|
||||
summary: Retrieves config info (with channels).
|
||||
tags:
|
||||
- configs
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ConfigId"
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/ConfigRes"
|
||||
'401':
|
||||
description: Missing or invalid access token provided.
|
||||
'404':
|
||||
description: Config does not exist.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
put:
|
||||
summary: Updates config info
|
||||
description: |
|
||||
Update is performed by replacing the current resource data with values
|
||||
provided in a request payload. Note that the owner, ID, external ID,
|
||||
external key, Magistrala Thing ID and key cannot be changed.
|
||||
tags:
|
||||
- configs
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ConfigId"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/ConfigUpdateReq"
|
||||
responses:
|
||||
'200':
|
||||
description: Config updated.
|
||||
'400':
|
||||
description: Failed due to malformed JSON.
|
||||
'401':
|
||||
description: Missing or invalid access token provided.
|
||||
'404':
|
||||
description: Config does not exist.
|
||||
'415':
|
||||
description: Missing or invalid content type.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
delete:
|
||||
summary: Removes a Config
|
||||
description: |
|
||||
Removes a Config. In case of successful removal the service will ensure
|
||||
that the removed config is disconnected from all of the Magistrala channels.
|
||||
tags:
|
||||
- configs
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ConfigId"
|
||||
responses:
|
||||
'204':
|
||||
description: Config removed.
|
||||
'400':
|
||||
description: Failed due to malformed config ID.
|
||||
'401':
|
||||
description: Missing or invalid access token provided.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/things/configs/certs/{configId}:
|
||||
patch:
|
||||
summary: Updates certs
|
||||
description: |
|
||||
Update is performed by replacing the current certificate data with values
|
||||
provided in a request payload.
|
||||
tags:
|
||||
- configs
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ConfigId"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/ConfigCertUpdateReq"
|
||||
responses:
|
||||
'200':
|
||||
description: Config updated.
|
||||
$ref: "#/components/responses/ConfigUpdateCertsRes"
|
||||
'400':
|
||||
description: Failed due to malformed JSON.
|
||||
'401':
|
||||
description: Missing or invalid access token provided.
|
||||
'404':
|
||||
description: Config does not exist.
|
||||
'415':
|
||||
description: Missing or invalid content type.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/things/configs/connections/{configId}:
|
||||
put:
|
||||
summary: Updates channels the thing is connected to
|
||||
description: |
|
||||
Update connections performs update of the channel list corresponding
|
||||
Thing is connected to.
|
||||
tags:
|
||||
- configs
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ConfigId"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/ConfigConnUpdateReq"
|
||||
responses:
|
||||
'200':
|
||||
description: Config updated.
|
||||
'400':
|
||||
description: Failed due to malformed JSON.
|
||||
'401':
|
||||
description: Missing or invalid access token provided.
|
||||
'404':
|
||||
description: Config does not exist.
|
||||
'415':
|
||||
description: Missing or invalid content type.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/things/bootstrap/{externalId}:
|
||||
get:
|
||||
summary: Retrieves configuration.
|
||||
description: |
|
||||
Retrieves a configuration with given external ID and external key.
|
||||
tags:
|
||||
- configs
|
||||
security:
|
||||
- bootstrapAuth: []
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ExternalId"
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/BootstrapConfigRes"
|
||||
'400':
|
||||
description: Failed due to malformed JSON.
|
||||
'401':
|
||||
description: Missing or invalid external key provided.
|
||||
'404':
|
||||
description: Failed to retrieve corresponding config.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/things/bootstrap/secure/{externalId}:
|
||||
get:
|
||||
summary: Retrieves configuration.
|
||||
description: |
|
||||
Retrieves a configuration with given external ID and encrypted external key.
|
||||
tags:
|
||||
- configs
|
||||
security:
|
||||
- bootstrapEncAuth: []
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ExternalId"
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/BootstrapConfigRes"
|
||||
'404':
|
||||
description: |
|
||||
Failed to retrieve corresponding config.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/things/state/{configId}:
|
||||
put:
|
||||
summary: Updates Config state.
|
||||
description: |
|
||||
Updating state represents enabling/disabling Config, i.e. connecting
|
||||
and disconnecting corresponding Magistrala Thing to the list of Channels.
|
||||
tags:
|
||||
- configs
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ConfigId"
|
||||
requestBody:
|
||||
$ref: '#/components/requestBodies/ConfigStateUpdateReq'
|
||||
responses:
|
||||
'204':
|
||||
description: Config removed.
|
||||
'400':
|
||||
description: Failed due to malformed config's ID.
|
||||
'401':
|
||||
description: Missing or invalid access token provided.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/HealthRes"
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
schemas:
|
||||
State:
|
||||
type: integer
|
||||
enum: [0, 1]
|
||||
Config:
|
||||
type: object
|
||||
properties:
|
||||
thing_id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Corresponding Magistrala Thing ID.
|
||||
magistrala_key:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Corresponding Magistrala Thing key.
|
||||
channels:
|
||||
type: array
|
||||
minItems: 0
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Channel unique identifier.
|
||||
name:
|
||||
type: string
|
||||
description: Name of the Channel.
|
||||
metadata:
|
||||
type: object
|
||||
description: Custom metadata related to the Channel.
|
||||
external_id:
|
||||
type: string
|
||||
description: External ID (MAC address or some unique identifier).
|
||||
external_key:
|
||||
type: string
|
||||
description: External key.
|
||||
content:
|
||||
type: string
|
||||
description: Free-form custom configuration.
|
||||
state:
|
||||
$ref: "#/components/schemas/State"
|
||||
client_cert:
|
||||
type: string
|
||||
description: Client certificate.
|
||||
ca_cert:
|
||||
type: string
|
||||
description: Issuing CA certificate.
|
||||
required:
|
||||
- external_id
|
||||
- external_key
|
||||
ConfigList:
|
||||
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
|
||||
configs:
|
||||
type: array
|
||||
minItems: 0
|
||||
uniqueItems: true
|
||||
items:
|
||||
$ref: "#/components/schemas/Config"
|
||||
required:
|
||||
- configs
|
||||
BootstrapConfig:
|
||||
type: object
|
||||
properties:
|
||||
thing_id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Corresponding Magistrala Thing ID.
|
||||
thing_key:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Corresponding Magistrala Thing key.
|
||||
channels:
|
||||
type: array
|
||||
minItems: 0
|
||||
items:
|
||||
type: string
|
||||
content:
|
||||
type: string
|
||||
description: Free-form custom configuration.
|
||||
client_cert:
|
||||
type: string
|
||||
description: Client certificate.
|
||||
client_key:
|
||||
type: string
|
||||
description: Key for the client_cert.
|
||||
ca_cert:
|
||||
type: string
|
||||
description: Issuing CA certificate.
|
||||
required:
|
||||
- thing_id
|
||||
- thing_key
|
||||
- channels
|
||||
- content
|
||||
ConfigUpdateCerts:
|
||||
type: object
|
||||
properties:
|
||||
thing_id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Corresponding Magistrala Thing ID.
|
||||
client_cert:
|
||||
type: string
|
||||
description: Client certificate.
|
||||
client_key:
|
||||
type: string
|
||||
description: Key for the client_cert.
|
||||
ca_cert:
|
||||
type: string
|
||||
description: Issuing CA certificate.
|
||||
required:
|
||||
- thing_id
|
||||
- thing_key
|
||||
- channels
|
||||
- content
|
||||
|
||||
parameters:
|
||||
ConfigId:
|
||||
name: configId
|
||||
description: Unique Config identifier. It's the ID of the corresponding Thing.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
ExternalId:
|
||||
name: externalId
|
||||
description: Unique Config identifier provided by external entity.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
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
|
||||
State:
|
||||
name: state
|
||||
description: A state of items
|
||||
in: query
|
||||
schema:
|
||||
$ref: "#/components/schemas/State"
|
||||
required: false
|
||||
Name:
|
||||
name: name
|
||||
description: Name of the config. Search by name is partial-match and case-insensitive.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
|
||||
requestBodies:
|
||||
ConfigCreateReq:
|
||||
description: JSON-formatted document describing the new config.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
external_id:
|
||||
type: string
|
||||
description: External ID (MAC address or some unique identifier).
|
||||
external_key:
|
||||
type: string
|
||||
description: External key.
|
||||
thing_id:
|
||||
type: string
|
||||
description: ID of the corresponding Magistrala Thing.
|
||||
channels:
|
||||
type: array
|
||||
minItems: 0
|
||||
items:
|
||||
type: string
|
||||
content:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
client_cert:
|
||||
type: string
|
||||
description: Thing Certificate.
|
||||
client_key:
|
||||
type: string
|
||||
description: Thing Private Key.
|
||||
ca_cert:
|
||||
type: string
|
||||
required:
|
||||
- external_id
|
||||
- external_key
|
||||
ConfigUpdateReq:
|
||||
description: JSON-formatted document describing the updated thing.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
content:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
required:
|
||||
- content
|
||||
- name
|
||||
ConfigCertUpdateReq:
|
||||
description: JSON-formatted document describing the updated thing.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
client_cert:
|
||||
type: string
|
||||
client_key:
|
||||
type: string
|
||||
ca_cert:
|
||||
type: string
|
||||
ConfigConnUpdateReq:
|
||||
description: Array if IDs the thing is be connected to.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
channels:
|
||||
type: array
|
||||
minItems: 0
|
||||
items:
|
||||
type: string
|
||||
ConfigStateUpdateReq:
|
||||
description: Update the state of the Config.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
state:
|
||||
$ref: "#/components/schemas/State"
|
||||
|
||||
responses:
|
||||
ConfigCreateRes:
|
||||
description: Config registered.
|
||||
headers:
|
||||
Location:
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
description: Created configuration's relative URL (i.e. /things/configs/{configId}).
|
||||
ConfigListRes:
|
||||
description: Data retrieved. Configs from this list don't contain channels.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ConfigList"
|
||||
ConfigRes:
|
||||
description: Data retrieved.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Config"
|
||||
BootstrapConfigRes:
|
||||
description: |
|
||||
Data retrieved. If secure, a response is encrypted using
|
||||
the secret key, so the response is in the binary form.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/BootstrapConfig"
|
||||
ServiceError:
|
||||
description: Unexpected server-side error occurred.
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas/HealthInfo.yml"
|
||||
ConfigUpdateCertsRes:
|
||||
description: Data retrieved. Config certs updated.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ConfigUpdateCerts"
|
||||
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
description: |
|
||||
* Users access: "Authorization: Bearer <user_token>"
|
||||
|
||||
bootstrapAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: string
|
||||
description: |
|
||||
* Things access: "Authorization: Thing <external_key>"
|
||||
|
||||
bootstrapEncAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: aes-sha256-uuid
|
||||
description: |
|
||||
* Things access: "Authorization: Thing <external_enc_key>"
|
||||
Hex-encoded configuration external key encrypted using
|
||||
the AES algorithm and SHA256 sum of the external key
|
||||
itself as an encryption key.
|
||||
|
||||
security:
|
||||
- bearerAuth: []
|
||||
@@ -1,274 +0,0 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: Magistrala Certs service
|
||||
description: |
|
||||
HTTP API for Certs service
|
||||
Some useful links:
|
||||
- [The Magistrala repository](https://github.com/absmach/magistrala)
|
||||
contact:
|
||||
email: info@mainflux.com
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/absmach/magistrala/blob/master/LICENSE
|
||||
version: 0.14.0
|
||||
|
||||
servers:
|
||||
- url: http://localhost:9019
|
||||
- url: https://localhost:9019
|
||||
|
||||
tags:
|
||||
- name: certs
|
||||
description: Everything about your Certs
|
||||
externalDocs:
|
||||
description: Find out more about certs
|
||||
url: https://docs.magistrala.abstractmachines.fr/
|
||||
|
||||
paths:
|
||||
/certs:
|
||||
post:
|
||||
summary: Creates a certificate for thing
|
||||
description: Creates a certificate for thing
|
||||
tags:
|
||||
- certs
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/CertReq"
|
||||
responses:
|
||||
'201':
|
||||
description: Created
|
||||
'400':
|
||||
description: Failed due to malformed JSON.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
'500':
|
||||
description: Unexpected server-side error ocurred.
|
||||
/certs/{certID}:
|
||||
get:
|
||||
summary: Retrieves a certificate
|
||||
description: |
|
||||
Retrieves a certificate for a given cert ID.
|
||||
tags:
|
||||
- certs
|
||||
parameters:
|
||||
- $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.
|
||||
'404':
|
||||
description: |
|
||||
Failed to retrieve corresponding certificate.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
delete:
|
||||
summary: Revokes a certificate
|
||||
description: |
|
||||
Revokes a certificate for a given cert ID.
|
||||
tags:
|
||||
- certs
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/CertID"
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/RevokeRes"
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
'404':
|
||||
description: |
|
||||
Failed to revoke corresponding certificate.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/serials/{thingID}:
|
||||
get:
|
||||
summary: Retrieves certificates' serial IDs
|
||||
description: |
|
||||
Retrieves a list of certificates' serial IDs for a given thing ID.
|
||||
tags:
|
||||
- certs
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ThingID"
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/SerialsPageRes"
|
||||
'400':
|
||||
description: Failed due to malformed query parameters.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
'404':
|
||||
description: |
|
||||
Failed to retrieve corresponding certificates.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/HealthRes"
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
parameters:
|
||||
ThingID:
|
||||
name: thingID
|
||||
description: Thing ID
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
CertID:
|
||||
name: certID
|
||||
description: Serial of certificate
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
|
||||
schemas:
|
||||
Cert:
|
||||
type: object
|
||||
properties:
|
||||
thing_id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Corresponding Magistrala Thing 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:
|
||||
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:
|
||||
type: object
|
||||
properties:
|
||||
revocation_time:
|
||||
type: string
|
||||
description: Certificate revocation time
|
||||
|
||||
requestBodies:
|
||||
CertReq:
|
||||
description: |
|
||||
Issues a certificate that is required for mTLS. To create a certificate for a thing
|
||||
provide a thing id, data identifying particular thing 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:
|
||||
- thing_id
|
||||
- ttl
|
||||
properties:
|
||||
thing_id:
|
||||
type: string
|
||||
format: uuid
|
||||
ttl:
|
||||
type: string
|
||||
example: "10h"
|
||||
|
||||
responses:
|
||||
ServiceError:
|
||||
description: Unexpected server-side error occurred.
|
||||
CertRes:
|
||||
description: Certificate data.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Cert"
|
||||
CertsPageRes:
|
||||
description: Certificates page.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/CertsPage"
|
||||
SerialsPageRes:
|
||||
description: Serials page.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/SerialsPage"
|
||||
RevokeRes:
|
||||
description: Certificate revoked.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Revoke"
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas/HealthInfo.yml"
|
||||
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
description: |
|
||||
* Users access: "Authorization: Bearer <user_token>"
|
||||
|
||||
security:
|
||||
- bearerAuth: []
|
||||
@@ -1,256 +0,0 @@
|
||||
# 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@mainflux.com
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/absmach/magistrala/blob/master/LICENSE
|
||||
version: 0.14.0
|
||||
|
||||
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://docs.magistrala.abstractmachines.fr/
|
||||
|
||||
paths:
|
||||
/subscriptions:
|
||||
post:
|
||||
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.
|
||||
"409":
|
||||
description: Failed due to using an existing topic and contact.
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
get:
|
||||
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.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/subscriptions/{id}:
|
||||
get:
|
||||
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"
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
delete:
|
||||
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.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
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"
|
||||
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/json:
|
||||
schema:
|
||||
$ref: "./schemas/HealthInfo.yml"
|
||||
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
description: |
|
||||
* Users access: "Authorization: Bearer <user_token>"
|
||||
|
||||
security:
|
||||
- bearerAuth: []
|
||||
@@ -1,486 +0,0 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: Magistrala Invitations Service
|
||||
description: |
|
||||
This is the Invitations Server based on the OpenAPI 3.0 specification. It is the HTTP API for managing platform invitations. 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 Magistrala repository](https://github.com/absmach/magistrala)
|
||||
contact:
|
||||
email: info@mainflux.com
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/absmach/magistrala/blob/master/LICENSE
|
||||
version: 0.14.0
|
||||
|
||||
servers:
|
||||
- url: http://localhost:9020
|
||||
- url: https://localhost:9020
|
||||
|
||||
tags:
|
||||
- name: Invitations
|
||||
description: Everything about your Invitations
|
||||
externalDocs:
|
||||
description: Find out more about Invitations
|
||||
url: https://docs.magistrala.abstractmachines.fr/
|
||||
|
||||
paths:
|
||||
/invitations:
|
||||
post:
|
||||
tags:
|
||||
- Invitations
|
||||
summary: Send invitation
|
||||
description: |
|
||||
Send invitation to user to join domain.
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/SendInvitationReq"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"201":
|
||||
description: Invitation sent.
|
||||
"400":
|
||||
description: Failed due to malformed JSON.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"409":
|
||||
description: Failed due to using an existing identity.
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
get:
|
||||
tags:
|
||||
- Invitations
|
||||
summary: List invitations
|
||||
description: |
|
||||
Retrieves a list of invitations. 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/Limit"
|
||||
- $ref: "#/components/parameters/Offset"
|
||||
- $ref: "#/components/parameters/UserID"
|
||||
- $ref: "#/components/parameters/InvitedBy"
|
||||
- $ref: "#/components/parameters/DomainID"
|
||||
- $ref: "#/components/parameters/Relation"
|
||||
- $ref: "#/components/parameters/State"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/InvitationPageRes"
|
||||
"400":
|
||||
description: Failed due to malformed query parameters.
|
||||
"401":
|
||||
description: |
|
||||
Missing or invalid access token provided.
|
||||
This endpoint is available only for administrators.
|
||||
"404":
|
||||
description: A non-existent entity request.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/invitations/accept:
|
||||
post:
|
||||
summary: Accept invitation
|
||||
description: |
|
||||
Current logged in user accepts invitation to join domain.
|
||||
tags:
|
||||
- Invitations
|
||||
security:
|
||||
- bearerAuth: []
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/AcceptInvitationReq"
|
||||
responses:
|
||||
"200":
|
||||
description: Invitation accepted.
|
||||
"400":
|
||||
description: Failed due to malformed query parameters.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/invitations/{user_id}/{domain_id}:
|
||||
get:
|
||||
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/user_id"
|
||||
- $ref: "#/components/parameters/domain_id"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/InvitationRes"
|
||||
"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"
|
||||
|
||||
delete:
|
||||
summary: Deletes a specific invitation
|
||||
description: |
|
||||
Deletes a specific invitation that is identifier by the user ID and domain ID.
|
||||
tags:
|
||||
- Invitations
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/user_id"
|
||||
- $ref: "#/components/parameters/domain_id"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"204":
|
||||
description: Invitation deleted.
|
||||
"400":
|
||||
description: Failed due to malformed JSON.
|
||||
"404":
|
||||
description: Failed due to non existing user.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/HealthRes"
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
schemas:
|
||||
SendInvitationReqObj:
|
||||
type: object
|
||||
properties:
|
||||
user_id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
description: User unique identifier.
|
||||
domain_id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
description: Domain unique identifier.
|
||||
relation:
|
||||
type: string
|
||||
enum:
|
||||
- administrator
|
||||
- editor
|
||||
- viewer
|
||||
- member
|
||||
- domain
|
||||
- parent_group
|
||||
- role_group
|
||||
- group
|
||||
- platform
|
||||
example: editor
|
||||
description: Relation between user and domain.
|
||||
resend:
|
||||
type: boolean
|
||||
example: true
|
||||
description: Resend invitation.
|
||||
required:
|
||||
- user_id
|
||||
- domain_id
|
||||
- relation
|
||||
|
||||
Invitation:
|
||||
type: object
|
||||
properties:
|
||||
invited_by:
|
||||
type: string
|
||||
format: uuid
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
description: User unique identifier.
|
||||
user_id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
description: User unique identifier.
|
||||
domain_id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
description: Domain unique identifier.
|
||||
relation:
|
||||
type: string
|
||||
enum:
|
||||
- administrator
|
||||
- editor
|
||||
- viewer
|
||||
- member
|
||||
- domain
|
||||
- parent_group
|
||||
- role_group
|
||||
- group
|
||||
- platform
|
||||
example: editor
|
||||
description: Relation between user and domain.
|
||||
created_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2019-11-26 13:31:52"
|
||||
description: Time when the group was created.
|
||||
updated_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2019-11-26 13:31:52"
|
||||
description: Time when the group was created.
|
||||
confirmed_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2019-11-26 13:31:52"
|
||||
description: Time when the group was created.
|
||||
xml:
|
||||
name: invitation
|
||||
|
||||
InvitationPage:
|
||||
type: object
|
||||
properties:
|
||||
invitations:
|
||||
type: array
|
||||
minItems: 0
|
||||
uniqueItems: true
|
||||
items:
|
||||
$ref: "#/components/schemas/Invitation"
|
||||
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:
|
||||
- invitations
|
||||
- total
|
||||
- offset
|
||||
|
||||
Error:
|
||||
type: object
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
description: Error message
|
||||
example: { "error": "malformed entity specification" }
|
||||
|
||||
HealthRes:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
description: Service status.
|
||||
enum:
|
||||
- pass
|
||||
version:
|
||||
type: string
|
||||
description: Service version.
|
||||
example: 0.14.0
|
||||
commit:
|
||||
type: string
|
||||
description: Service commit hash.
|
||||
example: 7d6f4dc4f7f0c1fa3dc24eddfb18bb5073ff4f62
|
||||
description:
|
||||
type: string
|
||||
description: Service description.
|
||||
example: <service_name> service
|
||||
build_time:
|
||||
type: string
|
||||
description: Service build time.
|
||||
example: 1970-01-01_00:00:00
|
||||
|
||||
parameters:
|
||||
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"
|
||||
|
||||
UserID:
|
||||
name: user_id
|
||||
description: Unique user identifier.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
|
||||
user_id:
|
||||
name: user_id
|
||||
description: Unique user identifier.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
|
||||
DomainID:
|
||||
name: domain_id
|
||||
description: Unique identifier for a domain.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: false
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
|
||||
domain_id:
|
||||
name: domain_id
|
||||
description: Unique identifier for a domain.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
|
||||
InvitedBy:
|
||||
name: invited_by
|
||||
description: Unique identifier for a user that invited the user.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: false
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
|
||||
Relation:
|
||||
name: relation
|
||||
description: Relation between user and domain.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- administrator
|
||||
- editor
|
||||
- viewer
|
||||
- member
|
||||
- domain
|
||||
- parent_group
|
||||
- role_group
|
||||
- group
|
||||
- platform
|
||||
required: false
|
||||
example: editor
|
||||
|
||||
State:
|
||||
name: state
|
||||
description: Invitation state.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- pending
|
||||
- accepted
|
||||
- all
|
||||
required: false
|
||||
example: accepted
|
||||
|
||||
requestBodies:
|
||||
SendInvitationReq:
|
||||
description: JSON-formatted document describing request for sending invitation
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/SendInvitationReqObj"
|
||||
|
||||
AcceptInvitationReq:
|
||||
description: JSON-formatted document describing request for accepting invitation
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
domain_id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
description: Domain unique identifier.
|
||||
required:
|
||||
- domain_id
|
||||
|
||||
responses:
|
||||
InvitationRes:
|
||||
description: Data retrieved.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Invitation"
|
||||
|
||||
InvitationPageRes:
|
||||
description: Data retrieved.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/InvitationPage"
|
||||
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/health+json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/HealthRes"
|
||||
|
||||
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: []
|
||||
@@ -1,116 +0,0 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: Magistrala Provision service
|
||||
description: |
|
||||
HTTP API for Provision service
|
||||
Some useful links:
|
||||
- [The Magistrala repository](https://github.com/absmach/magistrala)
|
||||
contact:
|
||||
email: info@mainflux.com
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/absmach/magistrala/blob/master/LICENSE
|
||||
version: 0.14.0
|
||||
|
||||
servers:
|
||||
- url: http://localhost:9016
|
||||
- url: https://localhost:9016
|
||||
|
||||
tags:
|
||||
- name: provision
|
||||
description: Everything about your Provision
|
||||
externalDocs:
|
||||
description: Find out more about provision
|
||||
url: https://docs.magistrala.abstractmachines.fr/
|
||||
|
||||
paths:
|
||||
/mapping:
|
||||
post:
|
||||
summary: Adds new device to proxy
|
||||
description: Adds new device to proxy
|
||||
tags:
|
||||
- provision
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/ProvisionReq"
|
||||
responses:
|
||||
'201':
|
||||
description: Created
|
||||
'400':
|
||||
description: Failed due to malformed JSON.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
get:
|
||||
summary: Gets current mapping.
|
||||
description: Gets current mapping. This can be used in UI
|
||||
so that when bootstrap config is created from UI matches
|
||||
configuration created with provision service.
|
||||
tags:
|
||||
- provision
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/ProvisionRes"
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/HealthRes"
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
requestBodies:
|
||||
ProvisionReq:
|
||||
description: MAC address of device or other identifier
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- external_id
|
||||
- external_key
|
||||
properties:
|
||||
external_id:
|
||||
type: string
|
||||
external_key:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
|
||||
responses:
|
||||
ServiceError:
|
||||
description: Unexpected server-side error occurred.
|
||||
ProvisionRes:
|
||||
description: Current mapping JSON representation.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas/HealthInfo.yml"
|
||||
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
description: |
|
||||
* Users access: "Authorization: Bearer <user_token>"
|
||||
|
||||
security:
|
||||
- bearerAuth: []
|
||||
@@ -1,271 +0,0 @@
|
||||
# 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@mainflux.com
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/absmach/magistrala/blob/master/LICENSE
|
||||
version: 0.14.0
|
||||
|
||||
servers:
|
||||
- url: http://localhost:9003
|
||||
- url: https://localhost:9003
|
||||
- url: http://localhost:9005
|
||||
- url: https://localhost:9005
|
||||
- url: http://localhost:9007
|
||||
- url: https://localhost:9007
|
||||
- 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://docs.magistrala.abstractmachines.fr/
|
||||
|
||||
paths:
|
||||
/channels/{chanId}/messages:
|
||||
get:
|
||||
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/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"
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/MessagesPageRes"
|
||||
'400':
|
||||
description: Failed due to malformed query parameters.
|
||||
'401':
|
||||
description: Missing or invalid access token provided.
|
||||
'500':
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
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:
|
||||
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
|
||||
required: false
|
||||
To:
|
||||
name: to
|
||||
description: SenML message time in nanoseconds (integer part represents seconds).
|
||||
in: query
|
||||
schema:
|
||||
type: number
|
||||
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/json:
|
||||
schema:
|
||||
$ref: "./schemas/HealthInfo.yml"
|
||||
|
||||
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: []
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,402 +0,0 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: Magistrala twins service
|
||||
description: |
|
||||
HTTP API for managing digital twins and their states.
|
||||
Some useful links:
|
||||
- [The Magistrala repository](https://github.com/absmach/magistrala)
|
||||
contact:
|
||||
email: info@mainflux.com
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/absmach/magistrala/blob/master/LICENSE
|
||||
version: 0.14.0
|
||||
|
||||
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.magistrala.abstractmachines.fr/
|
||||
|
||||
|
||||
paths:
|
||||
/twins:
|
||||
post:
|
||||
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.
|
||||
'500':
|
||||
$ref: '#/components/responses/ServiceError'
|
||||
|
||||
get:
|
||||
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.
|
||||
'500':
|
||||
$ref: '#/components/responses/ServiceError'
|
||||
|
||||
/twins/{twinID}:
|
||||
get:
|
||||
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.
|
||||
'500':
|
||||
$ref: '#/components/responses/ServiceError'
|
||||
put:
|
||||
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.
|
||||
'500':
|
||||
$ref: '#/components/responses/ServiceError'
|
||||
delete:
|
||||
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.
|
||||
'500':
|
||||
$ref: '#/components/responses/ServiceError'
|
||||
|
||||
/states/{twinID}:
|
||||
get:
|
||||
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.
|
||||
'500':
|
||||
$ref: '#/components/responses/ServiceError'
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
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: Magistrala 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
|
||||
uniqueItems: true
|
||||
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 Magistrala 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
|
||||
uniqueItems: true
|
||||
items:
|
||||
$ref: '#/components/schemas/Definition'
|
||||
metadata:
|
||||
type: object
|
||||
description: Arbitrary, object-encoded twin's data.
|
||||
TwinsPage:
|
||||
type: object
|
||||
properties:
|
||||
twins:
|
||||
type: array
|
||||
minItems: 0
|
||||
uniqueItems: true
|
||||
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:
|
||||
twins:
|
||||
type: array
|
||||
minItems: 0
|
||||
uniqueItems: true
|
||||
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:
|
||||
- twins
|
||||
|
||||
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'
|
||||
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/json:
|
||||
schema:
|
||||
$ref: "./schemas/HealthInfo.yml"
|
||||
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
description: |
|
||||
* Users access: "Authorization: Bearer <user_token>"
|
||||
|
||||
security:
|
||||
- bearerAuth: []
|
||||
@@ -2,23 +2,23 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
asyncapi: '2.6.0'
|
||||
id: 'https://github.com/absmach/magistrala/blob/master/api/asyncapi/mqtt.yml'
|
||||
id: 'https://github.com/absmach/supermq/blob/main/api/asyncapi/mqtt.yaml'
|
||||
info:
|
||||
title: Magistrala MQTT Adapter
|
||||
version: '1.0.0'
|
||||
title: SuperMQ MQTT Adapter
|
||||
version: '0.18.0'
|
||||
contact:
|
||||
name: Magistrala Team
|
||||
url: 'https://github.com/absmach/magistrala'
|
||||
email: info@mainflux.com
|
||||
name: SuperMQ Team
|
||||
url: 'https://github.com/absmach/supermq'
|
||||
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/magistrala/blob/master/LICENSE'
|
||||
|
||||
|
||||
url: 'https://github.com/absmach/supermq/blob/main/LICENSE'
|
||||
|
||||
|
||||
defaultContentType: application/json
|
||||
|
||||
servers:
|
||||
@@ -33,19 +33,23 @@ servers:
|
||||
enum:
|
||||
- '1883'
|
||||
- '8883'
|
||||
security:
|
||||
security:
|
||||
- user-password: []
|
||||
|
||||
channels:
|
||||
channels/{channelID}/messages/{subtopic}:
|
||||
/m/{domainPrefix}/c/{channelPrefix}/{subtopic}:
|
||||
parameters:
|
||||
channelID:
|
||||
$ref: '#/components/parameters/channelID'
|
||||
domainPrefix:
|
||||
$ref: '#/components/parameters/domainPrefix'
|
||||
in: path
|
||||
required: true
|
||||
channelPrefix:
|
||||
$ref: '#/components/parameters/channelPrefix'
|
||||
in: path
|
||||
required: true
|
||||
subtopic:
|
||||
$ref: '#/components/parameters/subtopic'
|
||||
in: path
|
||||
in: path
|
||||
required: false
|
||||
|
||||
publish:
|
||||
@@ -87,23 +91,26 @@ components:
|
||||
```
|
||||
|
||||
parameters:
|
||||
channelID:
|
||||
description: Channel ID connected to the Thing ID defined in the username.
|
||||
domainPrefix:
|
||||
description: ID or route of the domain associated with the channel and client.
|
||||
schema:
|
||||
type: string
|
||||
channelPrefix:
|
||||
description: ID or route of the channel connected to the Client ID defined in the username.
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
subtopic:
|
||||
description: Arbitrary message subtopic.
|
||||
schema:
|
||||
type: string
|
||||
default: ''
|
||||
|
||||
|
||||
securitySchemes:
|
||||
user-password:
|
||||
type: userPassword
|
||||
description: |
|
||||
username is thing ID connected to the channel defined in the mqtt topic and
|
||||
password is thing key corresponding to the thing ID
|
||||
username is client ID connected to the channel defined in the mqtt topic and
|
||||
password is client secret corresponding to the client ID
|
||||
|
||||
operationTraits:
|
||||
mqtt:
|
||||
@@ -2,18 +2,18 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
asyncapi: 2.6.0
|
||||
id: 'https://github.com/absmach/magistrala/blob/master/api/asyncapi/websocket.yml'
|
||||
id: 'https://github.com/absmach/supermq/blob/main/api/asyncapi/websocket.yaml'
|
||||
info:
|
||||
title: Magistrala WebSocket adapter
|
||||
title: SuperMQ 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: Magistrala Team
|
||||
url: 'https://github.com/absmach/magistrala'
|
||||
email: info@mainflux.com
|
||||
name: SuperMQ Team
|
||||
url: 'https://github.com/absmach/supermq'
|
||||
email: info@absmach.eu
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: 'https://github.com/absmach/magistrala/blob/master/LICENSE'
|
||||
url: 'https://github.com/absmach/supermq/blob/main/LICENSE'
|
||||
tags:
|
||||
- name: WebSocket
|
||||
defaultContentType: application/json
|
||||
@@ -28,14 +28,18 @@ servers:
|
||||
description: Hostname of the WebSocket adapter
|
||||
default: localhost
|
||||
port:
|
||||
description: Magistrala WebSocket Adapter port
|
||||
default: '8186'
|
||||
description: SuperMQ WebSocket Adapter port
|
||||
default: '8008'
|
||||
|
||||
channels:
|
||||
'channels/{channelID}/messages/{subtopic}':
|
||||
'm/{domainPrefix}/c/{channelPrefix}/{subtopic}':
|
||||
parameters:
|
||||
channelID:
|
||||
$ref: '#/components/parameters/channelID'
|
||||
domainPrefix:
|
||||
$ref: '#/components/parameters/domainPrefix'
|
||||
in: path
|
||||
required: true
|
||||
channelPrefix:
|
||||
$ref: '#/components/parameters/channelPrefix'
|
||||
in: path
|
||||
required: true
|
||||
subtopic:
|
||||
@@ -70,7 +74,7 @@ channels:
|
||||
- bearerAuth: []
|
||||
/version:
|
||||
subscribe:
|
||||
summary: Get the version of the Magistrala adapter
|
||||
summary: Get the version of the SuperMQ adapter
|
||||
operationId: getVersion
|
||||
bindings:
|
||||
http:
|
||||
@@ -125,11 +129,14 @@ components:
|
||||
|
||||
```
|
||||
parameters:
|
||||
channelID:
|
||||
description: Channel ID connected to the Thing ID defined in the username.
|
||||
domainPrefix:
|
||||
description: ID or route of the domain associated with the channel and client.
|
||||
schema:
|
||||
type: string
|
||||
channelPrefix:
|
||||
description: ID or route of the channel connected to the Client ID defined in the username.
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
subtopic:
|
||||
description: Arbitrary message subtopic.
|
||||
schema:
|
||||
@@ -141,4 +148,4 @@ components:
|
||||
scheme: bearer
|
||||
bearerFormat: uuid
|
||||
description: |
|
||||
* Thing access: "Authorization: Thing <thing_key>"
|
||||
* Client access: "Authorization: Client <client_key>"
|
||||
@@ -0,0 +1,5 @@
|
||||
# SuperMQ OpenAPI Specification
|
||||
|
||||
This folder contains an OpenAPI specifications for SuperMQ API.
|
||||
|
||||
View specification in Swagger UI at [docs.api.supermq.absmach.eu](https://docs.api.supermq.absmach.eu)
|
||||
@@ -0,0 +1,851 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: SuperMQ 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)
|
||||
contact:
|
||||
email: info@absmach.eu
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/absmach/supermq/blob/main/LICENSE
|
||||
version: 0.18.0
|
||||
|
||||
servers:
|
||||
- url: http://localhost:9001
|
||||
- url: https://localhost:9001
|
||||
|
||||
tags:
|
||||
- name: Keys
|
||||
description: Everything about your Keys.
|
||||
externalDocs:
|
||||
description: Find out more about keys
|
||||
url: https://docs.supermq.absmach.eu/
|
||||
- name: PATs
|
||||
description: Everything about your Personal Access Tokens.
|
||||
externalDocs:
|
||||
description: Find out more about Personal Access Tokens
|
||||
url: https://docs.supermq.absmach.eu/
|
||||
- name: Health
|
||||
description: Service health check endpoint.
|
||||
externalDocs:
|
||||
description: Find out more about health check
|
||||
url: https://docs.supermq.absmach.eu/
|
||||
|
||||
paths:
|
||||
/keys:
|
||||
post:
|
||||
operationId: issueKey
|
||||
tags:
|
||||
- Keys
|
||||
summary: Issue API key
|
||||
description: |
|
||||
Generates a new API key. Thew new API key will
|
||||
be uniquely identified by its ID.
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/KeyRequest"
|
||||
responses:
|
||||
"201":
|
||||
description: Issued new key.
|
||||
"400":
|
||||
description: Failed due to malformed JSON.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"409":
|
||||
description: Failed due to using already existing ID.
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/keys/{keyID}:
|
||||
get:
|
||||
operationId: getKey
|
||||
summary: Gets API key details.
|
||||
description: |
|
||||
Gets API key details for the given key.
|
||||
tags:
|
||||
- Keys
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ApiKeyId"
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/KeyRes"
|
||||
"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: Service can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
delete:
|
||||
operationId: revokeKey
|
||||
summary: Revoke API key
|
||||
description: |
|
||||
Revoke API key identified by the given ID.
|
||||
tags:
|
||||
- Keys
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ApiKeyId"
|
||||
responses:
|
||||
"204":
|
||||
description: Key revoked.
|
||||
"401":
|
||||
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"
|
||||
|
||||
/pats:
|
||||
post:
|
||||
operationId: createPAT
|
||||
tags:
|
||||
- PATs
|
||||
summary: Create a new Personal Access Token
|
||||
description: |
|
||||
Creates a new Personal Access Token (PAT) for the authenticated user.
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/CreatePATRequest"
|
||||
responses:
|
||||
"201":
|
||||
$ref: "#/components/responses/PATRes"
|
||||
"400":
|
||||
description: Failed due to malformed JSON or validation errors.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
get:
|
||||
operationId: listPATs
|
||||
tags:
|
||||
- PATs
|
||||
summary: List all Personal Access Tokens
|
||||
description: |
|
||||
Lists all Personal Access Tokens (PATs) for the authenticated user.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Limit"
|
||||
- $ref: "#/components/parameters/Offset"
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/PATsPageRes"
|
||||
"400":
|
||||
description: Failed due to malformed query parameters.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
delete:
|
||||
operationId: clearAllPATs
|
||||
tags:
|
||||
- PATs
|
||||
summary: Remove all Personal Access Tokens
|
||||
description: |
|
||||
Removes all Personal Access Tokens (PATs) for the authenticated user.
|
||||
responses:
|
||||
"200":
|
||||
description: All PATs removed successfully.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/pats/{patID}:
|
||||
get:
|
||||
operationId: retrievePAT
|
||||
tags:
|
||||
- PATs
|
||||
summary: Retrieve a Personal Access Token
|
||||
description: |
|
||||
Retrieves details of a specific Personal Access Token (PAT).
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/PatID"
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/PATRes"
|
||||
"400":
|
||||
description: Failed due to malformed query parameters.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: PAT not found.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
delete:
|
||||
operationId: deletePAT
|
||||
tags:
|
||||
- PATs
|
||||
summary: Delete a Personal Access Token
|
||||
description: |
|
||||
Deletes a specific Personal Access Token (PAT).
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/PatID"
|
||||
responses:
|
||||
"204":
|
||||
description: PAT deleted successfully.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: PAT not found.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/pats/{patID}/name:
|
||||
patch:
|
||||
operationId: updatePATName
|
||||
tags:
|
||||
- PATs
|
||||
summary: Update Personal Access Token name
|
||||
description: |
|
||||
Updates the name of a specific Personal Access Token (PAT).
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/PatID"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/UpdatePATNameRequest"
|
||||
responses:
|
||||
"202":
|
||||
$ref: "#/components/responses/PATRes"
|
||||
"400":
|
||||
description: Failed due to malformed JSON or validation errors.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: PAT not found.
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/pats/{patID}/description:
|
||||
patch:
|
||||
operationId: updatePATDescription
|
||||
tags:
|
||||
- PATs
|
||||
summary: Update Personal Access Token description
|
||||
description: |
|
||||
Updates the description of a specific Personal Access Token (PAT).
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/PatID"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/UpdatePATDescriptionRequest"
|
||||
responses:
|
||||
"202":
|
||||
$ref: "#/components/responses/PATRes"
|
||||
"400":
|
||||
description: Failed due to malformed JSON or validation errors.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: PAT not found.
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/pats/{patID}/secret/reset:
|
||||
patch:
|
||||
operationId: resetPATSecret
|
||||
tags:
|
||||
- PATs
|
||||
summary: Reset Personal Access Token secret
|
||||
description: |
|
||||
Resets the secret of a specific Personal Access Token (PAT).
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/PatID"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/ResetPATSecretRequest"
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/PATRes"
|
||||
"400":
|
||||
description: Failed due to malformed JSON or validation errors.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: PAT not found.
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/pats/{patID}/secret/revoke:
|
||||
patch:
|
||||
operationId: revokePATSecret
|
||||
tags:
|
||||
- PATs
|
||||
summary: Revoke Personal Access Token secret
|
||||
description: |
|
||||
Revokes the secret of a specific Personal Access Token (PAT).
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/PatID"
|
||||
responses:
|
||||
"204":
|
||||
description: PAT secret revoked successfully.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: PAT not found.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/pats/{patID}/scope:
|
||||
get:
|
||||
operationId: listScopes
|
||||
tags:
|
||||
- PATs
|
||||
summary: List scopes for a Personal Access Token
|
||||
description: |
|
||||
Lists all scopes for a specific Personal Access Token (PAT).
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/PatID"
|
||||
- $ref: "#/components/parameters/Limit"
|
||||
- $ref: "#/components/parameters/Offset"
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/ScopesPageRes"
|
||||
"400":
|
||||
description: Failed due to malformed query parameters.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: PAT not found.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
delete:
|
||||
operationId: clearAllScopes
|
||||
tags:
|
||||
- PATs
|
||||
summary: Remove all scopes from a Personal Access Token
|
||||
description: |
|
||||
Removes all scopes from a specific Personal Access Token (PAT).
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/PatID"
|
||||
responses:
|
||||
"200":
|
||||
description: All scopes removed successfully.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: PAT not found.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/pats/{patID}/scope/add:
|
||||
patch:
|
||||
operationId: addScope
|
||||
tags:
|
||||
- PATs
|
||||
summary: Add scope to a Personal Access Token
|
||||
description: |
|
||||
Adds a scope to a specific Personal Access Token (PAT).
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/PatID"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/AddScopeRequest"
|
||||
responses:
|
||||
"200":
|
||||
description: Scope added successfully.
|
||||
"400":
|
||||
description: Failed due to malformed JSON or validation errors.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: PAT not found.
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
"422":
|
||||
description: Database cannot process the request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/pats/{patID}/scope/remove:
|
||||
patch:
|
||||
operationId: removeScope
|
||||
tags:
|
||||
- PATs
|
||||
summary: Remove scope from a Personal Access Token
|
||||
description: |
|
||||
Removes a scope from a specific Personal Access Token (PAT).
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/PatID"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/RemoveScopeRequest"
|
||||
responses:
|
||||
"200":
|
||||
description: Scope removed successfully.
|
||||
"400":
|
||||
description: Failed due to malformed JSON or validation errors.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: PAT not found.
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
"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:
|
||||
PAT:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: "c5747f2f-2a7c-4fe1-b41a-51a5ae290945"
|
||||
description: Personal Access Token unique identifier
|
||||
user_id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: "9118de62-c680-46b7-ad0a-21748a52833a"
|
||||
description: User ID of the PAT owner
|
||||
name:
|
||||
type: string
|
||||
example: "My PAT"
|
||||
description: Name of the Personal Access Token
|
||||
description:
|
||||
type: string
|
||||
example: "Token for automation"
|
||||
description: Description of the Personal Access Token
|
||||
secret:
|
||||
type: string
|
||||
example: "pat_1234567890abcdef"
|
||||
description: Secret value of the Personal Access Token
|
||||
issued_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2019-11-26T13:31:52Z"
|
||||
description: Time when the PAT was issued
|
||||
expires_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2020-11-26T13:31:52Z"
|
||||
description: Time when the PAT expires
|
||||
updated_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2019-11-26T13:31:52Z"
|
||||
description: Time when the PAT was last updated
|
||||
last_used_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2019-11-26T13:31:52Z"
|
||||
description: Time when the PAT was last used
|
||||
revoked:
|
||||
type: boolean
|
||||
example: false
|
||||
description: Whether the PAT is revoked
|
||||
revoked_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2019-11-26T13:31:52Z"
|
||||
description: Time when the PAT was revoked
|
||||
|
||||
PATsPage:
|
||||
type: object
|
||||
properties:
|
||||
total:
|
||||
type: integer
|
||||
example: 10
|
||||
description: Total number of PATs
|
||||
offset:
|
||||
type: integer
|
||||
example: 0
|
||||
description: Number of items to skip during retrieval
|
||||
limit:
|
||||
type: integer
|
||||
example: 10
|
||||
description: Size of the subset to retrieve
|
||||
pats:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/PAT"
|
||||
description: List of Personal Access Tokens
|
||||
|
||||
Scope:
|
||||
type: object
|
||||
properties:
|
||||
optional_domain_id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: "bb7edb32-2eac-4aad-aebe-ed96fe073879"
|
||||
description: Optional domain ID for the scope
|
||||
entity_type:
|
||||
type: string
|
||||
enum:
|
||||
[groups, channels, clients, domains, users, dashboards, messages]
|
||||
example: "groups"
|
||||
description: Type of entity the scope applies to
|
||||
entity_id:
|
||||
type: string
|
||||
example: "*"
|
||||
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,
|
||||
]
|
||||
example: "read"
|
||||
description: Operation allowed by this scope
|
||||
|
||||
ScopesPage:
|
||||
type: object
|
||||
properties:
|
||||
total:
|
||||
type: integer
|
||||
example: 10
|
||||
description: Total number of scopes
|
||||
offset:
|
||||
type: integer
|
||||
example: 0
|
||||
description: Number of items to skip during retrieval
|
||||
limit:
|
||||
type: integer
|
||||
example: 10
|
||||
description: Size of the subset to retrieve
|
||||
scopes:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Scope"
|
||||
description: List of scopes
|
||||
Key:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: "c5747f2f-2a7c-4fe1-b41a-51a5ae290945"
|
||||
description: API key unique identifier
|
||||
issuer_id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: "9118de62-c680-46b7-ad0a-21748a52833a"
|
||||
description: In ID of the entity that issued the token.
|
||||
type:
|
||||
type: integer
|
||||
example: 0
|
||||
description: API key type. Keys of different type are processed differently.
|
||||
subject:
|
||||
type: string
|
||||
format: string
|
||||
example: "test@example.com"
|
||||
description: User's email or service identifier of API key subject.
|
||||
issued_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2019-11-26 13:31:52"
|
||||
description: Time when the key is generated.
|
||||
expires_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2019-11-26 13:31:52"
|
||||
description: Time when the Key expires. If this field is missing,
|
||||
that means that Key is valid indefinitely.
|
||||
|
||||
parameters:
|
||||
PatID:
|
||||
name: patID
|
||||
description: Personal Access Token ID.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
DomainID:
|
||||
name: domainID
|
||||
description: Unique domain identifier.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
Status:
|
||||
name: status
|
||||
description: Domain status.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
default: enabled
|
||||
required: false
|
||||
example: enabled
|
||||
DomainName:
|
||||
name: name
|
||||
description: Domain's name.
|
||||
in: query
|
||||
schema:
|
||||
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.
|
||||
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
|
||||
Metadata:
|
||||
name: metadata
|
||||
description: Metadata filter. Filtering is performed matching the parameter with metadata on top level. Parameter is json.
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
Type:
|
||||
name: type
|
||||
description: The type of the API Key.
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 0
|
||||
minimum: 0
|
||||
required: false
|
||||
Subject:
|
||||
name: subject
|
||||
description: The subject of an API Key
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
|
||||
requestBodies:
|
||||
CreatePATRequest:
|
||||
description: JSON-formatted document describing PAT creation request.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
- duration
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
minLength: 1
|
||||
example: "My PAT"
|
||||
description: Name of the Personal Access Token
|
||||
description:
|
||||
type: string
|
||||
example: "Token for automation"
|
||||
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
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
properties:
|
||||
name:
|
||||
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
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- description
|
||||
properties:
|
||||
description:
|
||||
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
|
||||
content:
|
||||
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
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- scopes
|
||||
properties:
|
||||
scopes:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Scope"
|
||||
description: List of scopes to add
|
||||
|
||||
RemoveScopeRequest:
|
||||
description: JSON-formatted document describing remove scope request.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- scopes_id
|
||||
properties:
|
||||
scopes_id:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
format: uuid
|
||||
description: List of scope IDs to remove
|
||||
KeyRequest:
|
||||
description: JSON-formatted document describing key request.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
type: integer
|
||||
example: 0
|
||||
description: API key type. Keys of different type are processed differently.
|
||||
duration:
|
||||
type: number
|
||||
format: integer
|
||||
example: 23456
|
||||
description: Number of seconds issued token is valid for.
|
||||
|
||||
responses:
|
||||
PATRes:
|
||||
description: Personal Access Token data.
|
||||
content:
|
||||
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:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ScopesPage"
|
||||
ServiceError:
|
||||
description: Unexpected server-side error occurred.
|
||||
KeyRes:
|
||||
description: Data retrieved.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Key"
|
||||
links:
|
||||
revoke:
|
||||
operationId: revokeKey
|
||||
parameters:
|
||||
keyID: $response.body#/id
|
||||
|
||||
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: []
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -3,17 +3,17 @@
|
||||
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: Magistrala http adapter
|
||||
title: SuperMQ http adapter
|
||||
description: |
|
||||
HTTP API for sending messages through communication channels.
|
||||
Some useful links:
|
||||
- [The Magistrala repository](https://github.com/absmach/magistrala)
|
||||
- [The SuperMQ repository](https://github.com/absmach/supermq)
|
||||
contact:
|
||||
email: info@mainflux.com
|
||||
email: info@absmach.eu
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/absmach/magistrala/blob/master/LICENSE
|
||||
version: 0.14.0
|
||||
url: https://github.com/absmach/supermq/blob/main/LICENSE
|
||||
version: 0.18.0
|
||||
|
||||
servers:
|
||||
- url: http://localhost:8008
|
||||
@@ -24,10 +24,10 @@ tags:
|
||||
description: Everything about your Messages
|
||||
externalDocs:
|
||||
description: Find out more about messages
|
||||
url: https://docs.magistrala.abstractmachines.fr/
|
||||
|
||||
url: https://docs.supermq.absmach.eu/
|
||||
|
||||
paths:
|
||||
/channels/{id}/messages:
|
||||
/m/{domainPrefix}/c/{channelPrefix}:
|
||||
post:
|
||||
summary: Sends message to the communication channel
|
||||
description: |
|
||||
@@ -36,7 +36,8 @@ paths:
|
||||
tags:
|
||||
- messages
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ID"
|
||||
- $ref: "#/components/parameters/domainPrefix"
|
||||
- $ref: "#/components/parameters/channelPrefix"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/MessageReq"
|
||||
responses:
|
||||
@@ -46,21 +47,24 @@ 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":
|
||||
description: Message discarded due to invalid or missing content type.
|
||||
'500':
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
security: []
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
$ref: "#/components/responses/HealthRes"
|
||||
'500':
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
@@ -128,13 +132,21 @@ components:
|
||||
$ref: "#/components/schemas/SenMLRecord"
|
||||
|
||||
parameters:
|
||||
ID:
|
||||
name: id
|
||||
description: Unique channel identifier.
|
||||
domainPrefix:
|
||||
name: domainPrefix
|
||||
description: ID or route of the domain associated with the channel and client.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
example: mydomain
|
||||
required: true
|
||||
channelPrefix:
|
||||
name: channelPrefix
|
||||
description: ID or route of the channel connected to the client.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
example: mychannel
|
||||
required: true
|
||||
|
||||
requestBodies:
|
||||
@@ -154,13 +166,13 @@ components:
|
||||
responses:
|
||||
ServiceError:
|
||||
description: Unexpected server-side error occurred.
|
||||
|
||||
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/json:
|
||||
application/health+json:
|
||||
schema:
|
||||
$ref: "./schemas/HealthInfo.yml"
|
||||
$ref: "./schemas/health_info.yaml"
|
||||
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
@@ -168,13 +180,13 @@ components:
|
||||
scheme: bearer
|
||||
bearerFormat: uuid
|
||||
description: |
|
||||
* Thing access: "Authorization: Thing <thing_key>"
|
||||
* Client access: "Authorization: Client <client_key>"
|
||||
|
||||
basicAuth:
|
||||
type: http
|
||||
scheme: basic
|
||||
description: |
|
||||
* Things access: "Authorization: Basic <base64-encoded_credentials>"
|
||||
* Clients access: "Authorization: Basic <base64-encoded_credentials>"
|
||||
|
||||
security:
|
||||
- bearerAuth: []
|
||||
@@ -0,0 +1,426 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: SuperMQ Journal Log Service
|
||||
description: |
|
||||
This is the Journal Log Server based on the OpenAPI 3.0 specification. It is the HTTP API for viewing journal log history. You can now help us improve the API whether it's by making changes to the definition itself or to the code.
|
||||
Some useful links:
|
||||
- [The SuperMQ repository](https://github.com/absmach/supermq)
|
||||
contact:
|
||||
email: info@mainflux.com
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/absmach/supermq/blob/main/LICENSE
|
||||
version: 0.18.0
|
||||
|
||||
servers:
|
||||
- url: http://localhost:9021
|
||||
- url: https://localhost:9021
|
||||
|
||||
tags:
|
||||
- name: journal-log
|
||||
description: Everything about your Journal Log
|
||||
externalDocs:
|
||||
description: Find out more about Journal Log
|
||||
url: http://docs.mainflux.io/
|
||||
|
||||
paths:
|
||||
/journal/user/{userID}:
|
||||
get:
|
||||
tags:
|
||||
- journal-log
|
||||
summary: List user journal log
|
||||
description: |
|
||||
Retrieves a list of journal. Due to performance concerns, data
|
||||
is retrieved in subsets. The API must ensure that the entire
|
||||
dataset is consumed either by making subsequent requests, or by
|
||||
increasing the subset size of the initial request.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/user_id"
|
||||
- $ref: "#/components/parameters/offset"
|
||||
- $ref: "#/components/parameters/limit"
|
||||
- $ref: "#/components/parameters/operation"
|
||||
- $ref: "#/components/parameters/with_attributes"
|
||||
- $ref: "#/components/parameters/with_metadata"
|
||||
- $ref: "#/components/parameters/from"
|
||||
- $ref: "#/components/parameters/to"
|
||||
- $ref: "#/components/parameters/dir"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/JournalsPageRes"
|
||||
"400":
|
||||
description: Failed due to malformed query parameters.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"403":
|
||||
description: Failed to perform authorization over the entity.
|
||||
"404":
|
||||
description: A non-existent entity request.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/{domainID}/journal/client/{clientID}/telemetry:
|
||||
get:
|
||||
tags:
|
||||
- journal-log
|
||||
summary: View client telemetry
|
||||
description: |
|
||||
Retrieves telemetry data for a specific client within a domain.
|
||||
This includes connection status, messages sent/received, and other metrics.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/domain_id"
|
||||
- $ref: "#/components/parameters/client_id"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
description: Client telemetry data retrieved successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Telemetry"
|
||||
"400":
|
||||
description: Failed due to malformed request parameters.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"403":
|
||||
description: Failed to perform authorization over the entity.
|
||||
"404":
|
||||
description: Client not found.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/{domainID}/journal/{entityType}/{id}:
|
||||
get:
|
||||
tags:
|
||||
- journal-log
|
||||
summary: List entity journal log
|
||||
description: |
|
||||
Retrieves a list of journal. Due to performance concerns, data
|
||||
is retrieved in subsets. The API must ensure that the entire
|
||||
dataset is consumed either by making subsequent requests, or by
|
||||
increasing the subset size of the initial request.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/domain_id"
|
||||
- $ref: "#/components/parameters/entity_type"
|
||||
- $ref: "#/components/parameters/id"
|
||||
- $ref: "#/components/parameters/offset"
|
||||
- $ref: "#/components/parameters/limit"
|
||||
- $ref: "#/components/parameters/operation"
|
||||
- $ref: "#/components/parameters/with_attributes"
|
||||
- $ref: "#/components/parameters/with_metadata"
|
||||
- $ref: "#/components/parameters/from"
|
||||
- $ref: "#/components/parameters/to"
|
||||
- $ref: "#/components/parameters/dir"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/JournalsPageRes"
|
||||
"400":
|
||||
description: Failed due to malformed query parameters.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"403":
|
||||
description: Failed to perform authorization over the entity.
|
||||
"404":
|
||||
description: A non-existent entity request.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
security: []
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/HealthRes"
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
schemas:
|
||||
Telemetry:
|
||||
type: object
|
||||
properties:
|
||||
client_id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Unique identifier of the client
|
||||
example: "bb7edb32-2eac-4aad-aebe-ed96fe073879"
|
||||
domain_id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Unique identifier of the domain
|
||||
example: "29d425c8-542b-4614-8a4d-a5951945d720"
|
||||
subscriptions:
|
||||
type: integer
|
||||
format: int64
|
||||
description: Number of active subscriptions for the client
|
||||
example: 5
|
||||
inbound_messages:
|
||||
type: integer
|
||||
format: int64
|
||||
description: Number of messages received by the client
|
||||
example: 1234567
|
||||
outbound_messages:
|
||||
type: integer
|
||||
format: int64
|
||||
description: Number of messages sent by the client
|
||||
example: 987654
|
||||
first_seen:
|
||||
type: string
|
||||
format: date-time
|
||||
description: Timestamp when the client was first seen
|
||||
example: "2024-01-11T10:00:00.000Z"
|
||||
last_seen:
|
||||
type: string
|
||||
format: date-time
|
||||
description: Timestamp when the client was last seen
|
||||
example: "2024-01-11T12:05:07.449053Z"
|
||||
|
||||
Journal:
|
||||
type: object
|
||||
properties:
|
||||
operation:
|
||||
type: string
|
||||
example: user.create
|
||||
description: Journal operation.
|
||||
occurred_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2024-01-11T12:05:07.449053Z"
|
||||
description: Time when the journal occurred.
|
||||
attributes:
|
||||
type: object
|
||||
description: Journal attributes.
|
||||
example:
|
||||
{
|
||||
"created_at": "2024-06-12T11:34:32.991591Z",
|
||||
"id": "29d425c8-542b-4614-8a4d-a5951945d720",
|
||||
"identity": "Gawne-Havlicek@email.com",
|
||||
"name": "Newgard-Frisina",
|
||||
"status": "enabled",
|
||||
"updated_at": "2024-06-12T11:34:33.116795Z",
|
||||
"updated_by": "ad228f20-4741-47c5-bef7-d871b541c019",
|
||||
}
|
||||
metadata:
|
||||
type: object
|
||||
description: Journal payload.
|
||||
example: { "Update": "Calvo-Felkins" }
|
||||
xml:
|
||||
name: journal
|
||||
|
||||
JournalPage:
|
||||
type: object
|
||||
properties:
|
||||
journals:
|
||||
type: array
|
||||
minItems: 0
|
||||
uniqueItems: true
|
||||
items:
|
||||
$ref: "#/components/schemas/Journal"
|
||||
total:
|
||||
type: integer
|
||||
example: 1
|
||||
description: Total number of items.
|
||||
offset:
|
||||
type: integer
|
||||
description: Number of items to skip during retrieval.
|
||||
limit:
|
||||
type: integer
|
||||
example: 10
|
||||
description: Maximum number of items to return in one page.
|
||||
required:
|
||||
- journals
|
||||
- total
|
||||
- offset
|
||||
|
||||
Error:
|
||||
type: object
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
description: Error message
|
||||
example: { "error": "malformed entity specification" }
|
||||
|
||||
parameters:
|
||||
domain_id:
|
||||
name: domainID
|
||||
description: Unique identifier for a domain.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
|
||||
client_id:
|
||||
name: clientID
|
||||
description: Unique identifier for a client
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
|
||||
entity_type:
|
||||
name: entityType
|
||||
description: Type of entity, e.g. group, client, channel.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- group
|
||||
- client
|
||||
- channel
|
||||
required: true
|
||||
example: group
|
||||
|
||||
user_id:
|
||||
name: userID
|
||||
description: Unique identifier for a user.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
|
||||
id:
|
||||
name: id
|
||||
description: Unique identifier for an entity, e.g. group, channel or client. Used together with entity_type.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
|
||||
offset:
|
||||
name: offset
|
||||
description: Number of items to skip during retrieval.
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 0
|
||||
minimum: 0
|
||||
required: false
|
||||
example: 0
|
||||
|
||||
limit:
|
||||
name: limit
|
||||
description: Size of the subset to retrieve.
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 10
|
||||
maximum: 100
|
||||
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: integer
|
||||
format: int64
|
||||
required: false
|
||||
example: 1966777289
|
||||
|
||||
to:
|
||||
name: to
|
||||
description: End date in unix time.
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
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: []
|
||||
@@ -11,11 +11,11 @@ properties:
|
||||
version:
|
||||
type: string
|
||||
description: Service version.
|
||||
example: 0.0.1
|
||||
example: v0.18.0
|
||||
commit:
|
||||
type: string
|
||||
description: Service commit hash.
|
||||
example: 7d6f4dc4f7f0c1fa3dc24eddfb18bb5073ff4f62
|
||||
example: 73362210dd2e04e389eaddb802cab3fe03976593
|
||||
description:
|
||||
type: string
|
||||
description: Service description.
|
||||
@@ -23,4 +23,8 @@ properties:
|
||||
build_time:
|
||||
type: string
|
||||
description: Service build time.
|
||||
example: 1970-01-01_00:00:00
|
||||
example: 2024-02-01_12:18:15
|
||||
instance_id:
|
||||
type: string
|
||||
description: Service instance ID.
|
||||
example: 8edbf8af-7db7-4218-bb4f-a8a929ff5266
|
||||
@@ -0,0 +1,395 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
components:
|
||||
schemas:
|
||||
NewRole:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
description: Role unique identifier.
|
||||
name:
|
||||
type: string
|
||||
description: Role's name.
|
||||
example: "roleName"
|
||||
entity_id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
description: Entity unique identifier.
|
||||
created_by:
|
||||
type: string
|
||||
format: uuid
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
description: Role creator unique identifier.
|
||||
created_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2019-11-26 13:31:52"
|
||||
description: Time when the channel was created.
|
||||
updated_by:
|
||||
type: string
|
||||
format: uuid
|
||||
example: ""
|
||||
description: Role updater unique identifier.
|
||||
updated_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: ""
|
||||
description: Time when the channel was created.
|
||||
|
||||
Role:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
description: Role unique identifier.
|
||||
name:
|
||||
type: string
|
||||
description: Role's name.
|
||||
example: "roleName"
|
||||
entity_id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
description: Entity unique identifier.
|
||||
created_by:
|
||||
type: string
|
||||
format: uuid
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
description: Role creator unique identifier.
|
||||
created_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2019-11-26 13:31:52"
|
||||
description: Time when the channel was created.
|
||||
updated_by:
|
||||
type: string
|
||||
format: uuid
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
description: Role updater unique identifier.
|
||||
updated_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2019-11-26 13:31:52"
|
||||
description: Time when the channel was created.
|
||||
|
||||
CreateRoleObj:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: Role's name.
|
||||
example: "roleName"
|
||||
optional_actions:
|
||||
type: array
|
||||
description: List of optional actions.
|
||||
items:
|
||||
type: string
|
||||
example:
|
||||
[
|
||||
"read",
|
||||
"update",
|
||||
]
|
||||
optional_members:
|
||||
type: array
|
||||
minItems: 0
|
||||
description: List of optional members.
|
||||
items:
|
||||
type: string
|
||||
example:
|
||||
[
|
||||
"5dc1ce4b-7cc9-4f12-98a6-9d74cc4980bb",
|
||||
"c01ed106-e52d-4aa4-bed3-39f360177cfa",
|
||||
]
|
||||
|
||||
UpdateRoleObj:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: Role's name.
|
||||
|
||||
RolesPage:
|
||||
type: object
|
||||
properties:
|
||||
roles:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Role'
|
||||
description: List of roles.
|
||||
total:
|
||||
type: integer
|
||||
description: Total number of roles.
|
||||
example: 1
|
||||
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.
|
||||
|
||||
EntityMembersPage:
|
||||
type: object
|
||||
properties:
|
||||
groups:
|
||||
type: array
|
||||
minItems: 0
|
||||
uniqueItems: true
|
||||
items:
|
||||
$ref: "#/components/schemas/EntityMembersObj"
|
||||
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:
|
||||
- groups
|
||||
- total
|
||||
- offset
|
||||
|
||||
RoleActionsObj:
|
||||
type: object
|
||||
properties:
|
||||
actions:
|
||||
type: array
|
||||
description: List of actions to be added to a role.
|
||||
items:
|
||||
type: string
|
||||
example:
|
||||
[
|
||||
"read",
|
||||
"update",
|
||||
]
|
||||
|
||||
RoleMembersObj:
|
||||
type: object
|
||||
properties:
|
||||
members:
|
||||
type: array
|
||||
description: List of members to be added to a role.
|
||||
items:
|
||||
type: string
|
||||
example:
|
||||
[
|
||||
"5dc1ce4b-7cc9-4f12-98a6-9d74cc4980bb",
|
||||
"c01ed106-e52d-4aa4-bed3-39f360177cfa",
|
||||
]
|
||||
|
||||
EntityMembersObj:
|
||||
type: object
|
||||
properties:
|
||||
members:
|
||||
type: array
|
||||
description: List of members with assigned roles and actions.
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Unique identifier of the member.
|
||||
roles:
|
||||
type: array
|
||||
description: List of roles assigned to the member.
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Unique identifier of the role.
|
||||
name:
|
||||
type: string
|
||||
description: Name of the role.
|
||||
actions:
|
||||
type: array
|
||||
description: List of actions the member can perform.
|
||||
items:
|
||||
type: string
|
||||
access_type:
|
||||
type: string
|
||||
description: Type of access granted.
|
||||
enum: [read, write, admin] # Adjust based on your actual access types.
|
||||
example:
|
||||
members:
|
||||
- id: "5dc1ce4b-7cc9-4f12-98a6-9d74cc4980bb"
|
||||
roles:
|
||||
- id: "a1b2c3d4-e5f6-7890-1234-56789abcdef0"
|
||||
name: "Admin"
|
||||
actions: ["create", "update", "delete"]
|
||||
access_type: "admin"
|
||||
- id: "c01ed106-e52d-4aa4-bed3-39f360177cfa"
|
||||
roles:
|
||||
- id: "b2c3d4e5-f678-9012-3456-789abcdef012"
|
||||
name: "Editor"
|
||||
actions: ["read", "update"]
|
||||
access_type: "write"
|
||||
|
||||
|
||||
AvailableActionsObj:
|
||||
type: object
|
||||
properties:
|
||||
available_actions:
|
||||
type: array
|
||||
description: List of all available actions.
|
||||
items:
|
||||
type: string
|
||||
example:
|
||||
[
|
||||
"read",
|
||||
"update",
|
||||
]
|
||||
|
||||
parameters:
|
||||
RoleName:
|
||||
name: roleName
|
||||
description: Role's name.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
example: "roleName"
|
||||
RoleID:
|
||||
name: roleID
|
||||
description: Role ID.
|
||||
in: path
|
||||
schema:
|
||||
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:
|
||||
description: JSON- formatted object decsribing a new role to be created.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CreateRoleObj'
|
||||
|
||||
UpdateRoleReq:
|
||||
description: JSON- formatted object decsribing a role to be updated.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/UpdateRoleObj'
|
||||
|
||||
AddRoleActionsReq:
|
||||
description: JSON- formatted object decsribing an action to be added to a role.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RoleActionsObj'
|
||||
|
||||
AddRoleMembersReq:
|
||||
description: JSON- formatted object decsribing a member to be added to a role.
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RoleMembersObj'
|
||||
|
||||
responses:
|
||||
CreateRoleRes:
|
||||
description: Role created successfully.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/NewRole'
|
||||
|
||||
ListRolesRes:
|
||||
description: Role retrieved successfully.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RolesPage'
|
||||
|
||||
GetRoleRes:
|
||||
description: Role retrieved successfully.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Role'
|
||||
|
||||
AddRoleActionsRes:
|
||||
description: Action added to role successfully.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RoleActionsObj'
|
||||
|
||||
ListRoleActionsRes:
|
||||
description: Role actions retrieved successfully.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RoleActionsObj'
|
||||
|
||||
AddRoleMembersRes:
|
||||
description: Member added to role successfully.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RoleMembersObj'
|
||||
|
||||
ListRoleMembersRes:
|
||||
description: Role members retrieved successfully.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RoleMembersObj'
|
||||
|
||||
ListAvailableActionsRes:
|
||||
description: Available actions retrieved successfully.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/AvailableActionsObj'
|
||||
|
||||
|
||||
ListEntityMembersRes:
|
||||
description: Entity members retrieved successfully.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/EntityMembersObj'
|
||||
File diff suppressed because it is too large
Load Diff
-2592
File diff suppressed because it is too large
Load Diff
-208
@@ -1,208 +0,0 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package magistrala;
|
||||
option go_package = "./magistrala";
|
||||
|
||||
// AuthzService is a service that provides authentication and authorization
|
||||
// functionalities for the things service.
|
||||
service AuthzService {
|
||||
// Authorize checks if the subject is authorized to perform
|
||||
// the action on the object.
|
||||
rpc Authorize(AuthorizeReq) returns (AuthorizeRes) {}
|
||||
}
|
||||
|
||||
// AuthService is a service that provides authentication and authorization
|
||||
// functionalities for the users service.
|
||||
service AuthService {
|
||||
rpc Issue(IssueReq) returns (Token) {}
|
||||
rpc Refresh(RefreshReq) returns (Token) {}
|
||||
rpc Identify(IdentityReq) returns (IdentityRes) {}
|
||||
rpc Authorize(AuthorizeReq) returns (AuthorizeRes) {}
|
||||
rpc AddPolicy(AddPolicyReq) returns (AddPolicyRes) {}
|
||||
rpc AddPolicies(AddPoliciesReq) returns (AddPoliciesRes) {}
|
||||
rpc DeletePolicy(DeletePolicyReq) returns (DeletePolicyRes) {}
|
||||
rpc DeletePolicies(DeletePoliciesReq) returns (DeletePoliciesRes) {}
|
||||
rpc ListObjects(ListObjectsReq) returns (ListObjectsRes) {}
|
||||
rpc ListAllObjects(ListObjectsReq) returns (ListObjectsRes) {}
|
||||
rpc CountObjects(CountObjectsReq) returns (CountObjectsRes) {}
|
||||
rpc ListSubjects(ListSubjectsReq) returns (ListSubjectsRes) {}
|
||||
rpc ListAllSubjects(ListSubjectsReq) returns (ListSubjectsRes) {}
|
||||
rpc CountSubjects(CountSubjectsReq) returns (CountSubjectsRes) {}
|
||||
rpc ListPermissions(ListPermissionsReq) returns (ListPermissionsRes) {}
|
||||
}
|
||||
|
||||
// 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.
|
||||
message Token {
|
||||
string accessToken = 1;
|
||||
optional string refreshToken = 2;
|
||||
string accessType = 3;
|
||||
}
|
||||
|
||||
message IdentityReq {
|
||||
string token = 1;
|
||||
}
|
||||
|
||||
message IdentityRes {
|
||||
string id = 1; // IMPROVEMENT NOTE: change name from "id" to "subject" , sub in jwt = user id + domain id //
|
||||
string user_id = 2; // user id
|
||||
string domain_id = 3; // domain id
|
||||
}
|
||||
|
||||
message IssueReq {
|
||||
string user_id = 1;
|
||||
optional string domain_id = 2;
|
||||
uint32 type = 3;
|
||||
}
|
||||
|
||||
message RefreshReq {
|
||||
string refresh_token = 1;
|
||||
optional string domain_id = 2;
|
||||
}
|
||||
|
||||
message AuthorizeReq {
|
||||
string domain = 1; // Domain
|
||||
string subject_type = 2; // Thing or User
|
||||
string subject_kind = 3; // ID or Token
|
||||
string subject_relation = 4; // Subject relation
|
||||
string subject = 5; // Subject value (id or token, depending on kind)
|
||||
string relation = 6; // Relation to filter
|
||||
string permission = 7; // Action
|
||||
string object = 8; // Object ID
|
||||
string object_type = 9; // Thing, User, Group
|
||||
}
|
||||
|
||||
message AuthorizeRes {
|
||||
bool authorized = 1;
|
||||
string id = 2;
|
||||
}
|
||||
|
||||
message AddPolicyReq {
|
||||
string domain = 1;
|
||||
string subject_type = 2;
|
||||
string subject_relation = 3;
|
||||
string subject_kind = 4;
|
||||
string subject = 5;
|
||||
string relation = 6;
|
||||
string permission = 7;
|
||||
string object = 8;
|
||||
string object_kind = 9;
|
||||
string object_type = 10;
|
||||
}
|
||||
|
||||
message AddPoliciesReq{
|
||||
repeated AddPolicyReq addPoliciesReq= 1;
|
||||
}
|
||||
|
||||
message AddPolicyRes { bool added = 1; }
|
||||
|
||||
message AddPoliciesRes { bool added = 1; }
|
||||
|
||||
message DeletePolicyReq {
|
||||
string domain = 1;
|
||||
string subject_type = 2;
|
||||
string subject_relation = 3;
|
||||
string subject_kind = 4;
|
||||
string subject = 5;
|
||||
string relation = 6;
|
||||
string permission = 7;
|
||||
string object = 8;
|
||||
string object_kind = 9;
|
||||
string object_type = 10;
|
||||
}
|
||||
|
||||
message DeletePoliciesReq {
|
||||
repeated DeletePolicyReq deletePoliciesReq = 1;
|
||||
}
|
||||
|
||||
message DeletePolicyRes { bool deleted = 1; }
|
||||
|
||||
message DeletePoliciesRes { bool deleted = 1; }
|
||||
|
||||
message ListObjectsReq {
|
||||
string domain = 1;
|
||||
string subject_type = 2;
|
||||
string subject_relation = 3;
|
||||
string subject = 4;
|
||||
string relation = 5;
|
||||
string permission = 6;
|
||||
string object = 7;
|
||||
string object_type = 8;
|
||||
string nextPageToken = 9;
|
||||
int32 limit = 10;
|
||||
}
|
||||
|
||||
message ListObjectsRes {
|
||||
repeated string policies = 1;
|
||||
string nextPageToken = 2;
|
||||
}
|
||||
|
||||
message CountObjectsReq {
|
||||
string domain = 1;
|
||||
string subject_type = 2;
|
||||
string subject_relation = 3;
|
||||
string subject = 4;
|
||||
string relation = 5;
|
||||
string permission = 6;
|
||||
string object = 7;
|
||||
string object_type = 8;
|
||||
string nextPageToken = 9;
|
||||
}
|
||||
|
||||
message CountObjectsRes { int64 count = 1; }
|
||||
|
||||
message ListSubjectsReq {
|
||||
string domain = 1;
|
||||
string subject_type = 2;
|
||||
string subject_relation = 3;
|
||||
string subject = 4;
|
||||
string relation = 5;
|
||||
string permission = 6;
|
||||
string object = 7;
|
||||
string object_type = 8;
|
||||
string nextPageToken = 9;
|
||||
int32 limit = 10;
|
||||
}
|
||||
|
||||
message ListSubjectsRes {
|
||||
repeated string policies = 1;
|
||||
string nextPageToken = 2;
|
||||
}
|
||||
|
||||
message CountSubjectsReq {
|
||||
string domain = 1;
|
||||
string subject_type = 2;
|
||||
string subject_relation = 3;
|
||||
string subject = 4;
|
||||
string relation = 5;
|
||||
string permission = 6;
|
||||
string object = 7;
|
||||
string object_type = 8;
|
||||
string nextPageToken = 9;
|
||||
}
|
||||
|
||||
message CountSubjectsRes { int64 count = 1; }
|
||||
|
||||
message ListPermissionsReq {
|
||||
string domain = 1;
|
||||
string subject_type = 2;
|
||||
string subject_relation = 3;
|
||||
string subject = 4;
|
||||
string object = 5;
|
||||
string object_type = 6;
|
||||
repeated string filter_permissions = 7;
|
||||
}
|
||||
|
||||
message ListPermissionsRes {
|
||||
string domain = 1;
|
||||
string subject_type = 2;
|
||||
string subject_relation = 3;
|
||||
string subject = 4;
|
||||
string object = 5;
|
||||
string object_type = 6;
|
||||
repeated string permissions = 7;
|
||||
}
|
||||
+370
-80
@@ -1,6 +1,6 @@
|
||||
# Auth - Authentication and Authorization service
|
||||
|
||||
Auth service provides authentication features as an API for managing authentication keys as well as administering groups of entities - `things` and `users`.
|
||||
Auth service provides authentication features as an API for managing authentication keys as well as administering groups of entities - `clients` and `users`.
|
||||
|
||||
## Authentication
|
||||
|
||||
@@ -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 Magistrala User who issued the key
|
||||
- IssuerID - an ID of the SuperMQ 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
|
||||
@@ -25,11 +25,11 @@ Authentication keys are represented and distributed by the corresponding [JWT](j
|
||||
|
||||
User keys are issued when user logs in. Each user request (other than `registration` and `login`) contains user key that is used to authenticate the user.
|
||||
|
||||
API keys are similar to the User keys. The main difference is that API keys have configurable expiration time. If no time is set, the key will never expire. For that reason, API keys are _the only key type that can be revoked_. This also means that, despite being used as a JWT, it requires a query to the database to validate the API key. The user with API key can perform all the same actions as the user with login key (can act on behalf of the user for Thing, Channel, or user profile management), _except issuing new API keys_.
|
||||
API keys are similar to the User keys. The main difference is that API keys have configurable expiration time. If no time is set, the key will never expire. For that reason, API keys are _the only key type that can be revoked_. This also means that, despite being used as a JWT, it requires a query to the database to validate the API key. The user with API key can perform all the same actions as the user with login key (can act on behalf of the user for Client, Channel, or user profile management), _except issuing new API keys_.
|
||||
|
||||
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 Magistrala, please check out the [official documentation][doc].
|
||||
For in-depth explanation of the aforementioned scenarios, as well as thorough understanding of SuperMQ, 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 things. Each domain has a unique alias that is used to identify 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:
|
||||
|
||||
@@ -48,7 +48,7 @@ Domain consists of the following fields:
|
||||
- Name - name of the domain
|
||||
- Tags - array of tags
|
||||
- Metadata - Arbitrary, object-encoded domain's data
|
||||
- Alias - unique alias of the domain
|
||||
- Route - unique route of the domain used in messaging
|
||||
- CreatedAt - timestamp at which the domain is created
|
||||
- UpdatedAt - timestamp at which the domain is updated
|
||||
- UpdatedBy - user that updated the domain
|
||||
@@ -59,53 +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 |
|
||||
| ------------------------------ | ----------------------------------------------------------------------- | -------------------------------- |
|
||||
| MG_AUTH_LOG_LEVEL | Log level for the Auth service (debug, info, warn, error) | info |
|
||||
| MG_AUTH_DB_HOST | Database host address | localhost |
|
||||
| MG_AUTH_DB_PORT | Database host port | 5432 |
|
||||
| MG_AUTH_DB_USER | Database user | magistrala |
|
||||
| MG_AUTH_DB_PASSWORD | Database password | magistrala |
|
||||
| MG_AUTH_DB_NAME | Name of the database used by the service | auth |
|
||||
| MG_AUTH_DB_SSL_MODE | Database connection SSL mode (disable, require, verify-ca, verify-full) | disable |
|
||||
| MG_AUTH_DB_SSL_CERT | Path to the PEM encoded certificate file | "" |
|
||||
| MG_AUTH_DB_SSL_KEY | Path to the PEM encoded key file | "" |
|
||||
| MG_AUTH_DB_SSL_ROOT_CERT | Path to the PEM encoded root certificate file | "" |
|
||||
| MG_AUTH_HTTP_HOST | Auth service HTTP host | "" |
|
||||
| MG_AUTH_HTTP_PORT | Auth service HTTP port | 8189 |
|
||||
| MG_AUTH_HTTP_SERVER_CERT | Path to the PEM encoded HTTP server certificate file | "" |
|
||||
| MG_AUTH_HTTP_SERVER_KEY | Path to the PEM encoded HTTP server key file | "" |
|
||||
| MG_AUTH_GRPC_HOST | Auth service gRPC host | "" |
|
||||
| MG_AUTH_GRPC_PORT | Auth service gRPC port | 8181 |
|
||||
| MG_AUTH_GRPC_SERVER_CERT | Path to the PEM encoded gRPC server certificate file | "" |
|
||||
| MG_AUTH_GRPC_SERVER_KEY | Path to the PEM encoded gRPC server key file | "" |
|
||||
| MG_AUTH_GRPC_SERVER_CA_CERTS | Path to the PEM encoded gRPC server CA certificate file | "" |
|
||||
| MG_AUTH_GRPC_CLIENT_CA_CERTS | Path to the PEM encoded gRPC client CA certificate file | "" |
|
||||
| MG_AUTH_SECRET_KEY | String used for signing tokens | secret |
|
||||
| MG_AUTH_ACCESS_TOKEN_DURATION | The access token expiration period | 1h |
|
||||
| MG_AUTH_REFRESH_TOKEN_DURATION | The refresh token expiration period | 24h |
|
||||
| MG_AUTH_INVITATION_DURATION | The invitation token expiration period | 168h |
|
||||
| MG_SPICEDB_HOST | SpiceDB host address | localhost |
|
||||
| MG_SPICEDB_PORT | SpiceDB host port | 50051 |
|
||||
| MG_SPICEDB_PRE_SHARED_KEY | SpiceDB pre-shared key | 12345678 |
|
||||
| MG_SPICEDB_SCHEMA_FILE | Path to SpiceDB schema file | ./docker/spicedb/schema.zed |
|
||||
| MG_JAEGER_URL | Jaeger server URL | <http://jaeger:14268/api/traces> |
|
||||
| MG_JAEGER_TRACE_RATIO | Jaeger sampling ratio | 1.0 |
|
||||
| MG_SEND_TELEMETRY | Send telemetry to magistrala call home server | true |
|
||||
| MG_AUTH_ADAPTER_INSTANCE_ID | Adapter instance ID | "" |
|
||||
| Variable | Description | Default |
|
||||
| :--- | :--- | :--- |
|
||||
| `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. | "" |
|
||||
|
||||
## Deployment
|
||||
|
||||
The service itself is distributed as Docker container. Check the [`auth`](https://github.com/absmach/magistrala/blob/master/docker/docker-compose.yml) service section in docker-compose to see how service is deployed.
|
||||
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.
|
||||
|
||||
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/magistrala
|
||||
git clone https://github.com/absmach/supermq
|
||||
|
||||
cd magistrala
|
||||
cd supermq
|
||||
|
||||
# compile the service
|
||||
make auth
|
||||
@@ -114,46 +124,326 @@ make auth
|
||||
make install
|
||||
|
||||
# set the environment variables and run the service
|
||||
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="" \
|
||||
$GOBIN/magistrala-auth
|
||||
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
|
||||
```
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## 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.
|
||||
|
||||
### Overview
|
||||
|
||||
PATs in SuperMQ 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
|
||||
- **Revocable**: Tokens can be revoked at any time
|
||||
- **Auditable**: Track when tokens were last used
|
||||
- **Secure**: Tokens are stored as hashes, not in plaintext
|
||||
|
||||
### Token Structure
|
||||
|
||||
A PAT consists of three parts separated by underscores:
|
||||
|
||||
```bash
|
||||
pat_<encoded-user-and-pat-id>_<random-string>
|
||||
```
|
||||
|
||||
Where:
|
||||
|
||||
- `pat` is a fixed prefix
|
||||
- `<encoded-user-and-pat-id>` is a base64-encoded combination of the user ID and PAT ID
|
||||
- `<random-string>` is a randomly generated string for additional security
|
||||
|
||||
### PAT Operations
|
||||
|
||||
SuperMQ supports the following operations for PATs:
|
||||
|
||||
| Operation | Description |
|
||||
| ----------- | ------------------------------------ |
|
||||
| `create` | Create a new resource |
|
||||
| `read` | Read/view a resource |
|
||||
| `list` | List resources |
|
||||
| `update` | Update/modify a resource |
|
||||
| `delete` | Delete a resource |
|
||||
| `share` | Share a resource with others |
|
||||
| `unshare` | Remove sharing permissions |
|
||||
| `publish` | Publish messages to a channel |
|
||||
| `subscribe` | Subscribe to messages from a channel |
|
||||
|
||||
### Entity Types
|
||||
|
||||
PATs can be scoped to the following entity types:
|
||||
|
||||
| Entity Type | Description |
|
||||
| ------------ | ---------------------- |
|
||||
| `groups` | User groups |
|
||||
| `channels` | Communication channels |
|
||||
| `clients` | Client applications |
|
||||
| `domains` | Organizational domains |
|
||||
| `users` | User accounts |
|
||||
| `dashboards` | Dashboard interfaces |
|
||||
| `messages` | Message content |
|
||||
|
||||
### API Examples
|
||||
|
||||
#### Creating a PAT
|
||||
|
||||
```bash
|
||||
curl --location 'http://localhost:9001/pats' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--header 'Authorization: Bearer <access_token>' \
|
||||
--data '{
|
||||
"name": "test pat",
|
||||
"description": "testing pat",
|
||||
"duration": "24h"
|
||||
}'
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "a2500226-95dc-4285-87e2-e693e4a0a976",
|
||||
"user_id": "user123",
|
||||
"name": "pat 1",
|
||||
"description": "for creating any client or channel",
|
||||
"secret": "pat_dXNlcjEyM19hMjUwMDIyNi05NWRjLTQyODUtODdlMi1lNjkzZTRhMGE5NzY=_randomstring...",
|
||||
"issued_at": "2025-02-27T11:20:59Z",
|
||||
"expires_at": "2025-02-28T11:20:59Z"
|
||||
}
|
||||
```
|
||||
|
||||
#### Adding Scopes to a PAT
|
||||
|
||||
```bash
|
||||
curl --location --request PATCH 'http://localhost:9001/pats/a2500226-95dc-4285-87e2-e693e4a0a976/scope/add' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--header 'Authorization: Bearer <access_token>' \
|
||||
--data '{
|
||||
"scopes": [
|
||||
{
|
||||
"optional_domain_id": "c16c980a-9d4c-4793-8fb2-c81304cf1d9f",
|
||||
"entity_type": "clients",
|
||||
"operation": "create",
|
||||
"entity_id": "*"
|
||||
},
|
||||
{
|
||||
"optional_domain_id": "c16c980a-9d4c-4793-8fb2-c81304cf1d9f",
|
||||
"entity_type": "channels",
|
||||
"operation": "create",
|
||||
"entity_id": "cfbc6936-5748-4339-a8ef-37b64b02bc96"
|
||||
},
|
||||
{
|
||||
"entity_type": "dashboards",
|
||||
"optional_domain_id": "c16c980a-9d4c-4793-8fb2-c81304cf1d9f",
|
||||
"operation": "read",
|
||||
"entity_id": "*"
|
||||
}
|
||||
]
|
||||
}'
|
||||
```
|
||||
|
||||
#### Listing PATs
|
||||
|
||||
```bash
|
||||
curl --location 'http://localhost:9001/pats' \
|
||||
--header 'Authorization: Bearer <access_token>'
|
||||
```
|
||||
|
||||
#### Listing Scopes for a PAT
|
||||
|
||||
```bash
|
||||
curl --location 'http://localhost:9001/pats/a2500226-95dc-4285-87e2-e693e4a0a976/scopes' \
|
||||
--header 'Authorization: Bearer <access_token>'
|
||||
```
|
||||
|
||||
#### Revoking a PAT
|
||||
|
||||
```bash
|
||||
curl --location --request PATCH 'http://localhost:9001/pats/a2500226-95dc-4285-87e2-e693e4a0a976/revoke' \
|
||||
--header 'Authorization: Bearer <access_token>'
|
||||
```
|
||||
|
||||
#### Resetting a PAT Secret
|
||||
|
||||
```bash
|
||||
curl --location --request PATCH 'http://localhost:9001/pats/a2500226-95dc-4285-87e2-e693e4a0a976/reset' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--header 'Authorization: Bearer <access_token>' \
|
||||
--data '{
|
||||
"duration": "720h"
|
||||
}'
|
||||
```
|
||||
|
||||
### Using PATs for Authentication
|
||||
|
||||
When making API requests, include the PAT in the Authorization header:
|
||||
|
||||
```bash
|
||||
Authorization: Bearer pat_<encoded-user-and-pat-id>_<random-string>
|
||||
```
|
||||
|
||||
#### Example: Creating a Client Using PAT
|
||||
|
||||
```bash
|
||||
curl --location 'http://localhost:9006/c16c980a-9d4c-4793-8fb2-c81304cf1d9f/clients' \
|
||||
--header 'accept: application/json' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--header 'Authorization: Bearer pat_etKoiXKTR6a0zdgsBHC00qJQAiaV3EKFh+Lmk+SgqXY=_u7@5fyjgti9V@#Bw^bS*SPmX3OnH=HTvKwmIbxIuyBjoI|6FASo9egjKD^u-M$b|2Dpt3CXZtv&4k+hmYYjk&C$57AV59P%-iDV0' \
|
||||
--data '{
|
||||
"name": "test client",
|
||||
"tags": [
|
||||
"tag1",
|
||||
"tag2"
|
||||
],
|
||||
"metadata":{"units":"km"},
|
||||
"status": "enabled"
|
||||
}'
|
||||
```
|
||||
|
||||
This example shows how to create a client in a specific domain (`c16c980a-9d4c-4793-8fb2-c81304cf1d9f`) using a PAT for authentication. The PAT must have the appropriate scope (e.g., `clients` entity type with `create` operation) for this domain.
|
||||
|
||||
### Wildcard Entity IDs
|
||||
|
||||
When defining scopes for PATs, you can use the wildcard character `*` for the `entity_id` field to grant permissions for all entities of a specific type. This is particularly useful for automation tasks that need to operate on multiple resources.
|
||||
|
||||
For example:
|
||||
|
||||
- `"entity_id": "*"` - Grants permission for all entities of the specified type
|
||||
- `"entity_id": "specific-id"` - Grants permission only for the entity with the specified ID
|
||||
|
||||
Using wildcards should be done carefully, as they grant broader permissions. Always follow the principle of least privilege by granting only the permissions necessary for the intended use case.
|
||||
|
||||
### Scope Examples
|
||||
|
||||
#### Allow Creating Any Client in a Domain
|
||||
|
||||
```json
|
||||
{
|
||||
"optional_domain_id": "domain_id",
|
||||
"entity_type": "clients",
|
||||
"operation": "create",
|
||||
"entity_id": "*"
|
||||
}
|
||||
```
|
||||
|
||||
This scope allows the PAT to create any client within the specified domain. The wildcard `*` for `entity_id` means the token can create any client, not just a specific one.
|
||||
|
||||
#### Allow Publishing to a Specific Channel
|
||||
|
||||
```json
|
||||
{
|
||||
"optional_domain_id": "domain_id",
|
||||
"entity_type": "channels",
|
||||
"operation": "publish",
|
||||
"entity_id": "channel_id"
|
||||
}
|
||||
```
|
||||
|
||||
This scope restricts the PAT to only publish to a specific channel (`channel_id`) within the specified domain. No wildcard is used, so the permission is limited to just this one channel.
|
||||
|
||||
#### Allow Reading All Dashboards
|
||||
|
||||
```json
|
||||
{
|
||||
"optional_domain_id": "domain_id",
|
||||
"entity_type": "dashboards",
|
||||
"operation": "read",
|
||||
"entity_id": "*"
|
||||
}
|
||||
```
|
||||
|
||||
This scope allows the PAT to read all dashboards within the specified domain. The wildcard `*` for `entity_id` means the token can read any dashboard in that domain.
|
||||
|
||||
### Best Practices
|
||||
|
||||
1. **Limit Scope**: Always use the principle of least privilege when creating PATs
|
||||
2. **Set Expirations**: Use reasonable expiration times for tokens
|
||||
3. **Rotate Regularly**: Reset token secrets periodically
|
||||
4. **Audit Usage**: Monitor when tokens are used
|
||||
5. **Revoke Unused**: Remove tokens that are no longer needed
|
||||
|
||||
### Implementation Details
|
||||
|
||||
PATs are stored in the database with the following schema:
|
||||
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS pats (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
name VARCHAR(254) NOT NULL,
|
||||
user_id VARCHAR(36),
|
||||
description TEXT,
|
||||
secret TEXT,
|
||||
issued_at TIMESTAMPTZ,
|
||||
expires_at TIMESTAMPTZ,
|
||||
updated_at TIMESTAMPTZ,
|
||||
revoked BOOLEAN,
|
||||
revoked_at TIMESTAMPTZ,
|
||||
last_used_at TIMESTAMPTZ,
|
||||
UNIQUE (id, name, secret)
|
||||
)
|
||||
|
||||
CREATE TABLE IF NOT EXISTS pat_scopes (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
pat_id VARCHAR(36) REFERENCES pats(id) ON DELETE CASCADE,
|
||||
optional_domain_id VARCHAR(36),
|
||||
entity_type VARCHAR(50) NOT NULL,
|
||||
operation VARCHAR(50) NOT NULL,
|
||||
entity_id VARCHAR(50) NOT NULL,
|
||||
UNIQUE (pat_id, optional_domain_id, entity_type, operation, entity_id)
|
||||
)
|
||||
```
|
||||
|
||||
### Authorization
|
||||
|
||||
When a PAT is used for authentication:
|
||||
|
||||
1. The system parses the token to extract the user ID and PAT ID
|
||||
2. It verifies the token hasn't been revoked or expired
|
||||
3. It checks if the requested operation is allowed by the token's scopes
|
||||
4. If all checks pass, the operation is authorized
|
||||
|
||||
## Usage
|
||||
|
||||
For more information about service capabilities and its usage, please check out the [API documentation](https://api.mainflux.io/?urls.primaryName=auth.yml).
|
||||
For more information about service capabilities and its usage, please check out the [API documentation](https://docs.api.supermq.absmach.eu/?urls.primaryName=auth.yaml).
|
||||
|
||||
[doc]: https://docs.mainflux.io
|
||||
[doc]: https://docs.supermq.absmach.eu/
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package auth
|
||||
|
||||
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"
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
kitgrpc "github.com/go-kit/kit/transport/grpc"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
const authSvcName = "auth.v1.AuthService"
|
||||
|
||||
type authGrpcClient struct {
|
||||
authenticate endpoint.Endpoint
|
||||
authorize endpoint.Endpoint
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
var _ grpcAuthV1.AuthServiceClient = (*authGrpcClient)(nil)
|
||||
|
||||
// NewAuthClient returns new auth gRPC client instance.
|
||||
func NewAuthClient(conn *grpc.ClientConn, timeout time.Duration) grpcAuthV1.AuthServiceClient {
|
||||
return &authGrpcClient{
|
||||
authenticate: kitgrpc.NewClient(
|
||||
conn,
|
||||
authSvcName,
|
||||
"Authenticate",
|
||||
encodeIdentifyRequest,
|
||||
decodeIdentifyResponse,
|
||||
grpcAuthV1.AuthNRes{},
|
||||
).Endpoint(),
|
||||
authorize: kitgrpc.NewClient(
|
||||
conn,
|
||||
authSvcName,
|
||||
"Authorize",
|
||||
encodeAuthorizeRequest,
|
||||
decodeAuthorizeResponse,
|
||||
grpcAuthV1.AuthZRes{},
|
||||
).Endpoint(),
|
||||
timeout: timeout,
|
||||
}
|
||||
}
|
||||
|
||||
func (client authGrpcClient) Authenticate(ctx context.Context, token *grpcAuthV1.AuthNReq, _ ...grpc.CallOption) (*grpcAuthV1.AuthNRes, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := client.authenticate(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, UserRole: uint32(ir.userRole), Verified: ir.verified}, nil
|
||||
}
|
||||
|
||||
func encodeIdentifyRequest(_ context.Context, grpcReq any) (any, error) {
|
||||
req := grpcReq.(authenticateReq)
|
||||
return &grpcAuthV1.AuthNReq{Token: req.token}, nil
|
||||
}
|
||||
|
||||
func decodeIdentifyResponse(_ context.Context, grpcRes any) (any, error) {
|
||||
res := grpcRes.(*grpcAuthV1.AuthNRes)
|
||||
return authenticateRes{id: res.GetId(), userID: res.GetUserId(), userRole: auth.Role(res.UserRole), verified: res.GetVerified()}, nil
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
|
||||
ar := res.(authorizeRes)
|
||||
return &grpcAuthV1.AuthZRes{Authorized: ar.authorized, Id: ar.id}, nil
|
||||
}
|
||||
|
||||
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 any) (any, error) {
|
||||
req := grpcReq.(authReq)
|
||||
|
||||
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,
|
||||
},
|
||||
}
|
||||
|
||||
if req.PatID != "" {
|
||||
authZReq.PatReq = &grpcAuthV1.PATReq{
|
||||
PatId: req.PatID,
|
||||
Domain: req.Domain,
|
||||
Operation: req.Operation,
|
||||
UserId: req.UserID,
|
||||
EntityId: req.EntityID,
|
||||
EntityType: req.EntityType,
|
||||
}
|
||||
}
|
||||
|
||||
return authZReq, nil
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package api contains implementation of certs service HTTP API.
|
||||
package api
|
||||
// Package auth contains implementation of Auth service gRPC API.
|
||||
package auth
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/absmach/supermq/auth"
|
||||
"github.com/absmach/supermq/pkg/policies"
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
)
|
||||
|
||||
func authenticateEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request any) (any, error) {
|
||||
req := request.(authenticateReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return authenticateRes{}, err
|
||||
}
|
||||
|
||||
key, err := svc.Identify(ctx, req.token)
|
||||
if err != nil {
|
||||
return authenticateRes{}, err
|
||||
}
|
||||
|
||||
return authenticateRes{id: key.ID, userID: key.Subject, userRole: key.Role, verified: key.Verified}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func authorizeEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
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,
|
||||
SubjectKind: req.SubjectKind,
|
||||
Subject: req.Subject,
|
||||
Relation: req.Relation,
|
||||
Permission: req.Permission,
|
||||
ObjectType: req.ObjectType,
|
||||
Object: req.Object,
|
||||
}, pat)
|
||||
if err != nil {
|
||||
return authorizeRes{authorized: false}, err
|
||||
}
|
||||
return authorizeRes{authorized: true}, nil
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,358 @@
|
||||
// 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/absmach/supermq/pkg/policies"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
)
|
||||
|
||||
const (
|
||||
port = 8081
|
||||
id = "testID"
|
||||
usersType = "users"
|
||||
adminPermission = "admin"
|
||||
authoritiesObj = "authorities"
|
||||
memberRelation = "member"
|
||||
validToken = "valid"
|
||||
inValidToken = "invalid"
|
||||
validPATToken = "valid"
|
||||
)
|
||||
|
||||
var (
|
||||
domainID = testsutil.GenerateUUID(&testing.T{})
|
||||
authAddr = fmt.Sprintf("localhost:%d", port)
|
||||
clientID = testsutil.GenerateUUID(&testing.T{})
|
||||
)
|
||||
|
||||
func startGRPCServer(svc auth.Service, port int) *grpc.Server {
|
||||
listener, _ := net.Listen("tcp", fmt.Sprintf(":%d", port))
|
||||
server := grpc.NewServer()
|
||||
grpcAuthV1.RegisterAuthServiceServer(server, grpcapi.NewAuthServer(svc))
|
||||
go func() {
|
||||
err := server.Serve(listener)
|
||||
assert.Nil(&testing.T{}, err, fmt.Sprintf(`"Unexpected error creating auth server %s"`, err))
|
||||
}()
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
func TestIdentify(t *testing.T) {
|
||||
conn, err := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err))
|
||||
defer conn.Close()
|
||||
grpcClient := grpcapi.NewAuthClient(conn, time.Second)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
token string
|
||||
key auth.Key
|
||||
idt *grpcAuthV1.AuthNRes
|
||||
svcErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "authenticate user with valid user token",
|
||||
token: validToken,
|
||||
key: auth.Key{ID: "", Subject: id, Role: auth.UserRole},
|
||||
idt: &grpcAuthV1.AuthNRes{UserId: id, UserRole: uint32(auth.UserRole)},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "authenticate user with invalid user token",
|
||||
token: "invalid",
|
||||
key: auth.Key{},
|
||||
idt: &grpcAuthV1.AuthNRes{},
|
||||
svcErr: svcerr.ErrAuthentication,
|
||||
err: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "authenticate user with empty token",
|
||||
token: "",
|
||||
idt: &grpcAuthV1.AuthNRes{},
|
||||
err: apiutil.ErrBearerToken,
|
||||
},
|
||||
{
|
||||
desc: "authenticate user with valid PAT token",
|
||||
token: "pat_" + validPATToken,
|
||||
key: auth.Key{ID: id, Type: auth.PersonalAccessToken, Subject: clientID, Role: auth.UserRole},
|
||||
idt: &grpcAuthV1.AuthNRes{Id: id, UserId: clientID, UserRole: uint32(auth.UserRole)},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "authenticate user with invalid PAT token",
|
||||
token: "pat_invalid",
|
||||
key: auth.Key{},
|
||||
idt: &grpcAuthV1.AuthNRes{},
|
||||
svcErr: svcerr.ErrAuthentication,
|
||||
err: svcerr.ErrAuthentication,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
svcCall := svc.On("Identify", mock.Anything, tc.token).Return(tc.key, tc.svcErr)
|
||||
idt, err := grpcClient.Authenticate(context.Background(), &grpcAuthV1.AuthNReq{Token: tc.token})
|
||||
if idt != nil {
|
||||
assert.Equal(t, tc.idt, idt, fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.idt, idt))
|
||||
}
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
svcCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthorize(t *testing.T) {
|
||||
conn, err := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err))
|
||||
defer conn.Close()
|
||||
|
||||
grpcClient := grpcapi.NewAuthClient(conn, time.Second)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
token string
|
||||
authRequest *grpcAuthV1.AuthZReq
|
||||
authResponse *grpcAuthV1.AuthZRes
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "authorize user with authorized token",
|
||||
token: validToken,
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||
Subject: id,
|
||||
SubjectType: usersType,
|
||||
Object: authoritiesObj,
|
||||
ObjectType: usersType,
|
||||
Relation: memberRelation,
|
||||
Permission: adminPermission,
|
||||
},
|
||||
},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: true},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "authorize user with unauthorized token",
|
||||
token: inValidToken,
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||
Subject: id,
|
||||
SubjectType: usersType,
|
||||
Object: authoritiesObj,
|
||||
ObjectType: usersType,
|
||||
Relation: memberRelation,
|
||||
Permission: adminPermission,
|
||||
},
|
||||
},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
{
|
||||
desc: "authorize user with empty subject",
|
||||
token: validToken,
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||
Subject: "",
|
||||
SubjectType: usersType,
|
||||
Object: authoritiesObj,
|
||||
ObjectType: usersType,
|
||||
Relation: memberRelation,
|
||||
Permission: adminPermission,
|
||||
},
|
||||
},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: apiutil.ErrMissingPolicySub,
|
||||
},
|
||||
{
|
||||
desc: "authorize user with empty subject type",
|
||||
token: validToken,
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||
Subject: id,
|
||||
SubjectType: "",
|
||||
Object: authoritiesObj,
|
||||
ObjectType: usersType,
|
||||
Relation: memberRelation,
|
||||
Permission: adminPermission,
|
||||
},
|
||||
},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: apiutil.ErrMissingPolicySub,
|
||||
},
|
||||
{
|
||||
desc: "authorize user with empty object",
|
||||
token: validToken,
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||
Subject: id,
|
||||
SubjectType: usersType,
|
||||
Object: "",
|
||||
ObjectType: usersType,
|
||||
Relation: memberRelation,
|
||||
Permission: adminPermission,
|
||||
},
|
||||
},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: apiutil.ErrMissingPolicyObj,
|
||||
},
|
||||
{
|
||||
desc: "authorize user with empty object type",
|
||||
token: validToken,
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||
Subject: id,
|
||||
SubjectType: usersType,
|
||||
Object: authoritiesObj,
|
||||
ObjectType: "",
|
||||
Relation: memberRelation,
|
||||
Permission: adminPermission,
|
||||
},
|
||||
},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: apiutil.ErrMissingPolicyObj,
|
||||
},
|
||||
{
|
||||
desc: "authorize user with empty permission",
|
||||
token: validToken,
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||
Subject: id,
|
||||
SubjectType: usersType,
|
||||
Object: authoritiesObj,
|
||||
ObjectType: usersType,
|
||||
Relation: memberRelation,
|
||||
Permission: "",
|
||||
},
|
||||
},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: apiutil.ErrMalformedPolicyPer,
|
||||
},
|
||||
{
|
||||
desc: "authorize user with valid PAT token",
|
||||
token: validPATToken,
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||
Subject: id,
|
||||
SubjectType: policies.UserType,
|
||||
SubjectKind: policies.UsersKind,
|
||||
Permission: policies.ViewPermission,
|
||||
ObjectType: policies.ClientType,
|
||||
Domain: domainID,
|
||||
Object: clientID,
|
||||
},
|
||||
PatReq: &grpcAuthV1.PATReq{
|
||||
PatId: id,
|
||||
Domain: domainID,
|
||||
Operation: "view",
|
||||
UserId: id,
|
||||
EntityId: clientID,
|
||||
EntityType: auth.ClientsScopeStr,
|
||||
},
|
||||
},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: true},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "authorize user with unauthorized PAT token",
|
||||
token: inValidToken,
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||
Subject: id,
|
||||
SubjectType: policies.UserType,
|
||||
SubjectKind: policies.UsersKind,
|
||||
Permission: policies.ViewPermission,
|
||||
ObjectType: policies.ClientType,
|
||||
Domain: domainID,
|
||||
Object: clientID,
|
||||
},
|
||||
PatReq: &grpcAuthV1.PATReq{
|
||||
PatId: id,
|
||||
Domain: domainID,
|
||||
Operation: "view",
|
||||
UserId: id,
|
||||
EntityId: clientID,
|
||||
EntityType: auth.ClientsScopeStr,
|
||||
},
|
||||
},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
{
|
||||
desc: "authorize PAT with missing user id",
|
||||
token: validPATToken,
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||
Subject: id,
|
||||
SubjectType: policies.UserType,
|
||||
SubjectKind: policies.UsersKind,
|
||||
Permission: policies.ViewPermission,
|
||||
ObjectType: policies.ClientType,
|
||||
Domain: domainID,
|
||||
Object: clientID,
|
||||
},
|
||||
PatReq: &grpcAuthV1.PATReq{
|
||||
PatId: id,
|
||||
Domain: domainID,
|
||||
Operation: "view",
|
||||
EntityId: clientID,
|
||||
EntityType: auth.ClientsScopeStr,
|
||||
},
|
||||
},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: apiutil.ErrMissingUserID,
|
||||
},
|
||||
{
|
||||
desc: "authorize PAT with missing entity id",
|
||||
token: validPATToken,
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||
Subject: id,
|
||||
SubjectType: policies.UserType,
|
||||
SubjectKind: policies.UsersKind,
|
||||
Permission: policies.ViewPermission,
|
||||
ObjectType: policies.ClientType,
|
||||
Domain: domainID,
|
||||
Object: clientID,
|
||||
},
|
||||
PatReq: &grpcAuthV1.PATReq{
|
||||
PatId: id,
|
||||
Domain: domainID,
|
||||
Operation: "view",
|
||||
UserId: id,
|
||||
EntityType: auth.ClientsScopeStr,
|
||||
},
|
||||
},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
svcCall := svc.On("Authorize", mock.Anything, mock.Anything, 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()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
apiutil "github.com/absmach/supermq/api/http/util"
|
||||
)
|
||||
|
||||
type authenticateReq struct {
|
||||
token string
|
||||
}
|
||||
|
||||
func (req authenticateReq) validate() error {
|
||||
if req.token == "" {
|
||||
return apiutil.ErrBearerToken
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// authReq represents authorization request. It contains:
|
||||
// 1. subject - an action invoker
|
||||
// 2. object - an entity over which action will be executed
|
||||
// 3. action - type of action that will be executed (read/write).
|
||||
type authReq struct {
|
||||
Domain string
|
||||
SubjectType string
|
||||
SubjectKind string
|
||||
Subject string
|
||||
Relation string
|
||||
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
|
||||
}
|
||||
|
||||
if req.Object == "" || req.ObjectType == "" {
|
||||
return apiutil.ErrMissingPolicyObj
|
||||
}
|
||||
|
||||
if req.Permission == "" {
|
||||
return apiutil.ErrMalformedPolicyPer
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package auth
|
||||
|
||||
import smqauth "github.com/absmach/supermq/auth"
|
||||
|
||||
type authenticateRes struct {
|
||||
id string
|
||||
userID string
|
||||
userRole smqauth.Role
|
||||
verified bool
|
||||
}
|
||||
|
||||
type authorizeRes struct {
|
||||
id string
|
||||
authorized bool
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
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"
|
||||
kitgrpc "github.com/go-kit/kit/transport/grpc"
|
||||
)
|
||||
|
||||
var _ grpcAuthV1.AuthServiceServer = (*authGrpcServer)(nil)
|
||||
|
||||
type authGrpcServer struct {
|
||||
grpcAuthV1.UnimplementedAuthServiceServer
|
||||
authorize kitgrpc.Handler
|
||||
authenticate kitgrpc.Handler
|
||||
}
|
||||
|
||||
// NewAuthServer returns new AuthnServiceServer instance.
|
||||
func NewAuthServer(svc auth.Service) grpcAuthV1.AuthServiceServer {
|
||||
return &authGrpcServer{
|
||||
authorize: kitgrpc.NewServer(
|
||||
(authorizeEndpoint(svc)),
|
||||
decodeAuthorizeRequest,
|
||||
encodeAuthorizeResponse,
|
||||
),
|
||||
|
||||
authenticate: kitgrpc.NewServer(
|
||||
(authenticateEndpoint(svc)),
|
||||
decodeAuthenticateRequest,
|
||||
encodeAuthenticateResponse,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *authGrpcServer) Authenticate(ctx context.Context, req *grpcAuthV1.AuthNReq) (*grpcAuthV1.AuthNRes, error) {
|
||||
_, res, err := s.authenticate.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 {
|
||||
return nil, grpcapi.EncodeError(err)
|
||||
}
|
||||
return res.(*grpcAuthV1.AuthZRes), nil
|
||||
}
|
||||
|
||||
func decodeAuthenticateRequest(_ context.Context, grpcReq any) (any, error) {
|
||||
req := grpcReq.(*grpcAuthV1.AuthNReq)
|
||||
return authenticateReq{token: req.GetToken()}, nil
|
||||
}
|
||||
|
||||
func encodeAuthenticateResponse(_ context.Context, grpcRes any) (any, error) {
|
||||
res := grpcRes.(authenticateRes)
|
||||
return &grpcAuthV1.AuthNRes{Id: res.id, UserId: res.userID, UserRole: uint32(res.userRole), Verified: res.verified}, nil
|
||||
}
|
||||
|
||||
func decodeAuthorizeRequest(_ context.Context, grpcReq any) (any, error) {
|
||||
req := grpcReq.(*grpcAuthV1.AuthZReq)
|
||||
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 {
|
||||
authRequest.UserID = patReq.GetUserId()
|
||||
authRequest.PatID = patReq.GetPatId()
|
||||
authRequest.EntityType = patReq.GetEntityType()
|
||||
authRequest.Operation = patReq.GetOperation()
|
||||
authRequest.EntityID = patReq.GetEntityId()
|
||||
}
|
||||
|
||||
return authRequest, nil
|
||||
}
|
||||
|
||||
func encodeAuthorizeResponse(_ context.Context, grpcRes any) (any, error) {
|
||||
res := grpcRes.(authorizeRes)
|
||||
return &grpcAuthV1.AuthZRes{Authorized: res.authorized, Id: res.id}, nil
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// 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)
|
||||
}
|
||||
@@ -1,749 +0,0 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/magistrala"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
kitgrpc "github.com/go-kit/kit/transport/grpc"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
const svcName = "magistrala.AuthService"
|
||||
|
||||
var _ magistrala.AuthServiceClient = (*grpcClient)(nil)
|
||||
|
||||
type grpcClient struct {
|
||||
issue endpoint.Endpoint
|
||||
refresh endpoint.Endpoint
|
||||
identify endpoint.Endpoint
|
||||
authorize endpoint.Endpoint
|
||||
addPolicy endpoint.Endpoint
|
||||
addPolicies endpoint.Endpoint
|
||||
deletePolicy endpoint.Endpoint
|
||||
deletePolicies endpoint.Endpoint
|
||||
listObjects endpoint.Endpoint
|
||||
listAllObjects endpoint.Endpoint
|
||||
countObjects endpoint.Endpoint
|
||||
listSubjects endpoint.Endpoint
|
||||
listAllSubjects endpoint.Endpoint
|
||||
countSubjects endpoint.Endpoint
|
||||
listPermissions endpoint.Endpoint
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
// NewClient returns new gRPC client instance.
|
||||
func NewClient(conn *grpc.ClientConn, timeout time.Duration) magistrala.AuthServiceClient {
|
||||
return &grpcClient{
|
||||
issue: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"Issue",
|
||||
encodeIssueRequest,
|
||||
decodeIssueResponse,
|
||||
magistrala.Token{},
|
||||
).Endpoint(),
|
||||
refresh: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"Refresh",
|
||||
encodeRefreshRequest,
|
||||
decodeRefreshResponse,
|
||||
magistrala.Token{},
|
||||
).Endpoint(),
|
||||
identify: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"Identify",
|
||||
encodeIdentifyRequest,
|
||||
decodeIdentifyResponse,
|
||||
magistrala.IdentityRes{},
|
||||
).Endpoint(),
|
||||
authorize: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"Authorize",
|
||||
encodeAuthorizeRequest,
|
||||
decodeAuthorizeResponse,
|
||||
magistrala.AuthorizeRes{},
|
||||
).Endpoint(),
|
||||
addPolicy: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"AddPolicy",
|
||||
encodeAddPolicyRequest,
|
||||
decodeAddPolicyResponse,
|
||||
magistrala.AddPolicyRes{},
|
||||
).Endpoint(),
|
||||
addPolicies: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"AddPolicies",
|
||||
encodeAddPoliciesRequest,
|
||||
decodeAddPoliciesResponse,
|
||||
magistrala.AddPoliciesRes{},
|
||||
).Endpoint(),
|
||||
deletePolicy: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"DeletePolicy",
|
||||
encodeDeletePolicyRequest,
|
||||
decodeDeletePolicyResponse,
|
||||
magistrala.DeletePolicyRes{},
|
||||
).Endpoint(),
|
||||
deletePolicies: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"DeletePolicies",
|
||||
encodeDeletePoliciesRequest,
|
||||
decodeDeletePoliciesResponse,
|
||||
magistrala.DeletePoliciesRes{},
|
||||
).Endpoint(),
|
||||
listObjects: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"ListObjects",
|
||||
encodeListObjectsRequest,
|
||||
decodeListObjectsResponse,
|
||||
magistrala.ListObjectsRes{},
|
||||
).Endpoint(),
|
||||
listAllObjects: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"ListAllObjects",
|
||||
encodeListObjectsRequest,
|
||||
decodeListObjectsResponse,
|
||||
magistrala.ListObjectsRes{},
|
||||
).Endpoint(),
|
||||
countObjects: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"CountObjects",
|
||||
encodeCountObjectsRequest,
|
||||
decodeCountObjectsResponse,
|
||||
magistrala.CountObjectsRes{},
|
||||
).Endpoint(),
|
||||
listSubjects: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"ListSubjects",
|
||||
encodeListSubjectsRequest,
|
||||
decodeListSubjectsResponse,
|
||||
magistrala.ListSubjectsRes{},
|
||||
).Endpoint(),
|
||||
listAllSubjects: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"ListAllSubjects",
|
||||
encodeListSubjectsRequest,
|
||||
decodeListSubjectsResponse,
|
||||
magistrala.ListSubjectsRes{},
|
||||
).Endpoint(),
|
||||
countSubjects: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"CountSubjects",
|
||||
encodeCountSubjectsRequest,
|
||||
decodeCountSubjectsResponse,
|
||||
magistrala.CountSubjectsRes{},
|
||||
).Endpoint(),
|
||||
listPermissions: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"ListPermissions",
|
||||
encodeListPermissionsRequest,
|
||||
decodeListPermissionsResponse,
|
||||
magistrala.ListPermissionsRes{},
|
||||
).Endpoint(),
|
||||
|
||||
timeout: timeout,
|
||||
}
|
||||
}
|
||||
|
||||
func (client grpcClient) Issue(ctx context.Context, req *magistrala.IssueReq, _ ...grpc.CallOption) (*magistrala.Token, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := client.issue(ctx, issueReq{userID: req.GetUserId(), domainID: req.GetDomainId(), keyType: auth.KeyType(req.Type)})
|
||||
if err != nil {
|
||||
return &magistrala.Token{}, decodeError(err)
|
||||
}
|
||||
return res.(*magistrala.Token), nil
|
||||
}
|
||||
|
||||
func encodeIssueRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(issueReq)
|
||||
return &magistrala.IssueReq{UserId: req.userID, DomainId: &req.domainID, Type: uint32(req.keyType)}, nil
|
||||
}
|
||||
|
||||
func decodeIssueResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
return grpcRes, nil
|
||||
}
|
||||
|
||||
func (client grpcClient) Refresh(ctx context.Context, req *magistrala.RefreshReq, _ ...grpc.CallOption) (*magistrala.Token, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := client.refresh(ctx, refreshReq{refreshToken: req.GetRefreshToken(), domainID: req.GetDomainId()})
|
||||
if err != nil {
|
||||
return &magistrala.Token{}, decodeError(err)
|
||||
}
|
||||
return res.(*magistrala.Token), nil
|
||||
}
|
||||
|
||||
func encodeRefreshRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(refreshReq)
|
||||
return &magistrala.RefreshReq{RefreshToken: req.refreshToken, DomainId: &req.domainID}, nil
|
||||
}
|
||||
|
||||
func decodeRefreshResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
return grpcRes, nil
|
||||
}
|
||||
|
||||
func (client grpcClient) Identify(ctx context.Context, token *magistrala.IdentityReq, _ ...grpc.CallOption) (*magistrala.IdentityRes, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := client.identify(ctx, identityReq{token: token.GetToken()})
|
||||
if err != nil {
|
||||
return &magistrala.IdentityRes{}, decodeError(err)
|
||||
}
|
||||
ir := res.(identityRes)
|
||||
return &magistrala.IdentityRes{Id: ir.id, UserId: ir.userID, DomainId: ir.domainID}, nil
|
||||
}
|
||||
|
||||
func encodeIdentifyRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(identityReq)
|
||||
return &magistrala.IdentityReq{Token: req.token}, nil
|
||||
}
|
||||
|
||||
func decodeIdentifyResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(*magistrala.IdentityRes)
|
||||
return identityRes{id: res.GetId(), userID: res.GetUserId(), domainID: res.GetDomainId()}, nil
|
||||
}
|
||||
|
||||
func (client grpcClient) Authorize(ctx context.Context, req *magistrala.AuthorizeReq, _ ...grpc.CallOption) (r *magistrala.AuthorizeRes, 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(),
|
||||
})
|
||||
if err != nil {
|
||||
return &magistrala.AuthorizeRes{}, decodeError(err)
|
||||
}
|
||||
|
||||
ar := res.(authorizeRes)
|
||||
return &magistrala.AuthorizeRes{Authorized: ar.authorized, Id: ar.id}, nil
|
||||
}
|
||||
|
||||
func decodeAuthorizeResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(*magistrala.AuthorizeRes)
|
||||
return authorizeRes{authorized: res.Authorized, id: res.Id}, nil
|
||||
}
|
||||
|
||||
func encodeAuthorizeRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(authReq)
|
||||
return &magistrala.AuthorizeReq{
|
||||
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 grpcClient) AddPolicy(ctx context.Context, in *magistrala.AddPolicyReq, opts ...grpc.CallOption) (*magistrala.AddPolicyRes, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := client.addPolicy(ctx, policyReq{
|
||||
Domain: in.GetDomain(),
|
||||
SubjectType: in.GetSubjectType(),
|
||||
SubjectKind: in.GetSubjectKind(),
|
||||
Subject: in.GetSubject(),
|
||||
Relation: in.GetRelation(),
|
||||
Permission: in.GetPermission(),
|
||||
ObjectType: in.GetObjectType(),
|
||||
ObjectKind: in.GetObjectKind(),
|
||||
Object: in.GetObject(),
|
||||
})
|
||||
if err != nil {
|
||||
return &magistrala.AddPolicyRes{}, decodeError(err)
|
||||
}
|
||||
|
||||
apr := res.(addPolicyRes)
|
||||
return &magistrala.AddPolicyRes{Added: apr.added}, nil
|
||||
}
|
||||
|
||||
func decodeAddPolicyResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(*magistrala.AddPolicyRes)
|
||||
return addPolicyRes{added: res.Added}, nil
|
||||
}
|
||||
|
||||
func encodeAddPolicyRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(policyReq)
|
||||
return &magistrala.AddPolicyReq{
|
||||
Domain: req.Domain,
|
||||
SubjectType: req.SubjectType,
|
||||
SubjectKind: req.SubjectKind,
|
||||
Subject: req.Subject,
|
||||
Relation: req.Relation,
|
||||
Permission: req.Permission,
|
||||
ObjectType: req.ObjectType,
|
||||
ObjectKind: req.ObjectKind,
|
||||
Object: req.Object,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (client grpcClient) AddPolicies(ctx context.Context, in *magistrala.AddPoliciesReq, opts ...grpc.CallOption) (*magistrala.AddPoliciesRes, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
r := policiesReq{}
|
||||
if in.GetAddPoliciesReq() != nil {
|
||||
for _, mgApr := range in.GetAddPoliciesReq() {
|
||||
r = append(r, policyReq{
|
||||
Domain: mgApr.GetDomain(),
|
||||
SubjectType: mgApr.GetSubjectType(),
|
||||
SubjectKind: mgApr.GetSubjectKind(),
|
||||
Subject: mgApr.GetSubject(),
|
||||
Relation: mgApr.GetRelation(),
|
||||
Permission: mgApr.GetPermission(),
|
||||
ObjectType: mgApr.GetObjectType(),
|
||||
ObjectKind: mgApr.GetObjectKind(),
|
||||
Object: mgApr.GetObject(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
res, err := client.addPolicies(ctx, r)
|
||||
if err != nil {
|
||||
return &magistrala.AddPoliciesRes{}, decodeError(err)
|
||||
}
|
||||
|
||||
apr := res.(addPoliciesRes)
|
||||
return &magistrala.AddPoliciesRes{Added: apr.added}, nil
|
||||
}
|
||||
|
||||
func decodeAddPoliciesResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(*magistrala.AddPoliciesRes)
|
||||
return addPoliciesRes{added: res.Added}, nil
|
||||
}
|
||||
|
||||
func encodeAddPoliciesRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
reqs := grpcReq.(policiesReq)
|
||||
|
||||
addPolicies := []*magistrala.AddPolicyReq{}
|
||||
|
||||
for _, req := range reqs {
|
||||
addPolicies = append(addPolicies, &magistrala.AddPolicyReq{
|
||||
Domain: req.Domain,
|
||||
SubjectType: req.SubjectType,
|
||||
SubjectKind: req.SubjectKind,
|
||||
Subject: req.Subject,
|
||||
Relation: req.Relation,
|
||||
Permission: req.Permission,
|
||||
ObjectType: req.ObjectType,
|
||||
ObjectKind: req.ObjectKind,
|
||||
Object: req.Object,
|
||||
})
|
||||
}
|
||||
return &magistrala.AddPoliciesReq{AddPoliciesReq: addPolicies}, nil
|
||||
}
|
||||
|
||||
func (client grpcClient) DeletePolicy(ctx context.Context, in *magistrala.DeletePolicyReq, opts ...grpc.CallOption) (*magistrala.DeletePolicyRes, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := client.deletePolicy(ctx, policyReq{
|
||||
Domain: in.GetDomain(),
|
||||
SubjectType: in.GetSubjectType(),
|
||||
SubjectKind: in.GetSubjectKind(),
|
||||
Subject: in.GetSubject(),
|
||||
Relation: in.GetRelation(),
|
||||
Permission: in.GetPermission(),
|
||||
ObjectType: in.GetObjectType(),
|
||||
ObjectKind: in.GetObjectKind(),
|
||||
Object: in.GetObject(),
|
||||
})
|
||||
if err != nil {
|
||||
return &magistrala.DeletePolicyRes{}, decodeError(err)
|
||||
}
|
||||
|
||||
dpr := res.(deletePolicyRes)
|
||||
return &magistrala.DeletePolicyRes{Deleted: dpr.deleted}, nil
|
||||
}
|
||||
|
||||
func decodeDeletePolicyResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(*magistrala.DeletePolicyRes)
|
||||
return deletePolicyRes{deleted: res.GetDeleted()}, nil
|
||||
}
|
||||
|
||||
func encodeDeletePolicyRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(policyReq)
|
||||
return &magistrala.DeletePolicyReq{
|
||||
Domain: req.Domain,
|
||||
SubjectType: req.SubjectType,
|
||||
SubjectKind: req.SubjectKind,
|
||||
Subject: req.Subject,
|
||||
Relation: req.Relation,
|
||||
Permission: req.Permission,
|
||||
ObjectType: req.ObjectType,
|
||||
ObjectKind: req.ObjectKind,
|
||||
Object: req.Object,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (client grpcClient) DeletePolicies(ctx context.Context, in *magistrala.DeletePoliciesReq, opts ...grpc.CallOption) (*magistrala.DeletePoliciesRes, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
r := policiesReq{}
|
||||
|
||||
if in.GetDeletePoliciesReq() != nil {
|
||||
for _, mgApr := range in.GetDeletePoliciesReq() {
|
||||
r = append(r, policyReq{
|
||||
Domain: mgApr.GetDomain(),
|
||||
SubjectType: mgApr.GetSubjectType(),
|
||||
SubjectKind: mgApr.GetSubjectKind(),
|
||||
Subject: mgApr.GetSubject(),
|
||||
Relation: mgApr.GetRelation(),
|
||||
Permission: mgApr.GetPermission(),
|
||||
ObjectType: mgApr.GetObjectType(),
|
||||
ObjectKind: mgApr.GetObjectKind(),
|
||||
Object: mgApr.GetObject(),
|
||||
})
|
||||
}
|
||||
}
|
||||
res, err := client.deletePolicies(ctx, r)
|
||||
if err != nil {
|
||||
return &magistrala.DeletePoliciesRes{}, decodeError(err)
|
||||
}
|
||||
|
||||
dpr := res.(deletePoliciesRes)
|
||||
return &magistrala.DeletePoliciesRes{Deleted: dpr.deleted}, nil
|
||||
}
|
||||
|
||||
func decodeDeletePoliciesResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(*magistrala.DeletePoliciesRes)
|
||||
return deletePoliciesRes{deleted: res.GetDeleted()}, nil
|
||||
}
|
||||
|
||||
func encodeDeletePoliciesRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
reqs := grpcReq.(policiesReq)
|
||||
|
||||
deletePolicies := []*magistrala.DeletePolicyReq{}
|
||||
|
||||
for _, req := range reqs {
|
||||
deletePolicies = append(deletePolicies, &magistrala.DeletePolicyReq{
|
||||
Domain: req.Domain,
|
||||
SubjectType: req.SubjectType,
|
||||
SubjectKind: req.SubjectKind,
|
||||
Subject: req.Subject,
|
||||
Relation: req.Relation,
|
||||
Permission: req.Permission,
|
||||
ObjectType: req.ObjectType,
|
||||
ObjectKind: req.ObjectKind,
|
||||
Object: req.Object,
|
||||
})
|
||||
}
|
||||
return &magistrala.DeletePoliciesReq{DeletePoliciesReq: deletePolicies}, nil
|
||||
}
|
||||
|
||||
func (client grpcClient) ListObjects(ctx context.Context, in *magistrala.ListObjectsReq, opts ...grpc.CallOption) (*magistrala.ListObjectsRes, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := client.listObjects(ctx, listObjectsReq{
|
||||
Domain: in.GetDomain(),
|
||||
SubjectType: in.GetSubjectType(),
|
||||
Subject: in.GetSubject(),
|
||||
Relation: in.GetRelation(),
|
||||
Permission: in.GetPermission(),
|
||||
ObjectType: in.GetObjectType(),
|
||||
Object: in.GetObject(),
|
||||
})
|
||||
if err != nil {
|
||||
return &magistrala.ListObjectsRes{}, decodeError(err)
|
||||
}
|
||||
|
||||
lpr := res.(listObjectsRes)
|
||||
return &magistrala.ListObjectsRes{Policies: lpr.policies}, nil
|
||||
}
|
||||
|
||||
func decodeListObjectsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(*magistrala.ListObjectsRes)
|
||||
return listObjectsRes{policies: res.GetPolicies()}, nil
|
||||
}
|
||||
|
||||
func encodeListObjectsRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(listObjectsReq)
|
||||
return &magistrala.ListObjectsReq{
|
||||
Domain: req.Domain,
|
||||
SubjectType: req.SubjectType,
|
||||
Subject: req.Subject,
|
||||
Relation: req.Relation,
|
||||
Permission: req.Permission,
|
||||
ObjectType: req.ObjectType,
|
||||
Object: req.Object,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (client grpcClient) ListAllObjects(ctx context.Context, in *magistrala.ListObjectsReq, opts ...grpc.CallOption) (*magistrala.ListObjectsRes, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := client.listAllObjects(ctx, listObjectsReq{
|
||||
Domain: in.GetDomain(),
|
||||
SubjectType: in.GetSubjectType(),
|
||||
Subject: in.GetSubject(),
|
||||
Relation: in.GetRelation(),
|
||||
Permission: in.GetPermission(),
|
||||
ObjectType: in.GetObjectType(),
|
||||
Object: in.GetObject(),
|
||||
})
|
||||
if err != nil {
|
||||
return &magistrala.ListObjectsRes{}, decodeError(err)
|
||||
}
|
||||
|
||||
lpr := res.(listObjectsRes)
|
||||
return &magistrala.ListObjectsRes{Policies: lpr.policies}, nil
|
||||
}
|
||||
|
||||
func (client grpcClient) CountObjects(ctx context.Context, in *magistrala.CountObjectsReq, opts ...grpc.CallOption) (*magistrala.CountObjectsRes, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := client.countObjects(ctx, countObjectsReq{
|
||||
Domain: in.GetDomain(),
|
||||
SubjectType: in.GetSubjectType(),
|
||||
Subject: in.GetSubject(),
|
||||
Relation: in.GetRelation(),
|
||||
Permission: in.GetPermission(),
|
||||
ObjectType: in.GetObjectType(),
|
||||
Object: in.GetObject(),
|
||||
})
|
||||
if err != nil {
|
||||
return &magistrala.CountObjectsRes{}, decodeError(err)
|
||||
}
|
||||
|
||||
cp := res.(countObjectsRes)
|
||||
return &magistrala.CountObjectsRes{Count: int64(cp.count)}, nil
|
||||
}
|
||||
|
||||
func decodeCountObjectsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(*magistrala.CountObjectsRes)
|
||||
return countObjectsRes{count: int(res.GetCount())}, nil
|
||||
}
|
||||
|
||||
func encodeCountObjectsRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(countObjectsReq)
|
||||
return &magistrala.CountObjectsReq{
|
||||
Domain: req.Domain,
|
||||
SubjectType: req.SubjectType,
|
||||
Subject: req.Subject,
|
||||
Relation: req.Relation,
|
||||
Permission: req.Permission,
|
||||
ObjectType: req.ObjectType,
|
||||
Object: req.Object,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (client grpcClient) ListSubjects(ctx context.Context, in *magistrala.ListSubjectsReq, opts ...grpc.CallOption) (*magistrala.ListSubjectsRes, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := client.listSubjects(ctx, listSubjectsReq{
|
||||
Domain: in.GetDomain(),
|
||||
SubjectType: in.GetSubjectType(),
|
||||
Subject: in.GetSubject(),
|
||||
Relation: in.GetRelation(),
|
||||
Permission: in.GetPermission(),
|
||||
ObjectType: in.GetObjectType(),
|
||||
Object: in.GetObject(),
|
||||
NextPageToken: in.GetNextPageToken(),
|
||||
})
|
||||
if err != nil {
|
||||
return &magistrala.ListSubjectsRes{}, decodeError(err)
|
||||
}
|
||||
|
||||
lpr := res.(listSubjectsRes)
|
||||
return &magistrala.ListSubjectsRes{Policies: lpr.policies}, nil
|
||||
}
|
||||
|
||||
func decodeListSubjectsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(*magistrala.ListSubjectsRes)
|
||||
return listSubjectsRes{policies: res.GetPolicies()}, nil
|
||||
}
|
||||
|
||||
func encodeListSubjectsRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(listSubjectsReq)
|
||||
return &magistrala.ListSubjectsReq{
|
||||
Domain: req.Domain,
|
||||
SubjectType: req.SubjectType,
|
||||
Subject: req.Subject,
|
||||
Relation: req.Relation,
|
||||
Permission: req.Permission,
|
||||
ObjectType: req.ObjectType,
|
||||
Object: req.Object,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (client grpcClient) ListAllSubjects(ctx context.Context, in *magistrala.ListSubjectsReq, opts ...grpc.CallOption) (*magistrala.ListSubjectsRes, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := client.listAllSubjects(ctx, listSubjectsReq{
|
||||
Domain: in.GetDomain(),
|
||||
SubjectType: in.GetSubjectType(),
|
||||
Subject: in.GetSubject(),
|
||||
Relation: in.GetRelation(),
|
||||
Permission: in.GetPermission(),
|
||||
ObjectType: in.GetObjectType(),
|
||||
Object: in.GetObject(),
|
||||
})
|
||||
if err != nil {
|
||||
return &magistrala.ListSubjectsRes{}, decodeError(err)
|
||||
}
|
||||
|
||||
lpr := res.(listSubjectsRes)
|
||||
return &magistrala.ListSubjectsRes{Policies: lpr.policies}, nil
|
||||
}
|
||||
|
||||
func (client grpcClient) CountSubjects(ctx context.Context, in *magistrala.CountSubjectsReq, opts ...grpc.CallOption) (*magistrala.CountSubjectsRes, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := client.countSubjects(ctx, countSubjectsReq{
|
||||
Domain: in.GetDomain(),
|
||||
SubjectType: in.GetSubjectType(),
|
||||
Subject: in.GetSubject(),
|
||||
Relation: in.GetRelation(),
|
||||
Permission: in.GetPermission(),
|
||||
ObjectType: in.GetObjectType(),
|
||||
Object: in.GetObject(),
|
||||
})
|
||||
if err != nil {
|
||||
return &magistrala.CountSubjectsRes{}, err
|
||||
}
|
||||
|
||||
cp := res.(countSubjectsRes)
|
||||
return &magistrala.CountSubjectsRes{Count: int64(cp.count)}, err
|
||||
}
|
||||
|
||||
func decodeCountSubjectsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(*magistrala.CountSubjectsRes)
|
||||
return countSubjectsRes{count: int(res.GetCount())}, nil
|
||||
}
|
||||
|
||||
func encodeCountSubjectsRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(countSubjectsReq)
|
||||
return &magistrala.CountSubjectsReq{
|
||||
Domain: req.Domain,
|
||||
SubjectType: req.SubjectType,
|
||||
Subject: req.Subject,
|
||||
Relation: req.Relation,
|
||||
Permission: req.Permission,
|
||||
ObjectType: req.ObjectType,
|
||||
Object: req.Object,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (client grpcClient) ListPermissions(ctx context.Context, in *magistrala.ListPermissionsReq, opts ...grpc.CallOption) (*magistrala.ListPermissionsRes, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := client.listPermissions(ctx, listPermissionsReq{
|
||||
Domain: in.GetDomain(),
|
||||
SubjectType: in.GetSubjectType(),
|
||||
Subject: in.GetSubject(),
|
||||
SubjectRelation: in.GetSubjectRelation(),
|
||||
ObjectType: in.GetObjectType(),
|
||||
Object: in.GetObject(),
|
||||
FilterPermissions: in.GetFilterPermissions(),
|
||||
})
|
||||
if err != nil {
|
||||
return &magistrala.ListPermissionsRes{}, decodeError(err)
|
||||
}
|
||||
|
||||
lp := res.(listPermissionsRes)
|
||||
return &magistrala.ListPermissionsRes{
|
||||
Domain: lp.Domain,
|
||||
SubjectType: lp.SubjectType,
|
||||
Subject: lp.Subject,
|
||||
SubjectRelation: lp.SubjectRelation,
|
||||
ObjectType: lp.ObjectType,
|
||||
Object: lp.Object,
|
||||
Permissions: lp.Permissions,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func decodeListPermissionsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(*magistrala.ListPermissionsRes)
|
||||
return listPermissionsRes{
|
||||
Domain: res.GetDomain(),
|
||||
SubjectType: res.GetSubjectType(),
|
||||
Subject: res.GetSubject(),
|
||||
SubjectRelation: res.GetSubjectRelation(),
|
||||
ObjectType: res.GetObjectType(),
|
||||
Object: res.GetObject(),
|
||||
Permissions: res.GetPermissions(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func encodeListPermissionsRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(listPermissionsReq)
|
||||
return &magistrala.ListPermissionsReq{
|
||||
Domain: req.Domain,
|
||||
SubjectType: req.SubjectType,
|
||||
Subject: req.Subject,
|
||||
ObjectType: req.ObjectType,
|
||||
Object: req.Object,
|
||||
FilterPermissions: req.FilterPermissions,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func decodeError(err error) error {
|
||||
if st, ok := status.FromError(err); ok {
|
||||
switch st.Code() {
|
||||
case codes.NotFound:
|
||||
return errors.Wrap(errors.ErrNotFound, errors.New(st.Message()))
|
||||
case codes.InvalidArgument:
|
||||
return errors.Wrap(errors.ErrMalformedEntity, errors.New(st.Message()))
|
||||
case codes.AlreadyExists:
|
||||
return errors.Wrap(errors.ErrConflict, errors.New(st.Message()))
|
||||
case codes.Unauthenticated:
|
||||
return errors.Wrap(errors.ErrAuthentication, errors.New(st.Message()))
|
||||
case codes.OK:
|
||||
if msg := st.Message(); msg != "" {
|
||||
return errors.Wrap(errors.ErrUnidentified, errors.New(msg))
|
||||
}
|
||||
return nil
|
||||
case codes.FailedPrecondition:
|
||||
return errors.Wrap(errors.ErrMalformedEntity, errors.New(st.Message()))
|
||||
case codes.PermissionDenied:
|
||||
return errors.Wrap(errors.ErrAuthorization, errors.New(st.Message()))
|
||||
default:
|
||||
return errors.Wrap(fmt.Errorf("unexpected gRPC status: %s (status code:%v)", st.Code().String(), st.Code()), errors.New(st.Message()))
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,351 +0,0 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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) {
|
||||
req := request.(issueReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return issueRes{}, err
|
||||
}
|
||||
|
||||
key := auth.Key{
|
||||
Type: req.keyType,
|
||||
User: req.userID,
|
||||
Domain: req.domainID,
|
||||
}
|
||||
tkn, err := svc.Issue(ctx, "", key)
|
||||
if err != nil {
|
||||
return issueRes{}, err
|
||||
}
|
||||
ret := issueRes{
|
||||
accessToken: tkn.AccessToken,
|
||||
refreshToken: tkn.RefreshToken,
|
||||
accessType: tkn.AccessType,
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
}
|
||||
|
||||
func refreshEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(refreshReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return issueRes{}, err
|
||||
}
|
||||
|
||||
key := auth.Key{Domain: req.domainID, Type: auth.RefreshKey}
|
||||
tkn, err := svc.Issue(ctx, req.refreshToken, key)
|
||||
if err != nil {
|
||||
return issueRes{}, err
|
||||
}
|
||||
ret := issueRes{
|
||||
accessToken: tkn.AccessToken,
|
||||
refreshToken: tkn.RefreshToken,
|
||||
accessType: tkn.AccessType,
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
}
|
||||
|
||||
func identifyEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(identityReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return identityRes{}, err
|
||||
}
|
||||
|
||||
key, err := svc.Identify(ctx, req.token)
|
||||
if err != nil {
|
||||
return identityRes{}, err
|
||||
}
|
||||
|
||||
return identityRes{id: key.Subject, userID: key.User, domainID: key.Domain}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func authorizeEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(authReq)
|
||||
|
||||
if err := req.validate(); err != nil {
|
||||
return authorizeRes{}, err
|
||||
}
|
||||
err := svc.Authorize(ctx, auth.PolicyReq{
|
||||
Domain: req.Domain,
|
||||
SubjectType: req.SubjectType,
|
||||
SubjectKind: req.SubjectKind,
|
||||
Subject: req.Subject,
|
||||
Relation: req.Relation,
|
||||
Permission: req.Permission,
|
||||
ObjectType: req.ObjectType,
|
||||
Object: req.Object,
|
||||
})
|
||||
if err != nil {
|
||||
return authorizeRes{authorized: false}, err
|
||||
}
|
||||
return authorizeRes{authorized: true}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func addPolicyEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(policyReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return addPolicyRes{}, err
|
||||
}
|
||||
|
||||
err := svc.AddPolicy(ctx, auth.PolicyReq{
|
||||
Domain: req.Domain,
|
||||
SubjectType: req.SubjectType,
|
||||
SubjectKind: req.SubjectKind,
|
||||
Subject: req.Subject,
|
||||
Relation: req.Relation,
|
||||
Permission: req.Permission,
|
||||
ObjectType: req.ObjectType,
|
||||
ObjectKind: req.ObjectKind,
|
||||
Object: req.Object,
|
||||
})
|
||||
if err != nil {
|
||||
return addPolicyRes{}, err
|
||||
}
|
||||
return addPolicyRes{added: true}, err
|
||||
}
|
||||
}
|
||||
|
||||
func addPoliciesEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
reqs := request.(policiesReq)
|
||||
if err := reqs.validate(); err != nil {
|
||||
return addPoliciesRes{}, err
|
||||
}
|
||||
|
||||
prs := []auth.PolicyReq{}
|
||||
|
||||
for _, req := range reqs {
|
||||
prs = append(prs, auth.PolicyReq{
|
||||
Domain: req.Domain,
|
||||
SubjectType: req.SubjectType,
|
||||
SubjectKind: req.SubjectKind,
|
||||
Subject: req.Subject,
|
||||
Relation: req.Relation,
|
||||
Permission: req.Permission,
|
||||
ObjectType: req.ObjectType,
|
||||
ObjectKind: req.ObjectKind,
|
||||
Object: req.Object,
|
||||
})
|
||||
}
|
||||
|
||||
if err := svc.AddPolicies(ctx, prs); err != nil {
|
||||
return addPoliciesRes{}, err
|
||||
}
|
||||
return addPoliciesRes{added: true}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func deletePolicyEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(policyReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return deletePolicyRes{}, err
|
||||
}
|
||||
|
||||
err := svc.DeletePolicy(ctx, auth.PolicyReq{
|
||||
Domain: req.Domain,
|
||||
SubjectKind: req.SubjectKind,
|
||||
SubjectType: req.SubjectType,
|
||||
Subject: req.Subject,
|
||||
Relation: req.Relation,
|
||||
Permission: req.Permission,
|
||||
ObjectType: req.ObjectType,
|
||||
ObjectKind: req.ObjectKind,
|
||||
Object: req.Object,
|
||||
})
|
||||
if err != nil {
|
||||
return deletePolicyRes{}, err
|
||||
}
|
||||
return deletePolicyRes{deleted: true}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func deletePoliciesEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
reqs := request.(policiesReq)
|
||||
if err := reqs.validate(); err != nil {
|
||||
return deletePoliciesRes{}, err
|
||||
}
|
||||
|
||||
prs := []auth.PolicyReq{}
|
||||
|
||||
for _, req := range reqs {
|
||||
prs = append(prs, auth.PolicyReq{
|
||||
Domain: req.Domain,
|
||||
SubjectType: req.SubjectType,
|
||||
SubjectKind: req.SubjectKind,
|
||||
Subject: req.Subject,
|
||||
Relation: req.Relation,
|
||||
Permission: req.Permission,
|
||||
ObjectType: req.ObjectType,
|
||||
ObjectKind: req.ObjectKind,
|
||||
Object: req.Object,
|
||||
})
|
||||
}
|
||||
|
||||
if err := svc.DeletePolicies(ctx, prs); err != nil {
|
||||
return deletePoliciesRes{}, err
|
||||
}
|
||||
return deletePoliciesRes{deleted: true}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func listObjectsEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(listObjectsReq)
|
||||
|
||||
page, err := svc.ListObjects(ctx, auth.PolicyReq{
|
||||
Domain: req.Domain,
|
||||
SubjectType: req.SubjectType,
|
||||
Subject: req.Subject,
|
||||
Relation: req.Relation,
|
||||
Permission: req.Permission,
|
||||
ObjectType: req.ObjectType,
|
||||
Object: req.Object,
|
||||
}, req.NextPageToken, req.Limit)
|
||||
if err != nil {
|
||||
return listObjectsRes{}, err
|
||||
}
|
||||
return listObjectsRes{policies: page.Policies, nextPageToken: page.NextPageToken}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func listAllObjectsEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(listObjectsReq)
|
||||
|
||||
page, err := svc.ListAllObjects(ctx, auth.PolicyReq{
|
||||
Domain: req.Domain,
|
||||
SubjectType: req.SubjectType,
|
||||
Subject: req.Subject,
|
||||
Relation: req.Relation,
|
||||
Permission: req.Permission,
|
||||
ObjectType: req.ObjectType,
|
||||
Object: req.Object,
|
||||
})
|
||||
if err != nil {
|
||||
return listObjectsRes{}, err
|
||||
}
|
||||
return listObjectsRes{policies: page.Policies, nextPageToken: page.NextPageToken}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func countObjectsEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(countObjectsReq)
|
||||
|
||||
count, err := svc.CountObjects(ctx, auth.PolicyReq{
|
||||
Domain: req.Domain,
|
||||
SubjectType: req.SubjectType,
|
||||
Subject: req.Subject,
|
||||
Relation: req.Relation,
|
||||
Permission: req.Permission,
|
||||
ObjectType: req.ObjectType,
|
||||
Object: req.Object,
|
||||
})
|
||||
if err != nil {
|
||||
return countObjectsRes{}, err
|
||||
}
|
||||
return countObjectsRes{count: count}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func listSubjectsEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(listSubjectsReq)
|
||||
|
||||
page, err := svc.ListSubjects(ctx, auth.PolicyReq{
|
||||
Domain: req.Domain,
|
||||
SubjectType: req.SubjectType,
|
||||
Subject: req.Subject,
|
||||
Relation: req.Relation,
|
||||
Permission: req.Permission,
|
||||
ObjectType: req.ObjectType,
|
||||
Object: req.Object,
|
||||
}, req.NextPageToken, req.Limit)
|
||||
if err != nil {
|
||||
return listSubjectsRes{}, err
|
||||
}
|
||||
return listSubjectsRes{policies: page.Policies, nextPageToken: page.NextPageToken}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func listAllSubjectsEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(listSubjectsReq)
|
||||
|
||||
page, err := svc.ListAllSubjects(ctx, auth.PolicyReq{
|
||||
Domain: req.Domain,
|
||||
SubjectType: req.SubjectType,
|
||||
Subject: req.Subject,
|
||||
Relation: req.Relation,
|
||||
Permission: req.Permission,
|
||||
ObjectType: req.ObjectType,
|
||||
Object: req.Object,
|
||||
})
|
||||
if err != nil {
|
||||
return listSubjectsRes{}, err
|
||||
}
|
||||
return listSubjectsRes{policies: page.Policies, nextPageToken: page.NextPageToken}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func countSubjectsEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(countSubjectsReq)
|
||||
|
||||
count, err := svc.CountSubjects(ctx, auth.PolicyReq{
|
||||
Domain: req.Domain,
|
||||
SubjectType: req.SubjectType,
|
||||
Subject: req.Subject,
|
||||
Relation: req.Relation,
|
||||
Permission: req.Permission,
|
||||
ObjectType: req.ObjectType,
|
||||
Object: req.Object,
|
||||
})
|
||||
if err != nil {
|
||||
return countSubjectsRes{}, err
|
||||
}
|
||||
return countSubjectsRes{count: count}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func listPermissionsEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(listPermissionsReq)
|
||||
permissions, err := svc.ListPermissions(ctx, auth.PolicyReq{
|
||||
SubjectType: req.SubjectType,
|
||||
SubjectRelation: req.SubjectRelation,
|
||||
Subject: req.Subject,
|
||||
Object: req.Object,
|
||||
ObjectType: req.ObjectType,
|
||||
}, req.FilterPermissions)
|
||||
if err != nil {
|
||||
return listPermissionsRes{}, err
|
||||
}
|
||||
return listPermissionsRes{
|
||||
SubjectType: req.SubjectType,
|
||||
SubjectRelation: req.SubjectRelation,
|
||||
Subject: req.Subject,
|
||||
Object: req.Object,
|
||||
ObjectType: req.ObjectType,
|
||||
Permissions: permissions,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,160 +0,0 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"github.com/absmach/magistrala/auth"
|
||||
"github.com/absmach/magistrala/internal/apiutil"
|
||||
)
|
||||
|
||||
type identityReq struct {
|
||||
token string
|
||||
}
|
||||
|
||||
func (req identityReq) validate() error {
|
||||
if req.token == "" {
|
||||
return apiutil.ErrBearerToken
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type issueReq struct {
|
||||
userID string
|
||||
domainID string // optional
|
||||
keyType auth.KeyType
|
||||
}
|
||||
|
||||
func (req issueReq) validate() error {
|
||||
if req.keyType != auth.AccessKey &&
|
||||
req.keyType != auth.APIKey &&
|
||||
req.keyType != auth.RecoveryKey &&
|
||||
req.keyType != auth.InvitationKey {
|
||||
return apiutil.ErrInvalidAuthKey
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type refreshReq struct {
|
||||
refreshToken string
|
||||
domainID string // optional
|
||||
}
|
||||
|
||||
func (req refreshReq) validate() error {
|
||||
if req.refreshToken == "" {
|
||||
return apiutil.ErrMissingSecret
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// authReq represents authorization request. It contains:
|
||||
// 1. subject - an action invoker
|
||||
// 2. object - an entity over which action will be executed
|
||||
// 3. action - type of action that will be executed (read/write).
|
||||
type authReq struct {
|
||||
Domain string
|
||||
SubjectType string
|
||||
SubjectKind string
|
||||
Subject string
|
||||
Relation string
|
||||
Permission string
|
||||
ObjectType string
|
||||
Object string
|
||||
}
|
||||
|
||||
func (req authReq) validate() error {
|
||||
if req.Subject == "" || req.SubjectType == "" {
|
||||
return apiutil.ErrMissingPolicySub
|
||||
}
|
||||
|
||||
if req.Object == "" || req.ObjectType == "" {
|
||||
return apiutil.ErrMissingPolicyObj
|
||||
}
|
||||
|
||||
if req.Permission == "" {
|
||||
return apiutil.ErrMalformedPolicyPer
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type policyReq struct {
|
||||
Domain string
|
||||
SubjectType string
|
||||
Subject string
|
||||
SubjectKind string
|
||||
Relation string
|
||||
Permission string
|
||||
ObjectType string
|
||||
ObjectKind string
|
||||
Object string
|
||||
}
|
||||
|
||||
func (req policyReq) validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type policiesReq []policyReq
|
||||
|
||||
func (prs policiesReq) validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type listObjectsReq struct {
|
||||
Domain string
|
||||
SubjectType string
|
||||
Subject string
|
||||
Relation string
|
||||
Permission string
|
||||
ObjectType string
|
||||
Object string
|
||||
NextPageToken string
|
||||
Limit int32
|
||||
}
|
||||
|
||||
type countObjectsReq struct {
|
||||
Domain string
|
||||
SubjectType string
|
||||
Subject string
|
||||
Relation string
|
||||
Permission string
|
||||
ObjectType string
|
||||
Object string
|
||||
NextPageToken string
|
||||
}
|
||||
|
||||
type listSubjectsReq struct {
|
||||
Domain string
|
||||
SubjectType string
|
||||
Subject string
|
||||
Relation string
|
||||
Permission string
|
||||
ObjectType string
|
||||
Object string
|
||||
NextPageToken string
|
||||
Limit int32
|
||||
}
|
||||
|
||||
type countSubjectsReq struct {
|
||||
Domain string
|
||||
SubjectType string
|
||||
Subject string
|
||||
Relation string
|
||||
Permission string
|
||||
ObjectType string
|
||||
Object string
|
||||
NextPageToken string
|
||||
}
|
||||
|
||||
type listPermissionsReq struct {
|
||||
Domain string
|
||||
SubjectType string
|
||||
Subject string
|
||||
SubjectRelation string
|
||||
ObjectType string
|
||||
Object string
|
||||
FilterPermissions []string
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package grpc
|
||||
|
||||
type identityRes struct {
|
||||
id string
|
||||
userID string
|
||||
domainID string
|
||||
}
|
||||
|
||||
type issueRes struct {
|
||||
accessToken string
|
||||
refreshToken string
|
||||
accessType string
|
||||
}
|
||||
|
||||
type authorizeRes struct {
|
||||
id string
|
||||
authorized bool
|
||||
}
|
||||
|
||||
type addPolicyRes struct {
|
||||
added bool
|
||||
}
|
||||
type addPoliciesRes struct {
|
||||
added bool
|
||||
}
|
||||
|
||||
type deletePolicyRes struct {
|
||||
deleted bool
|
||||
}
|
||||
|
||||
type deletePoliciesRes struct {
|
||||
deleted bool
|
||||
}
|
||||
|
||||
type listObjectsRes struct {
|
||||
policies []string
|
||||
nextPageToken string
|
||||
}
|
||||
|
||||
type countObjectsRes struct {
|
||||
count int
|
||||
}
|
||||
|
||||
type listSubjectsRes struct {
|
||||
policies []string
|
||||
nextPageToken string
|
||||
}
|
||||
|
||||
type countSubjectsRes struct {
|
||||
count int
|
||||
}
|
||||
|
||||
type listPermissionsRes struct {
|
||||
Domain string
|
||||
SubjectType string
|
||||
Subject string
|
||||
SubjectRelation string
|
||||
ObjectType string
|
||||
Object string
|
||||
Permissions []string
|
||||
}
|
||||
@@ -1,558 +0,0 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/absmach/magistrala"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
"github.com/absmach/magistrala/internal/apiutil"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
kitgrpc "github.com/go-kit/kit/transport/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
var _ magistrala.AuthServiceServer = (*grpcServer)(nil)
|
||||
|
||||
var (
|
||||
defThingsFilterPermissions = []string{
|
||||
auth.AdminPermission,
|
||||
auth.DeletePermission,
|
||||
auth.EditPermission,
|
||||
auth.ViewPermission,
|
||||
auth.SharePermission,
|
||||
auth.PublishPermission,
|
||||
auth.SubscribePermission,
|
||||
}
|
||||
|
||||
defGroupsFilterPermissions = []string{
|
||||
auth.AdminPermission,
|
||||
auth.DeletePermission,
|
||||
auth.EditPermission,
|
||||
auth.ViewPermission,
|
||||
auth.MembershipPermission,
|
||||
auth.SharePermission,
|
||||
}
|
||||
|
||||
defDomainsFilterPermissions = []string{
|
||||
auth.AdminPermission,
|
||||
auth.EditPermission,
|
||||
auth.ViewPermission,
|
||||
auth.MembershipPermission,
|
||||
auth.SharePermission,
|
||||
}
|
||||
defPlatformFilterPermissions = []string{
|
||||
auth.AdminPermission,
|
||||
auth.MembershipPermission,
|
||||
}
|
||||
)
|
||||
|
||||
type grpcServer struct {
|
||||
magistrala.UnimplementedAuthServiceServer
|
||||
issue kitgrpc.Handler
|
||||
refresh kitgrpc.Handler
|
||||
identify kitgrpc.Handler
|
||||
authorize kitgrpc.Handler
|
||||
addPolicy kitgrpc.Handler
|
||||
addPolicies kitgrpc.Handler
|
||||
deletePolicy kitgrpc.Handler
|
||||
deletePolicies kitgrpc.Handler
|
||||
listObjects kitgrpc.Handler
|
||||
listAllObjects kitgrpc.Handler
|
||||
countObjects kitgrpc.Handler
|
||||
listSubjects kitgrpc.Handler
|
||||
listAllSubjects kitgrpc.Handler
|
||||
countSubjects kitgrpc.Handler
|
||||
listPermissions kitgrpc.Handler
|
||||
}
|
||||
|
||||
// NewServer returns new AuthServiceServer instance.
|
||||
func NewServer(svc auth.Service) magistrala.AuthServiceServer {
|
||||
return &grpcServer{
|
||||
issue: kitgrpc.NewServer(
|
||||
(issueEndpoint(svc)),
|
||||
decodeIssueRequest,
|
||||
encodeIssueResponse,
|
||||
),
|
||||
refresh: kitgrpc.NewServer(
|
||||
(refreshEndpoint(svc)),
|
||||
decodeRefreshRequest,
|
||||
encodeIssueResponse,
|
||||
),
|
||||
identify: kitgrpc.NewServer(
|
||||
(identifyEndpoint(svc)),
|
||||
decodeIdentifyRequest,
|
||||
encodeIdentifyResponse,
|
||||
),
|
||||
authorize: kitgrpc.NewServer(
|
||||
(authorizeEndpoint(svc)),
|
||||
decodeAuthorizeRequest,
|
||||
encodeAuthorizeResponse,
|
||||
),
|
||||
addPolicy: kitgrpc.NewServer(
|
||||
(addPolicyEndpoint(svc)),
|
||||
decodeAddPolicyRequest,
|
||||
encodeAddPolicyResponse,
|
||||
),
|
||||
addPolicies: kitgrpc.NewServer(
|
||||
(addPoliciesEndpoint(svc)),
|
||||
decodeAddPoliciesRequest,
|
||||
encodeAddPoliciesResponse,
|
||||
),
|
||||
deletePolicy: kitgrpc.NewServer(
|
||||
(deletePolicyEndpoint(svc)),
|
||||
decodeDeletePolicyRequest,
|
||||
encodeDeletePolicyResponse,
|
||||
),
|
||||
deletePolicies: kitgrpc.NewServer(
|
||||
(deletePoliciesEndpoint(svc)),
|
||||
decodeDeletePoliciesRequest,
|
||||
encodeDeletePoliciesResponse,
|
||||
),
|
||||
listObjects: kitgrpc.NewServer(
|
||||
(listObjectsEndpoint(svc)),
|
||||
decodeListObjectsRequest,
|
||||
encodeListObjectsResponse,
|
||||
),
|
||||
listAllObjects: kitgrpc.NewServer(
|
||||
(listAllObjectsEndpoint(svc)),
|
||||
decodeListObjectsRequest,
|
||||
encodeListObjectsResponse,
|
||||
),
|
||||
countObjects: kitgrpc.NewServer(
|
||||
(countObjectsEndpoint(svc)),
|
||||
decodeCountObjectsRequest,
|
||||
encodeCountObjectsResponse,
|
||||
),
|
||||
listSubjects: kitgrpc.NewServer(
|
||||
(listSubjectsEndpoint(svc)),
|
||||
decodeListSubjectsRequest,
|
||||
encodeListSubjectsResponse,
|
||||
),
|
||||
listAllSubjects: kitgrpc.NewServer(
|
||||
(listAllSubjectsEndpoint(svc)),
|
||||
decodeListSubjectsRequest,
|
||||
encodeListSubjectsResponse,
|
||||
),
|
||||
countSubjects: kitgrpc.NewServer(
|
||||
(countSubjectsEndpoint(svc)),
|
||||
decodeCountSubjectsRequest,
|
||||
encodeCountSubjectsResponse,
|
||||
),
|
||||
listPermissions: kitgrpc.NewServer(
|
||||
(listPermissionsEndpoint(svc)),
|
||||
decodeListPermissionsRequest,
|
||||
encodeListPermissionsResponse,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *grpcServer) Issue(ctx context.Context, req *magistrala.IssueReq) (*magistrala.Token, error) {
|
||||
_, res, err := s.issue.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, encodeError(err)
|
||||
}
|
||||
return res.(*magistrala.Token), nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) Refresh(ctx context.Context, req *magistrala.RefreshReq) (*magistrala.Token, error) {
|
||||
_, res, err := s.refresh.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, encodeError(err)
|
||||
}
|
||||
return res.(*magistrala.Token), nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) Identify(ctx context.Context, token *magistrala.IdentityReq) (*magistrala.IdentityRes, error) {
|
||||
_, res, err := s.identify.ServeGRPC(ctx, token)
|
||||
if err != nil {
|
||||
return nil, encodeError(err)
|
||||
}
|
||||
return res.(*magistrala.IdentityRes), nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) Authorize(ctx context.Context, req *magistrala.AuthorizeReq) (*magistrala.AuthorizeRes, error) {
|
||||
_, res, err := s.authorize.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, encodeError(err)
|
||||
}
|
||||
return res.(*magistrala.AuthorizeRes), nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) AddPolicy(ctx context.Context, req *magistrala.AddPolicyReq) (*magistrala.AddPolicyRes, error) {
|
||||
_, res, err := s.addPolicy.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, encodeError(err)
|
||||
}
|
||||
return res.(*magistrala.AddPolicyRes), nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) AddPolicies(ctx context.Context, req *magistrala.AddPoliciesReq) (*magistrala.AddPoliciesRes, error) {
|
||||
_, res, err := s.addPolicies.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, encodeError(err)
|
||||
}
|
||||
return res.(*magistrala.AddPoliciesRes), nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) DeletePolicy(ctx context.Context, req *magistrala.DeletePolicyReq) (*magistrala.DeletePolicyRes, error) {
|
||||
_, res, err := s.deletePolicy.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, encodeError(err)
|
||||
}
|
||||
return res.(*magistrala.DeletePolicyRes), nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) DeletePolicies(ctx context.Context, req *magistrala.DeletePoliciesReq) (*magistrala.DeletePoliciesRes, error) {
|
||||
_, res, err := s.deletePolicies.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, encodeError(err)
|
||||
}
|
||||
return res.(*magistrala.DeletePoliciesRes), nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) ListObjects(ctx context.Context, req *magistrala.ListObjectsReq) (*magistrala.ListObjectsRes, error) {
|
||||
_, res, err := s.listObjects.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, encodeError(err)
|
||||
}
|
||||
return res.(*magistrala.ListObjectsRes), nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) ListAllObjects(ctx context.Context, req *magistrala.ListObjectsReq) (*magistrala.ListObjectsRes, error) {
|
||||
_, res, err := s.listAllObjects.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, encodeError(err)
|
||||
}
|
||||
return res.(*magistrala.ListObjectsRes), nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) CountObjects(ctx context.Context, req *magistrala.CountObjectsReq) (*magistrala.CountObjectsRes, error) {
|
||||
_, res, err := s.countObjects.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, encodeError(err)
|
||||
}
|
||||
return res.(*magistrala.CountObjectsRes), nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) ListSubjects(ctx context.Context, req *magistrala.ListSubjectsReq) (*magistrala.ListSubjectsRes, error) {
|
||||
_, res, err := s.listSubjects.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, encodeError(err)
|
||||
}
|
||||
return res.(*magistrala.ListSubjectsRes), nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) ListAllSubjects(ctx context.Context, req *magistrala.ListSubjectsReq) (*magistrala.ListSubjectsRes, error) {
|
||||
_, res, err := s.listAllSubjects.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, encodeError(err)
|
||||
}
|
||||
return res.(*magistrala.ListSubjectsRes), nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) CountSubjects(ctx context.Context, req *magistrala.CountSubjectsReq) (*magistrala.CountSubjectsRes, error) {
|
||||
_, res, err := s.countSubjects.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, encodeError(err)
|
||||
}
|
||||
return res.(*magistrala.CountSubjectsRes), nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) ListPermissions(ctx context.Context, req *magistrala.ListPermissionsReq) (*magistrala.ListPermissionsRes, error) {
|
||||
_, res, err := s.listPermissions.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, encodeError(err)
|
||||
}
|
||||
return res.(*magistrala.ListPermissionsRes), nil
|
||||
}
|
||||
|
||||
func decodeIssueRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*magistrala.IssueReq)
|
||||
return issueReq{userID: req.GetUserId(), domainID: req.GetDomainId(), keyType: auth.KeyType(req.GetType())}, nil
|
||||
}
|
||||
|
||||
func decodeRefreshRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*magistrala.RefreshReq)
|
||||
return refreshReq{refreshToken: req.GetRefreshToken(), domainID: req.GetDomainId()}, nil
|
||||
}
|
||||
|
||||
func encodeIssueResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(issueRes)
|
||||
|
||||
return &magistrala.Token{
|
||||
AccessToken: res.accessToken,
|
||||
RefreshToken: &res.refreshToken,
|
||||
AccessType: res.accessType,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func decodeIdentifyRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*magistrala.IdentityReq)
|
||||
return identityReq{token: req.GetToken()}, nil
|
||||
}
|
||||
|
||||
func encodeIdentifyResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(identityRes)
|
||||
return &magistrala.IdentityRes{Id: res.id, UserId: res.userID, DomainId: res.domainID}, nil
|
||||
}
|
||||
|
||||
func decodeAuthorizeRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*magistrala.AuthorizeReq)
|
||||
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
|
||||
}
|
||||
|
||||
func encodeAuthorizeResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(authorizeRes)
|
||||
return &magistrala.AuthorizeRes{Authorized: res.authorized, Id: res.id}, nil
|
||||
}
|
||||
|
||||
func decodeAddPolicyRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*magistrala.AddPolicyReq)
|
||||
return policyReq{
|
||||
Domain: req.GetDomain(),
|
||||
SubjectType: req.GetSubjectType(),
|
||||
SubjectKind: req.GetSubjectKind(),
|
||||
Subject: req.GetSubject(),
|
||||
Relation: req.GetRelation(),
|
||||
Permission: req.GetPermission(),
|
||||
ObjectType: req.GetObjectType(),
|
||||
ObjectKind: req.GetObjectKind(),
|
||||
Object: req.GetObject(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func encodeAddPolicyResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(addPolicyRes)
|
||||
return &magistrala.AddPolicyRes{Added: res.added}, nil
|
||||
}
|
||||
|
||||
func decodeAddPoliciesRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
reqs := grpcReq.(*magistrala.AddPoliciesReq)
|
||||
r := policiesReq{}
|
||||
for _, req := range reqs.AddPoliciesReq {
|
||||
r = append(r, policyReq{
|
||||
Domain: req.GetDomain(),
|
||||
SubjectType: req.GetSubjectType(),
|
||||
SubjectKind: req.GetSubjectKind(),
|
||||
Subject: req.GetSubject(),
|
||||
Relation: req.GetRelation(),
|
||||
Permission: req.GetPermission(),
|
||||
ObjectType: req.GetObjectType(),
|
||||
ObjectKind: req.GetObjectKind(),
|
||||
Object: req.GetObject(),
|
||||
})
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func encodeAddPoliciesResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(addPoliciesRes)
|
||||
return &magistrala.AddPoliciesRes{Added: res.added}, nil
|
||||
}
|
||||
|
||||
func decodeDeletePolicyRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*magistrala.DeletePolicyReq)
|
||||
return policyReq{
|
||||
Domain: req.GetDomain(),
|
||||
SubjectType: req.GetSubjectType(),
|
||||
SubjectKind: req.GetSubjectKind(),
|
||||
Subject: req.GetSubject(),
|
||||
Relation: req.GetRelation(),
|
||||
Permission: req.GetPermission(),
|
||||
ObjectType: req.GetObjectType(),
|
||||
ObjectKind: req.GetObjectKind(),
|
||||
Object: req.GetObject(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func encodeDeletePolicyResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(deletePolicyRes)
|
||||
return &magistrala.DeletePolicyRes{Deleted: res.deleted}, nil
|
||||
}
|
||||
|
||||
func decodeDeletePoliciesRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
reqs := grpcReq.(*magistrala.DeletePoliciesReq)
|
||||
r := policiesReq{}
|
||||
for _, req := range reqs.DeletePoliciesReq {
|
||||
r = append(r, policyReq{
|
||||
Domain: req.GetDomain(),
|
||||
SubjectType: req.GetSubjectType(),
|
||||
SubjectKind: req.GetSubjectKind(),
|
||||
Subject: req.GetSubject(),
|
||||
Relation: req.GetRelation(),
|
||||
Permission: req.GetPermission(),
|
||||
ObjectType: req.GetObjectType(),
|
||||
ObjectKind: req.GetObjectKind(),
|
||||
Object: req.GetObject(),
|
||||
})
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func encodeDeletePoliciesResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(deletePoliciesRes)
|
||||
return &magistrala.DeletePoliciesRes{Deleted: res.deleted}, nil
|
||||
}
|
||||
|
||||
func decodeListObjectsRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*magistrala.ListObjectsReq)
|
||||
return listObjectsReq{
|
||||
Domain: req.GetDomain(),
|
||||
SubjectType: req.GetSubjectType(),
|
||||
Subject: req.GetSubject(),
|
||||
Relation: req.GetRelation(),
|
||||
Permission: req.GetPermission(),
|
||||
ObjectType: req.GetObjectType(),
|
||||
Object: req.GetObject(),
|
||||
NextPageToken: req.GetNextPageToken(),
|
||||
Limit: req.GetLimit(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func encodeListObjectsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(listObjectsRes)
|
||||
return &magistrala.ListObjectsRes{Policies: res.policies}, nil
|
||||
}
|
||||
|
||||
func decodeCountObjectsRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*magistrala.CountObjectsReq)
|
||||
return countObjectsReq{
|
||||
Domain: req.GetDomain(),
|
||||
SubjectType: req.GetSubjectType(),
|
||||
Subject: req.GetSubject(),
|
||||
Relation: req.GetRelation(),
|
||||
Permission: req.GetPermission(),
|
||||
ObjectType: req.GetObjectType(),
|
||||
Object: req.GetObject(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func encodeCountObjectsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(countObjectsRes)
|
||||
return &magistrala.CountObjectsRes{Count: int64(res.count)}, nil
|
||||
}
|
||||
|
||||
func decodeListSubjectsRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*magistrala.ListSubjectsReq)
|
||||
return listSubjectsReq{
|
||||
Domain: req.GetDomain(),
|
||||
SubjectType: req.GetSubjectType(),
|
||||
Subject: req.GetSubject(),
|
||||
Relation: req.GetRelation(),
|
||||
Permission: req.GetPermission(),
|
||||
ObjectType: req.GetObjectType(),
|
||||
Object: req.GetObject(), NextPageToken: req.GetNextPageToken(), Limit: req.GetLimit(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func encodeListSubjectsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(listSubjectsRes)
|
||||
return &magistrala.ListSubjectsRes{Policies: res.policies}, nil
|
||||
}
|
||||
|
||||
func decodeCountSubjectsRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*magistrala.CountSubjectsReq)
|
||||
return countSubjectsReq{
|
||||
Domain: req.GetDomain(),
|
||||
SubjectType: req.GetSubjectType(),
|
||||
Subject: req.GetSubject(),
|
||||
Relation: req.GetRelation(),
|
||||
Permission: req.GetPermission(),
|
||||
ObjectType: req.GetObjectType(),
|
||||
Object: req.GetObject(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func encodeCountSubjectsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(countSubjectsRes)
|
||||
return &magistrala.CountSubjectsRes{Count: int64(res.count)}, nil
|
||||
}
|
||||
|
||||
func decodeListPermissionsRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*magistrala.ListPermissionsReq)
|
||||
var fp []string
|
||||
|
||||
switch req.GetObjectType() {
|
||||
case auth.ThingType:
|
||||
fp = defThingsFilterPermissions
|
||||
case auth.GroupType:
|
||||
fp = defGroupsFilterPermissions
|
||||
case auth.PlatformType:
|
||||
fp = defPlatformFilterPermissions
|
||||
case auth.DomainType:
|
||||
fp = defDomainsFilterPermissions
|
||||
default:
|
||||
return nil, apiutil.ErrMalformedPolicy
|
||||
}
|
||||
if len(req.GetFilterPermissions()) > 0 {
|
||||
fp = req.GetFilterPermissions()
|
||||
}
|
||||
return listPermissionsReq{
|
||||
Domain: req.GetDomain(),
|
||||
SubjectType: req.GetSubjectType(),
|
||||
Subject: req.GetSubject(),
|
||||
SubjectRelation: req.GetSubjectRelation(),
|
||||
ObjectType: req.GetObjectType(),
|
||||
Object: req.GetObject(),
|
||||
FilterPermissions: fp,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func encodeListPermissionsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(listPermissionsRes)
|
||||
return &magistrala.ListPermissionsRes{
|
||||
Domain: res.Domain,
|
||||
SubjectType: res.SubjectType,
|
||||
Subject: res.Subject,
|
||||
SubjectRelation: res.SubjectRelation,
|
||||
ObjectType: res.ObjectType,
|
||||
Object: res.Object,
|
||||
Permissions: res.Permissions,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func encodeError(err error) error {
|
||||
switch {
|
||||
case errors.Contains(err, nil):
|
||||
return nil
|
||||
case errors.Contains(err, errors.ErrMalformedEntity),
|
||||
errors.Contains(err, svcerr.ErrInvalidPolicy),
|
||||
err == apiutil.ErrInvalidAuthKey,
|
||||
err == apiutil.ErrMissingID,
|
||||
err == apiutil.ErrMissingMemberType,
|
||||
err == apiutil.ErrMissingPolicySub,
|
||||
err == apiutil.ErrMissingPolicyObj,
|
||||
err == apiutil.ErrMalformedPolicyAct:
|
||||
return status.Error(codes.InvalidArgument, err.Error())
|
||||
case errors.Contains(err, errors.ErrAuthentication),
|
||||
errors.Contains(err, svcerr.ErrAuthentication),
|
||||
errors.Contains(err, auth.ErrKeyExpired),
|
||||
err == apiutil.ErrMissingEmail,
|
||||
err == apiutil.ErrBearerToken:
|
||||
return status.Error(codes.Unauthenticated, err.Error())
|
||||
case errors.Contains(err, errors.ErrAuthorization),
|
||||
errors.Contains(err, svcerr.ErrAuthorization),
|
||||
errors.Contains(err, errors.ErrDomainAuthorization):
|
||||
return status.Error(codes.PermissionDenied, err.Error())
|
||||
case errors.Contains(err, errors.ErrNotFound):
|
||||
return status.Error(codes.NotFound, err.Error())
|
||||
case errors.Contains(err, errors.ErrConflict):
|
||||
return status.Error(codes.AlreadyExists, err.Error())
|
||||
default:
|
||||
return status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package token
|
||||
|
||||
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"
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
kitgrpc "github.com/go-kit/kit/transport/grpc"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
const tokenSvcName = "token.v1.TokenService"
|
||||
|
||||
type tokenGrpcClient struct {
|
||||
issue endpoint.Endpoint
|
||||
refresh endpoint.Endpoint
|
||||
revoke endpoint.Endpoint
|
||||
listUserRefreshTokens endpoint.Endpoint
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
var _ grpcTokenV1.TokenServiceClient = (*tokenGrpcClient)(nil)
|
||||
|
||||
// NewTokenClient returns new token gRPC client instance.
|
||||
func NewTokenClient(conn *grpc.ClientConn, timeout time.Duration) grpcTokenV1.TokenServiceClient {
|
||||
return &tokenGrpcClient{
|
||||
issue: kitgrpc.NewClient(
|
||||
conn,
|
||||
tokenSvcName,
|
||||
"Issue",
|
||||
encodeIssueRequest,
|
||||
decodeIssueResponse,
|
||||
grpcTokenV1.Token{},
|
||||
).Endpoint(),
|
||||
refresh: kitgrpc.NewClient(
|
||||
conn,
|
||||
tokenSvcName,
|
||||
"Refresh",
|
||||
encodeRefreshRequest,
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
func (client tokenGrpcClient) Issue(ctx context.Context, req *grpcTokenV1.IssueReq, _ ...grpc.CallOption) (*grpcTokenV1.Token, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := client.issue(ctx, issueReq{
|
||||
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)
|
||||
}
|
||||
return res.(*grpcTokenV1.Token), nil
|
||||
}
|
||||
|
||||
func encodeIssueRequest(_ context.Context, grpcReq any) (any, error) {
|
||||
req := grpcReq.(issueReq)
|
||||
return &grpcTokenV1.IssueReq{
|
||||
UserId: req.userID,
|
||||
UserRole: uint32(req.userRole),
|
||||
Type: uint32(req.keyType),
|
||||
Verified: req.verified,
|
||||
Description: req.description,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func decodeIssueResponse(_ context.Context, grpcRes any) (any, error) {
|
||||
return grpcRes, nil
|
||||
}
|
||||
|
||||
func (client tokenGrpcClient) Refresh(ctx context.Context, req *grpcTokenV1.RefreshReq, _ ...grpc.CallOption) (*grpcTokenV1.Token, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
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 any) (any, error) {
|
||||
req := grpcReq.(refreshReq)
|
||||
return &grpcTokenV1.RefreshReq{RefreshToken: req.refreshToken, Verified: req.verified}, nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package grpc contains implementation of Auth service gRPC API.
|
||||
package token
|
||||
@@ -0,0 +1,90 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package token
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/absmach/supermq/auth"
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
)
|
||||
|
||||
func issueEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
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,
|
||||
Verified: req.verified,
|
||||
Description: req.description,
|
||||
}
|
||||
tkn, err := svc.Issue(ctx, "", key)
|
||||
if err != nil {
|
||||
return issueRes{}, err
|
||||
}
|
||||
ret := issueRes{
|
||||
accessToken: tkn.AccessToken,
|
||||
refreshToken: tkn.RefreshToken,
|
||||
accessType: tkn.AccessType,
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
}
|
||||
|
||||
func refreshEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
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, Verified: req.verified}
|
||||
tkn, err := svc.Issue(ctx, req.refreshToken, key)
|
||||
if err != nil {
|
||||
return issueRes{}, err
|
||||
}
|
||||
ret := issueRes{
|
||||
accessToken: tkn.AccessToken,
|
||||
refreshToken: tkn.RefreshToken,
|
||||
accessType: tkn.AccessType,
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
// 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
|
||||
validToken = "valid"
|
||||
inValidToken = "invalid"
|
||||
invalidID = "invalid"
|
||||
)
|
||||
|
||||
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()))
|
||||
assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err))
|
||||
grpcClient := grpcapi.NewTokenClient(conn, time.Second)
|
||||
defer conn.Close()
|
||||
|
||||
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()))
|
||||
assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err))
|
||||
grpcClient := grpcapi.NewTokenClient(conn, time.Second)
|
||||
defer conn.Close()
|
||||
|
||||
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).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()
|
||||
}
|
||||
}
|
||||
|
||||
func TestRevoke(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))
|
||||
grpcClient := grpcapi.NewTokenClient(conn, time.Second)
|
||||
defer conn.Close()
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "revoke token with valid id",
|
||||
id: validID,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "revoke token with invalid id",
|
||||
id: invalidID,
|
||||
err: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "revoke token with empty id",
|
||||
id: "",
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
{
|
||||
desc: "revoke already revoked token",
|
||||
id: validID,
|
||||
err: svcerr.ErrConflict,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
svcCall := svc.On("RevokeToken", mock.Anything, mock.Anything, tc.id).Return(tc.err)
|
||||
_, err := grpcClient.Revoke(context.Background(), &grpcTokenV1.RevokeReq{TokenId: tc.id})
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
svcCall.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestListUserRefreshTokens(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))
|
||||
grpcClient := grpcapi.NewTokenClient(conn, time.Second)
|
||||
defer conn.Close()
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
userID string
|
||||
listResponse []auth.TokenInfo
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "list tokens for user with valid id",
|
||||
userID: validID,
|
||||
listResponse: []auth.TokenInfo{
|
||||
{ID: testsutil.GenerateUUID(&testing.T{}), Description: "Token 1"},
|
||||
{ID: testsutil.GenerateUUID(&testing.T{}), Description: "Token 2"},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "list tokens for user with empty list",
|
||||
userID: validID,
|
||||
listResponse: []auth.TokenInfo{},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "list tokens with invalid user id",
|
||||
userID: invalidID,
|
||||
listResponse: nil,
|
||||
err: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "list tokens with empty user id",
|
||||
userID: "",
|
||||
listResponse: nil,
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
svcCall := svc.On("ListUserRefreshTokens", mock.Anything, tc.userID).Return(tc.listResponse, tc.err)
|
||||
_, err := grpcClient.ListUserRefreshTokens(context.Background(), &grpcTokenV1.ListUserRefreshTokensReq{UserId: tc.userID})
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
svcCall.Unset()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package token
|
||||
|
||||
import (
|
||||
apiutil "github.com/absmach/supermq/api/http/util"
|
||||
"github.com/absmach/supermq/auth"
|
||||
)
|
||||
|
||||
type issueReq struct {
|
||||
userID string
|
||||
userRole auth.Role
|
||||
keyType auth.KeyType
|
||||
verified bool
|
||||
description string
|
||||
}
|
||||
|
||||
func (req issueReq) validate() error {
|
||||
if req.keyType != auth.AccessKey &&
|
||||
req.keyType != auth.APIKey &&
|
||||
req.keyType != auth.RecoveryKey &&
|
||||
req.keyType != auth.InvitationKey {
|
||||
return apiutil.ErrInvalidAuthKey
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type refreshReq struct {
|
||||
refreshToken string
|
||||
verified bool
|
||||
}
|
||||
|
||||
func (req refreshReq) validate() error {
|
||||
if req.refreshToken == "" {
|
||||
return apiutil.ErrMissingSecret
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package token
|
||||
|
||||
import "github.com/absmach/supermq/auth"
|
||||
|
||||
type issueRes struct {
|
||||
accessToken string
|
||||
refreshToken string
|
||||
accessType string
|
||||
}
|
||||
|
||||
type listUserRefreshTokensRes struct {
|
||||
refreshTokens []auth.TokenInfo
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user