mirror of
https://github.com/Infisical/infisical.git
synced 2025-07-05 04:29:09 +00:00
Compare commits
713 Commits
api-refere
...
infisical/
Author | SHA1 | Date | |
---|---|---|---|
a91b6ebc03 | |||
e68d1d06a8 | |||
8f754d659a | |||
bef28fea2d | |||
28f15de8df | |||
66d258f02b | |||
d13eafcef7 | |||
6db47499de | |||
1cefb036e0 | |||
af77ad8b2f | |||
dd0f9f5216 | |||
29df6f067e | |||
4dc9a3692e | |||
49bb2121b9 | |||
07679d9318 | |||
fb271726fe | |||
f9e7d4ddd2 | |||
442c454932 | |||
8b22ee1fac | |||
8a10dc8983 | |||
d57920706a | |||
425611b409 | |||
b20489982d | |||
4b569ee4b4 | |||
af9661b221 | |||
53f16f01b8 | |||
f519d1cffc | |||
b8b28d2710 | |||
deab700716 | |||
4d184003a8 | |||
9849312317 | |||
79454a6aea | |||
8e0fb9fe9b | |||
a729114376 | |||
0c20cb0f91 | |||
d1597ed8da | |||
6cee8dc7e5 | |||
13040439c3 | |||
9a4f294749 | |||
2436a572f0 | |||
7cd21e3a93 | |||
e28416b50b | |||
9677836b76 | |||
ca858f8e13 | |||
c2beff493f | |||
34fafd815c | |||
c05ebbb864 | |||
372f2be2f3 | |||
23e621f557 | |||
464b80140f | |||
01cd496afe | |||
6094940a8b | |||
30b959babb | |||
cec14efe86 | |||
b3f090d87e | |||
1deb6827cf | |||
24dbf11962 | |||
20fb3906aa | |||
e7e2ca0f45 | |||
caabf2c952 | |||
35eade0206 | |||
6d1b79430d | |||
7864524944 | |||
adc90e91fe | |||
db7db0cc04 | |||
aa4d9ad267 | |||
27fd857120 | |||
205e46571a | |||
70a6a7cfa1 | |||
558315c24b | |||
a2bd808196 | |||
cfb0d4ee96 | |||
15fc4fd609 | |||
83bff9ae14 | |||
86ba6355cf | |||
6b427adfe0 | |||
01f711ad19 | |||
fa572f7ee0 | |||
249edf98e9 | |||
753a4daf69 | |||
b9320ed9bd | |||
8eace5528f | |||
9407c16e83 | |||
dcdcc40a4a | |||
edd78eaeba | |||
c21ea6fb75 | |||
a60dbe523b | |||
bb9a6b4272 | |||
eaca1b694a | |||
0afb44af29 | |||
3b39e38c89 | |||
4189d1028d | |||
f227824fb8 | |||
49d6918297 | |||
00212f1c72 | |||
987f0c9081 | |||
e4f00f74e9 | |||
ce580f417e | |||
c1662d6db5 | |||
2dae59c6be | |||
9bd764e535 | |||
e4f32f092a | |||
e02c082c7a | |||
80b6c4ad94 | |||
42eb01e1e2 | |||
b8157122e6 | |||
4f66749430 | |||
bfe5ee672b | |||
32a1a0a9e5 | |||
f7e1da65d5 | |||
6bf9bc1d2c | |||
59c747cf72 | |||
b04030a060 | |||
e8fd693da3 | |||
6c2803da93 | |||
4031f4a559 | |||
8ab89bc420 | |||
e46e87d758 | |||
9c2ef15314 | |||
3213dafba9 | |||
33c3c5ecc5 | |||
627c8711dc | |||
8d3d4f222f | |||
65d3038414 | |||
6b7b888fb4 | |||
bf059e0fe5 | |||
28fdf4ed4b | |||
2606e42079 | |||
b1285b401b | |||
3afafbb885 | |||
257547ff4d | |||
da4ae3c503 | |||
fb79e9e6fb | |||
5373cb6afb | |||
31c0bf6831 | |||
67618046c0 | |||
df642179ba | |||
c7d0f2325c | |||
bb6d482ff9 | |||
4f619d7e48 | |||
295c1e5d4a | |||
0be3ad9517 | |||
606ed25104 | |||
c880a48749 | |||
92f7b45e01 | |||
5fe8bdc00b | |||
9f813d72f2 | |||
d90fdac5ce | |||
87709dc86f | |||
deb8e74749 | |||
3519412639 | |||
0506389ada | |||
dd7c449483 | |||
c7572a3374 | |||
fe416556f2 | |||
20fb99f042 | |||
daa94db874 | |||
850e7bff98 | |||
bfaf87c4c2 | |||
55f1392faf | |||
0bf658e501 | |||
aed94ff5bb | |||
0d3f09d668 | |||
16f0ac6d43 | |||
6e6a1c87f2 | |||
b5aa6c0000 | |||
784cdb4201 | |||
17e61bfc68 | |||
a6a60b7bbb | |||
d154f68a59 | |||
f5159583ae | |||
771bec6d6d | |||
010963a80c | |||
0e1191f2ea | |||
8a6ab7f2f6 | |||
4f3582a98b | |||
498a90c484 | |||
76e5d61da5 | |||
53bb3bc610 | |||
1df7b88abf | |||
3670b16657 | |||
9a4b2f7d81 | |||
fadb36edb8 | |||
fbe5a1adb0 | |||
d0695a8998 | |||
a19e8ad016 | |||
15b57de0ed | |||
aaba4a0895 | |||
f3b37de3f3 | |||
fcfd6b3fb2 | |||
05205d1eff | |||
2243bcb3a4 | |||
356e981401 | |||
5b41fb0ff5 | |||
8893aec213 | |||
c4cb8f8008 | |||
046557c97f | |||
a15ba28c18 | |||
8386f4dcbd | |||
ada0fd9c5b | |||
6376c29e49 | |||
402692614e | |||
34de6d4e29 | |||
829e906650 | |||
b7cbb0f1a8 | |||
a50ffbb59d | |||
48eda0c684 | |||
ed89413689 | |||
0c94f77a6d | |||
e6068826f8 | |||
cfa0a2044e | |||
134b503c28 | |||
efcbf1aa88 | |||
284c18db07 | |||
1410a44610 | |||
746ffb3840 | |||
f9f12eafdf | |||
11470a5a0e | |||
9fe2190115 | |||
9e2bd31833 | |||
e88b0ad3c4 | |||
74644fd8bb | |||
2069ac1554 | |||
5a2516e0a7 | |||
b52bc3bed7 | |||
4a153e5658 | |||
7324822be5 | |||
766f301aea | |||
8fbc930012 | |||
0e5190a920 | |||
b815e3eb56 | |||
31231cfcca | |||
ee772e4a77 | |||
7bc29c5981 | |||
e9a89930da | |||
b85499859c | |||
7f17194c0f | |||
1e1ad450d2 | |||
5287b322d8 | |||
45d96be1ff | |||
12840bfdbd | |||
fef5369738 | |||
c94b7d63f6 | |||
485ddc5c50 | |||
edd9c66e49 | |||
0a3b85534b | |||
ec2cc5162e | |||
7ce472957c | |||
8529e0da3d | |||
e5a5433f10 | |||
ee6e518ff8 | |||
15a7222505 | |||
25d482cc62 | |||
785a2bec6a | |||
449466f326 | |||
4131e9c3f1 | |||
310595256f | |||
1737880e58 | |||
b72483f5f2 | |||
ee14bda706 | |||
e56463d52b | |||
ebd3d7c7c4 | |||
9ecbfe201b | |||
ba2a03897f | |||
304f14c0ed | |||
51e5c25e16 | |||
0f6490b1e7 | |||
f894e48fcb | |||
37cfa22619 | |||
94557344b7 | |||
d5063018eb | |||
51d68505d3 | |||
ade27ad072 | |||
683c512bce | |||
43ff28b5fb | |||
ce41855e84 | |||
d24461b17c | |||
1797e56f9f | |||
74f3ca5356 | |||
db27beaf0b | |||
d6e55f51f2 | |||
e9b5996567 | |||
094fe73917 | |||
dc3f85e92e | |||
c463256058 | |||
8df22302fd | |||
f37fa2bbf5 | |||
597c9d6f2a | |||
24d2eea930 | |||
382cb910af | |||
6725475575 | |||
026864951b | |||
287ed05ab7 | |||
37b036e614 | |||
024914c168 | |||
19e8b6d37b | |||
b6d648f1f3 | |||
a514a62a29 | |||
2f24956651 | |||
13d058025c | |||
8ccaa7f29b | |||
b83964051c | |||
0a2b078bdc | |||
40d16fa996 | |||
a3739cfe50 | |||
a73623258e | |||
6da39f41a6 | |||
69bbbfcfd8 | |||
c9d58ec77d | |||
cb364186d8 | |||
918afe05b6 | |||
e822820151 | |||
b5ac49eefe | |||
b21d1a0ed2 | |||
70f1122362 | |||
ea03db8a2c | |||
38d9abca17 | |||
5bed2580c3 | |||
d0b899897b | |||
1861dc85de | |||
bc6bf33674 | |||
44fd35baf5 | |||
8ddfee4c36 | |||
4d0bff4377 | |||
c7b2489d0b | |||
68eb0f8dd9 | |||
5941e8e836 | |||
80e50d13ec | |||
99c8dda4e1 | |||
14c8e3fa3b | |||
7aa3cb53a2 | |||
567309e848 | |||
f264340903 | |||
51b788cc5b | |||
8e0f424249 | |||
f3767d3963 | |||
51cbfdbc46 | |||
f5a580eb72 | |||
460ebf3296 | |||
7f7f11c970 | |||
f799e224a0 | |||
8a87277fe6 | |||
32805c726a | |||
6c4a6d31e4 | |||
e7b89b645f | |||
b60cf2eb07 | |||
cf5a79995f | |||
c51f09fd3a | |||
f9444c5205 | |||
7dd0943b2d | |||
31a9f032b3 | |||
9c55d1906d | |||
ff54a20ace | |||
8bf7eba07b | |||
bb75ea550a | |||
344f7276d2 | |||
c375662411 | |||
cc4ad1df4b | |||
c92c0f7288 | |||
fbe0cf006f | |||
d2f959558e | |||
e50c89e326 | |||
6cda14328b | |||
b551ee50e7 | |||
93aeacc6b6 | |||
f940f8b79d | |||
72ac2c04b8 | |||
bb3d591f21 | |||
763ce1b206 | |||
1f97ac5192 | |||
5f29562fad | |||
f3e8ef1537 | |||
544d37bbc4 | |||
4f6adb50d1 | |||
444ce9508d | |||
aabd896c37 | |||
50ef23e8a0 | |||
b87f51a044 | |||
1233d9c1a0 | |||
ff0b4d7f2b | |||
ef61bc6a40 | |||
13ee8c4e13 | |||
6ea9fc7134 | |||
00e1742a30 | |||
5055b5402c | |||
ff9418c0c7 | |||
d03921eef3 | |||
602afdefc3 | |||
5eb505326b | |||
fcf4153d87 | |||
097282c5e1 | |||
0eeef9a66c | |||
df0bec8a68 | |||
13014b5345 | |||
66d0cae066 | |||
8e82222fc5 | |||
f822bcd10f | |||
89d0c0e3c3 | |||
a4f6b828ad | |||
0fb2056b8b | |||
c51f8c5838 | |||
ec5cf97f18 | |||
69b57817d6 | |||
aafbe40c02 | |||
9d9b83f909 | |||
ea1f144b54 | |||
591f33ffbe | |||
855158d0bb | |||
87e997e7a0 | |||
3c449214d1 | |||
d813f0716f | |||
6787c0eaaa | |||
377a79f17d | |||
c91f6521c1 | |||
0ebd1d3d81 | |||
d257a449bb | |||
6a744c96e5 | |||
2a768a7bc4 | |||
28b617fd89 | |||
8b1eaad7b5 | |||
c917cf8a18 | |||
282830e7a2 | |||
3d6f04b94e | |||
60a5092947 | |||
69dae1f0b2 | |||
4b41664fa4 | |||
735cf093f0 | |||
98906f190c | |||
5f80e2f432 | |||
afd6a7736a | |||
057fcb164d | |||
b575c0e207 | |||
372afa2111 | |||
6557d7668e | |||
33017b50f0 | |||
f5de501348 | |||
758c3a2423 | |||
d01c6e4df9 | |||
ed94d218fd | |||
adc7be2e84 | |||
697485f8ed | |||
19e2523d0e | |||
8851987ac4 | |||
64d862ebe9 | |||
70d1cc0e06 | |||
aee91a9558 | |||
d6218eaa82 | |||
8886e57d4f | |||
6efb58da1a | |||
f187cc2c26 | |||
d5c5495475 | |||
8e33692cda | |||
6c31e70f4f | |||
d7026cbbfa | |||
df0e0bf988 | |||
640366a0ec | |||
ab5514fcf7 | |||
c8951f347b | |||
d76f556464 | |||
6ccaa24e59 | |||
4ec0c9cdbf | |||
75cd3bfa35 | |||
1db7d50a09 | |||
b4980b4a53 | |||
1351ba936f | |||
57bccaefba | |||
86af452888 | |||
6cef7532da | |||
74e33144a7 | |||
a9776eaeb5 | |||
3c2a66f722 | |||
d92b1d3cd8 | |||
f560242f1d | |||
33fc968055 | |||
f289b99cf1 | |||
019b477d2d | |||
9ad2d9d218 | |||
a575530ddf | |||
33ea019d70 | |||
5ae3b66e2e | |||
20210d7471 | |||
77e3d10a64 | |||
814b71052d | |||
6579b3c93f | |||
99c41bb63b | |||
63df0dba64 | |||
4e050cfe7a | |||
32f5c96dd2 | |||
d7262d4291 | |||
7a9221769d | |||
5e5761424a | |||
5b923c25b5 | |||
46c76e3984 | |||
b212681d09 | |||
be67b9b341 | |||
29016fbb23 | |||
0c0139ac8f | |||
180274be34 | |||
595a26a366 | |||
41c41a647f | |||
c3d2b7d3fc | |||
84e32faac9 | |||
87984a704a | |||
33e4104e98 | |||
b5d5eb87a7 | |||
bcfb14ca86 | |||
87e2844499 | |||
ae4b8ca9b2 | |||
0cff39f918 | |||
53ac05694c | |||
097a8cae89 | |||
597e1e1ca8 | |||
4757ceb938 | |||
e3d536ef58 | |||
89ae3070ce | |||
f3895b70ee | |||
3478d71e99 | |||
1f5e458b64 | |||
6f8373c977 | |||
c55a36b291 | |||
e4a04bdf0a | |||
4db9a5279f | |||
c37ff79927 | |||
98e299c2ac | |||
9d9e830d73 | |||
d909ff6a97 | |||
5301bcc91f | |||
77438f9282 | |||
122a1e32e1 | |||
9d2a08dbec | |||
87c2e417d2 | |||
341a745843 | |||
085ddb2c48 | |||
6734ce50a5 | |||
94f893017b | |||
a0dfa5eedf | |||
1fea2f1121 | |||
7fe8999432 | |||
fca5ae9172 | |||
4aacbed28b | |||
9fbf01c19e | |||
954bc0c5f1 | |||
4ac3669756 | |||
6b334b3103 | |||
3aae1b8432 | |||
e462722ec3 | |||
f58c560fc0 | |||
d035fe1008 | |||
8be0071413 | |||
c3ca992777 | |||
829f65cdb7 | |||
7785fbafbd | |||
35cff782e1 | |||
a35643bf6e | |||
85de985321 | |||
40f5bbbc07 | |||
85254ba984 | |||
4cb586996c | |||
29fa85e499 | |||
df7d8e7be9 | |||
1de5fd28a9 | |||
b3cdc4fdd2 | |||
5ee79be873 | |||
cae7e1808d | |||
131d5d7207 | |||
393cfe8953 | |||
5098c0731b | |||
c9ed5f793a | |||
50ce977c55 | |||
c29a11866e | |||
b3a468408e | |||
d1a26766ca | |||
73c8e8dc0f | |||
32882848ba | |||
5fb406884d | |||
176d92546c | |||
1063c12d25 | |||
3402acb05c | |||
db7a064961 | |||
b521d9fa3a | |||
73c7b917ab | |||
a8470d2133 | |||
ca8fff320d | |||
f9c28ab045 | |||
d4a5eb12e8 | |||
86d82737f4 | |||
abbeb67b95 | |||
c0c96d6407 | |||
58ff6a43bc | |||
079a09a3d1 | |||
a07bd5ad40 | |||
9cc99e41b8 | |||
f256493cb3 | |||
7bf2e96ad3 | |||
40238788e5 | |||
75eeda4278 | |||
c1ea441e3a | |||
8b522a3fb5 | |||
c36352f05f | |||
2de898fdbd | |||
bc68a00265 | |||
1382688e58 | |||
9248f36edb | |||
c9c40521b2 | |||
97e4338335 | |||
82e924baff | |||
2350219cc9 | |||
28d7c72390 | |||
e7321e8060 | |||
28a2aebe67 | |||
20d4f16d33 | |||
7d802b41a8 | |||
75992e5566 | |||
911aa3fd8a | |||
7622a3f518 | |||
3b0bd362c9 | |||
ad4513f926 | |||
a2c1a17222 | |||
279958d54c | |||
1be46b5e57 | |||
98d9dd256b | |||
e5eee14409 | |||
f3c76c79ee | |||
5bdb6ad6a1 | |||
c6846f8bf1 | |||
46f03f33b0 | |||
6280d7eb34 | |||
29286d2125 | |||
c9f01ce086 | |||
bc43e109eb | |||
238c43a360 | |||
040a50d599 | |||
8a1a3e9ab9 | |||
2585d50b29 | |||
4792e752c2 | |||
1d161f6c97 | |||
0d94b6deed | |||
75428bb750 | |||
d90680cc91 | |||
031c05b82d | |||
d414353258 | |||
ffc6dcdeb4 | |||
dfc74262ee | |||
59e46ef1d0 | |||
36e4cd71d3 | |||
d60b3d1598 | |||
e555a8d313 | |||
44ec88acd6 | |||
15504346cd | |||
508ed7f7d6 | |||
52bcee2785 | |||
c097e43a4e | |||
65afaa8177 | |||
01cbd4236d | |||
40a9a15709 | |||
abfc69fc75 | |||
3ea20328dc | |||
2aa46f5a65 | |||
f0ca059b17 | |||
b1369d66c2 | |||
151ba2ffc9 | |||
152feba1fa | |||
16125157f3 | |||
c0592ad904 | |||
32970e4990 | |||
7487b373fe | |||
6df678067c | |||
b97dc7f599 | |||
96db649cbc | |||
80ce695355 | |||
93a1725da6 | |||
619bbf2027 | |||
1476d06b7e | |||
fb59b02ab4 | |||
fc3db93f8b | |||
120f1cb5dd | |||
bb9b060fc0 | |||
26605638fa | |||
76758732af | |||
827d5b25c2 | |||
b32b19bcc1 | |||
69b9881cbc | |||
1084323d6d | |||
c98c45157a | |||
9a500504a4 | |||
6009dda2d2 | |||
d4e8162c41 | |||
f6ad641858 | |||
32acc370a4 | |||
ba9b1b45ae | |||
e05b26c727 | |||
4d78f4a824 | |||
47bf483c2e | |||
40e5ecfd7d | |||
0fb0744f09 | |||
e13b3f72b1 | |||
a6e02238ad | |||
ebe4f70b51 | |||
c3c7316ec0 | |||
2cd791a433 | |||
912818eec8 | |||
840eef7bce | |||
70b9d435d1 | |||
9546916aad | |||
59c861c695 | |||
2eff06cf06 | |||
a024eecf2c | |||
a2ad9e10b4 | |||
7fa4e09874 | |||
20c4e956aa | |||
4a227d05ce | |||
6f57ef03d1 | |||
257b4b0490 |
@ -3,6 +3,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- "infisical/v*.*.*"
|
- "infisical/v*.*.*"
|
||||||
|
- "!infisical/v*.*.*-postgres"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
backend-image:
|
backend-image:
|
||||||
|
57
.github/workflows/release-standalone-docker-img-postgres-offical.yml
vendored
Normal file
57
.github/workflows/release-standalone-docker-img-postgres-offical.yml
vendored
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
name: Release standalone docker image
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "infisical/v*.*.*-postgres"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
infisical-standalone:
|
||||||
|
name: Build infisical standalone image postgres
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Extract version from tag
|
||||||
|
id: extract_version
|
||||||
|
run: echo "::set-output name=version::${GITHUB_REF_NAME#infisical/}"
|
||||||
|
- name: ☁️ Checkout source
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: 📦 Install dependencies to test all dependencies
|
||||||
|
run: npm ci --only-production
|
||||||
|
working-directory: backend
|
||||||
|
- name: version output
|
||||||
|
run: |
|
||||||
|
echo "Output Value: ${{ steps.version.outputs.major }}"
|
||||||
|
echo "Output Value: ${{ steps.version.outputs.minor }}"
|
||||||
|
echo "Output Value: ${{ steps.version.outputs.patch }}"
|
||||||
|
echo "Output Value: ${{ steps.version.outputs.version }}"
|
||||||
|
echo "Output Value: ${{ steps.version.outputs.version_type }}"
|
||||||
|
echo "Output Value: ${{ steps.version.outputs.increment }}"
|
||||||
|
- name: Save commit hashes for tag
|
||||||
|
id: commit
|
||||||
|
uses: pr-mpt/actions-commit-hash@v2
|
||||||
|
- name: 🔧 Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
- name: 🐋 Login to Docker Hub
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
- name: Set up Depot CLI
|
||||||
|
uses: depot/setup-action@v1
|
||||||
|
- name: 📦 Build backend and export to Docker
|
||||||
|
uses: depot/build-push-action@v1
|
||||||
|
with:
|
||||||
|
project: 64mmf0n610
|
||||||
|
token: ${{ secrets.DEPOT_PROJECT_TOKEN }}
|
||||||
|
push: true
|
||||||
|
context: .
|
||||||
|
tags: |
|
||||||
|
# infisical/infisical:latest-postgres
|
||||||
|
infisical/infisical:${{ steps.commit.outputs.short }}
|
||||||
|
infisical/infisical:${{ steps.extract_version.outputs.version }}
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
file: Dockerfile.standalone-infisical
|
||||||
|
build-args: |
|
||||||
|
POSTHOG_API_KEY=${{ secrets.PUBLIC_POSTHOG_API_KEY }}
|
||||||
|
INFISICAL_PLATFORM_VERSION=${{ steps.extract_version.outputs.version }}
|
@ -3,6 +3,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- "infisical/v*.*.*"
|
- "infisical/v*.*.*"
|
||||||
|
- "!infisical/v*.*.*-postgres"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
infisical-standalone:
|
infisical-standalone:
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,7 @@
|
|||||||
# backend
|
# backend
|
||||||
node_modules
|
node_modules
|
||||||
.env
|
.env
|
||||||
|
.env.test
|
||||||
.env.dev
|
.env.dev
|
||||||
.env.gamma
|
.env.gamma
|
||||||
.env.prod
|
.env.prod
|
||||||
|
@ -108,7 +108,7 @@ brews:
|
|||||||
zsh_completion.install "completions/infisical.zsh" => "_infisical"
|
zsh_completion.install "completions/infisical.zsh" => "_infisical"
|
||||||
fish_completion.install "completions/infisical.fish"
|
fish_completion.install "completions/infisical.fish"
|
||||||
man1.install "manpages/infisical.1.gz"
|
man1.install "manpages/infisical.1.gz"
|
||||||
- name: 'infisical@{{.Version}}'
|
- name: "infisical@{{.Version}}"
|
||||||
tap:
|
tap:
|
||||||
owner: Infisical
|
owner: Infisical
|
||||||
name: homebrew-get-cli
|
name: homebrew-get-cli
|
||||||
@ -186,12 +186,14 @@ aurs:
|
|||||||
# man pages
|
# man pages
|
||||||
install -Dm644 "./manpages/infisical.1.gz" "${pkgdir}/usr/share/man/man1/infisical.1.gz"
|
install -Dm644 "./manpages/infisical.1.gz" "${pkgdir}/usr/share/man/man1/infisical.1.gz"
|
||||||
|
|
||||||
# dockers:
|
dockers:
|
||||||
# - dockerfile: cli/docker/Dockerfile
|
- dockerfile: docker/alpine
|
||||||
# goos: linux
|
goos: linux
|
||||||
# goarch: amd64
|
goarch: amd64
|
||||||
# ids:
|
ids:
|
||||||
# - infisical
|
- all-other-builds
|
||||||
# image_templates:
|
image_templates:
|
||||||
# - "infisical/cli:{{ .Version }}"
|
- "infisical/cli:{{ .Version }}"
|
||||||
# - "infisical/cli:latest"
|
- "infisical/cli:{{ .Major }}.{{ .Minor }}"
|
||||||
|
- "infisical/cli:{{ .Major }}"
|
||||||
|
- "infisical/cli:latest"
|
||||||
|
@ -2,7 +2,7 @@ ARG POSTHOG_HOST=https://app.posthog.com
|
|||||||
ARG POSTHOG_API_KEY=posthog-api-key
|
ARG POSTHOG_API_KEY=posthog-api-key
|
||||||
ARG INTERCOM_ID=intercom-id
|
ARG INTERCOM_ID=intercom-id
|
||||||
|
|
||||||
FROM node:16-alpine AS base
|
FROM node:20-alpine AS base
|
||||||
|
|
||||||
FROM base AS frontend-dependencies
|
FROM base AS frontend-dependencies
|
||||||
|
|
||||||
@ -73,6 +73,7 @@ RUN npm ci --only-production
|
|||||||
|
|
||||||
COPY /backend .
|
COPY /backend .
|
||||||
COPY --chown=non-root-user:nodejs standalone-entrypoint.sh standalone-entrypoint.sh
|
COPY --chown=non-root-user:nodejs standalone-entrypoint.sh standalone-entrypoint.sh
|
||||||
|
RUN npm i -D tsconfig-paths
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
# Production stage
|
# Production stage
|
||||||
@ -103,14 +104,17 @@ ENV NEXT_PUBLIC_INTERCOM_ID=$INTERCOM_ID \
|
|||||||
WORKDIR /
|
WORKDIR /
|
||||||
|
|
||||||
COPY --from=backend-runner /app /backend
|
COPY --from=backend-runner /app /backend
|
||||||
|
COPY --from=backend-runner /app/dist/services/smtp/templates /backend/dist/templates
|
||||||
|
|
||||||
COPY --from=frontend-runner /app ./backend/frontend-build
|
COPY --from=frontend-runner /app ./backend/frontend-build
|
||||||
|
|
||||||
|
|
||||||
ENV PORT 8080
|
ENV PORT 8080
|
||||||
|
ENV HOST=0.0.0.0
|
||||||
ENV HTTPS_ENABLED false
|
ENV HTTPS_ENABLED false
|
||||||
ENV NODE_ENV production
|
ENV NODE_ENV production
|
||||||
ENV STANDALONE_BUILD true
|
ENV STANDALONE_BUILD true
|
||||||
|
ENV STANDALONE_MODE true
|
||||||
WORKDIR /backend
|
WORKDIR /backend
|
||||||
|
|
||||||
ENV TELEMETRY_ENABLED true
|
ENV TELEMETRY_ENABLED true
|
||||||
@ -119,10 +123,8 @@ HEALTHCHECK --interval=10s --timeout=3s --start-period=10s \
|
|||||||
CMD node healthcheck.js
|
CMD node healthcheck.js
|
||||||
|
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
|
EXPOSE 443
|
||||||
|
|
||||||
USER non-root-user
|
USER non-root-user
|
||||||
|
|
||||||
CMD ["./standalone-entrypoint.sh"]
|
CMD ["./standalone-entrypoint.sh"]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
3
Makefile
3
Makefile
@ -7,6 +7,9 @@ push:
|
|||||||
up-dev:
|
up-dev:
|
||||||
docker-compose -f docker-compose.dev.yml up --build
|
docker-compose -f docker-compose.dev.yml up --build
|
||||||
|
|
||||||
|
up-pg-dev:
|
||||||
|
docker compose -f docker-compose.pg.yml up --build
|
||||||
|
|
||||||
i-dev:
|
i-dev:
|
||||||
infisical run -- docker-compose -f docker-compose.dev.yml up --build
|
infisical run -- docker-compose -f docker-compose.dev.yml up --build
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ Note that this security address should be used only for undisclosed vulnerabilit
|
|||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Whether it's big or small, we love contributions. Check out our guide to see how to [get started](https://infisical.com/docs/contributing/overview).
|
Whether it's big or small, we love contributions. Check out our guide to see how to [get started](https://infisical.com/docs/contributing/getting-started).
|
||||||
|
|
||||||
Not sure where to get started? You can:
|
Not sure where to get started? You can:
|
||||||
|
|
||||||
|
11
backend-mongo/.dockerignore
Normal file
11
backend-mongo/.dockerignore
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
node_modules
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
Dockerfile
|
||||||
|
.dockerignore
|
||||||
|
docker-compose.*
|
||||||
|
.DS_Store
|
||||||
|
*.swp
|
||||||
|
*~
|
2
backend-mongo/.eslintignore
Normal file
2
backend-mongo/.eslintignore
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
node_modules
|
||||||
|
built
|
33
backend-mongo/Dockerfile
Normal file
33
backend-mongo/Dockerfile
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# Build stage
|
||||||
|
FROM node:16-alpine AS build
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm ci --only-production
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Production stage
|
||||||
|
FROM node:16-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
ENV npm_config_cache /home/node/.npm
|
||||||
|
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm ci --only-production && npm cache clean --force
|
||||||
|
|
||||||
|
COPY --from=build /app .
|
||||||
|
|
||||||
|
RUN apk add --no-cache bash curl && curl -1sLf \
|
||||||
|
'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.alpine.sh' | bash \
|
||||||
|
&& apk add infisical=0.8.1 && apk add --no-cache git
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=10s --timeout=3s --start-period=10s \
|
||||||
|
CMD node healthcheck.js
|
||||||
|
|
||||||
|
EXPOSE 4000
|
||||||
|
|
||||||
|
CMD ["node", "build/index.js"]
|
Before Width: | Height: | Size: 493 KiB After Width: | Height: | Size: 493 KiB |
6
backend-mongo/nodemon.json
Normal file
6
backend-mongo/nodemon.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"watch": ["src"],
|
||||||
|
"ext": ".ts,.js",
|
||||||
|
"ignore": [],
|
||||||
|
"exec": "ts-node ./src/index.ts"
|
||||||
|
}
|
32861
backend-mongo/package-lock.json
generated
Normal file
32861
backend-mongo/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
148
backend-mongo/package.json
Normal file
148
backend-mongo/package.json
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"@aws-sdk/client-secrets-manager": "^3.319.0",
|
||||||
|
"@casl/ability": "^6.5.0",
|
||||||
|
"@casl/mongoose": "^7.2.1",
|
||||||
|
"@godaddy/terminus": "^4.12.0",
|
||||||
|
"@node-saml/passport-saml": "^4.0.4",
|
||||||
|
"@octokit/rest": "^19.0.5",
|
||||||
|
"@sentry/node": "^7.77.0",
|
||||||
|
"@sentry/tracing": "^7.48.0",
|
||||||
|
"@serdnam/pino-cloudwatch-transport": "^1.0.4",
|
||||||
|
"@types/crypto-js": "^4.1.1",
|
||||||
|
"@types/libsodium-wrappers": "^0.7.10",
|
||||||
|
"@ucast/mongo2js": "^1.3.4",
|
||||||
|
"ajv": "^8.12.0",
|
||||||
|
"argon2": "^0.30.3",
|
||||||
|
"aws-sdk": "^2.1364.0",
|
||||||
|
"axios": "^1.6.0",
|
||||||
|
"axios-retry": "^3.4.0",
|
||||||
|
"bcrypt": "^5.1.0",
|
||||||
|
"bigint-conversion": "^2.4.0",
|
||||||
|
"cookie-parser": "^1.4.6",
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"crypto-js": "^4.2.0",
|
||||||
|
"dotenv": "^16.0.1",
|
||||||
|
"express": "^4.18.1",
|
||||||
|
"express-async-errors": "^3.1.1",
|
||||||
|
"express-rate-limit": "^6.7.0",
|
||||||
|
"express-validator": "^6.14.2",
|
||||||
|
"handlebars": "^4.7.7",
|
||||||
|
"helmet": "^5.1.1",
|
||||||
|
"infisical-node": "^1.2.1",
|
||||||
|
"ioredis": "^5.3.2",
|
||||||
|
"jmespath": "^0.16.0",
|
||||||
|
"js-yaml": "^4.1.0",
|
||||||
|
"jsonwebtoken": "^9.0.0",
|
||||||
|
"jsrp": "^0.2.4",
|
||||||
|
"libsodium-wrappers": "^0.7.10",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"mongoose": "^7.4.1",
|
||||||
|
"mysql2": "^3.6.2",
|
||||||
|
"nanoid": "^3.3.6",
|
||||||
|
"node-cache": "^5.1.2",
|
||||||
|
"nodemailer": "^6.8.0",
|
||||||
|
"ora": "^5.4.1",
|
||||||
|
"passport": "^0.6.0",
|
||||||
|
"passport-github": "^1.1.0",
|
||||||
|
"passport-gitlab2": "^5.0.0",
|
||||||
|
"passport-google-oauth20": "^2.0.0",
|
||||||
|
"pg": "^8.11.3",
|
||||||
|
"pino": "^8.16.1",
|
||||||
|
"pino-http": "^8.5.1",
|
||||||
|
"posthog-node": "^2.6.0",
|
||||||
|
"probot": "^12.3.3",
|
||||||
|
"query-string": "^7.1.3",
|
||||||
|
"rate-limit-mongo": "^2.3.2",
|
||||||
|
"rimraf": "^3.0.2",
|
||||||
|
"swagger-ui-express": "^4.6.2",
|
||||||
|
"tweetnacl": "^1.0.3",
|
||||||
|
"tweetnacl-util": "^0.15.1",
|
||||||
|
"typescript": "^4.9.3",
|
||||||
|
"utility-types": "^3.10.0",
|
||||||
|
"zod": "^3.22.3"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"rate-limit-mongo": {
|
||||||
|
"mongodb": "5.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "infisical-api",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "src/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node build/index.js",
|
||||||
|
"dev": "nodemon index.js",
|
||||||
|
"swagger-autogen": "node ./swagger/index.ts",
|
||||||
|
"build": "rimraf ./build && tsc && cp -R ./src/templates ./build && cp -R ./src/data ./build",
|
||||||
|
"lint": "eslint . --ext .ts",
|
||||||
|
"lint-and-fix": "eslint . --ext .ts --fix",
|
||||||
|
"lint-staged": "lint-staged",
|
||||||
|
"pretest": "docker compose -f test-resources/docker-compose.test.yml up -d",
|
||||||
|
"test": "cross-env NODE_ENV=test jest --verbose --testTimeout=10000 --detectOpenHandles; npm run posttest",
|
||||||
|
"test:ci": "npm test -- --watchAll=false --ci --reporters=default --reporters=jest-junit --reporters=github-actions --coverage --testLocationInResults --json --outputFile=coverage/report.json",
|
||||||
|
"posttest": "docker compose -f test-resources/docker-compose.test.yml down"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/Infisical/infisical-api.git"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/Infisical/infisical-api/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/Infisical/infisical-api#readme",
|
||||||
|
"description": "",
|
||||||
|
"devDependencies": {
|
||||||
|
"@jest/globals": "^29.3.1",
|
||||||
|
"@posthog/plugin-scaffold": "^1.3.4",
|
||||||
|
"@swc/core": "^1.3.99",
|
||||||
|
"@swc/helpers": "^0.5.3",
|
||||||
|
"@types/bcrypt": "^5.0.0",
|
||||||
|
"@types/bcryptjs": "^2.4.2",
|
||||||
|
"@types/bull": "^4.10.0",
|
||||||
|
"@types/cookie-parser": "^1.4.3",
|
||||||
|
"@types/cors": "^2.8.12",
|
||||||
|
"@types/express": "^4.17.14",
|
||||||
|
"@types/jest": "^29.5.0",
|
||||||
|
"@types/jmespath": "^0.15.1",
|
||||||
|
"@types/jsonwebtoken": "^8.5.9",
|
||||||
|
"@types/lodash": "^4.14.191",
|
||||||
|
"@types/node": "^18.11.3",
|
||||||
|
"@types/nodemailer": "^6.4.6",
|
||||||
|
"@types/passport": "^1.0.12",
|
||||||
|
"@types/pg": "^8.10.7",
|
||||||
|
"@types/picomatch": "^2.3.0",
|
||||||
|
"@types/pino": "^7.0.5",
|
||||||
|
"@types/supertest": "^2.0.12",
|
||||||
|
"@types/swagger-jsdoc": "^6.0.1",
|
||||||
|
"@types/swagger-ui-express": "^4.1.3",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||||
|
"@typescript-eslint/parser": "^5.40.1",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
|
"eslint": "^8.26.0",
|
||||||
|
"eslint-plugin-unused-imports": "^2.0.0",
|
||||||
|
"install": "^0.13.0",
|
||||||
|
"jest": "^29.3.1",
|
||||||
|
"jest-junit": "^15.0.0",
|
||||||
|
"nodemon": "^2.0.19",
|
||||||
|
"npm": "^8.19.3",
|
||||||
|
"pino-pretty": "^10.2.3",
|
||||||
|
"regenerator-runtime": "^0.14.0",
|
||||||
|
"smee-client": "^1.2.3",
|
||||||
|
"supertest": "^6.3.3",
|
||||||
|
"swagger-autogen": "^2.23.5",
|
||||||
|
"ts-jest": "^29.0.3",
|
||||||
|
"ts-node": "^10.9.1"
|
||||||
|
},
|
||||||
|
"jest-junit": {
|
||||||
|
"outputDirectory": "reports",
|
||||||
|
"outputName": "jest-junit.xml",
|
||||||
|
"ancestorSeparator": " › ",
|
||||||
|
"uniqueOutputName": "false",
|
||||||
|
"suiteNameTemplate": "{filepath}",
|
||||||
|
"classNameTemplate": "{classname}",
|
||||||
|
"titleTemplate": "{title}"
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
43
backend-mongo/src/bootstrap.ts
Normal file
43
backend-mongo/src/bootstrap.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import ora from "ora";
|
||||||
|
import nodemailer from "nodemailer";
|
||||||
|
import { getSmtpHost, getSmtpPort } from "./config";
|
||||||
|
import { logger } from "./utils/logging";
|
||||||
|
import mongoose from "mongoose";
|
||||||
|
import { redisClient } from "./services/RedisService";
|
||||||
|
|
||||||
|
type BootstrapOpt = {
|
||||||
|
transporter: nodemailer.Transporter;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const bootstrap = async ({ transporter }: BootstrapOpt) => {
|
||||||
|
const spinner = ora().start();
|
||||||
|
spinner.info("Checking configurations...");
|
||||||
|
spinner.info("Testing smtp connection");
|
||||||
|
|
||||||
|
await transporter
|
||||||
|
.verify()
|
||||||
|
.then(async () => {
|
||||||
|
spinner.succeed("SMTP successfully connected");
|
||||||
|
})
|
||||||
|
.catch(async (err) => {
|
||||||
|
spinner.fail(`SMTP - Failed to connect to ${await getSmtpHost()}:${await getSmtpPort()}`);
|
||||||
|
logger.error(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
spinner.info("Testing mongodb connection");
|
||||||
|
if (mongoose.connection.readyState !== mongoose.ConnectionStates.connected) {
|
||||||
|
spinner.fail("Mongo DB - Failed to connect");
|
||||||
|
} else {
|
||||||
|
spinner.succeed("Mongodb successfully connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
spinner.info("Testing redis connection");
|
||||||
|
const redisPing = await redisClient?.ping();
|
||||||
|
if (!redisPing) {
|
||||||
|
spinner.fail("Redis - Failed to connect");
|
||||||
|
} else {
|
||||||
|
spinner.succeed("Redis successfully connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
spinner.stop();
|
||||||
|
};
|
176
backend-mongo/src/config/index.ts
Normal file
176
backend-mongo/src/config/index.ts
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
import { GITLAB_URL } from "../variables";
|
||||||
|
|
||||||
|
import InfisicalClient from "infisical-node";
|
||||||
|
|
||||||
|
export const client = new InfisicalClient({
|
||||||
|
token: process.env.INFISICAL_TOKEN!
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getIsMigrationMode = async () =>
|
||||||
|
(await client.getSecret("MIGRATION_MODE")).secretValue === "true";
|
||||||
|
|
||||||
|
export const getPort = async () => (await client.getSecret("PORT")).secretValue || 4000;
|
||||||
|
export const getEncryptionKey = async () => {
|
||||||
|
const secretValue = (await client.getSecret("ENCRYPTION_KEY")).secretValue;
|
||||||
|
return secretValue === "" ? undefined : secretValue;
|
||||||
|
};
|
||||||
|
export const getRootEncryptionKey = async () => {
|
||||||
|
const secretValue = (await client.getSecret("ROOT_ENCRYPTION_KEY")).secretValue;
|
||||||
|
return secretValue === "" ? undefined : secretValue;
|
||||||
|
};
|
||||||
|
export const getInviteOnlySignup = async () =>
|
||||||
|
(await client.getSecret("INVITE_ONLY_SIGNUP")).secretValue === "true";
|
||||||
|
export const getSaltRounds = async () =>
|
||||||
|
parseInt((await client.getSecret("SALT_ROUNDS")).secretValue) || 10;
|
||||||
|
export const getAuthSecret = async () =>
|
||||||
|
(await client.getSecret("JWT_AUTH_SECRET")).secretValue ??
|
||||||
|
(await client.getSecret("AUTH_SECRET")).secretValue;
|
||||||
|
export const getJwtAuthLifetime = async () =>
|
||||||
|
(await client.getSecret("JWT_AUTH_LIFETIME")).secretValue || "10d";
|
||||||
|
export const getJwtMfaLifetime = async () =>
|
||||||
|
(await client.getSecret("JWT_MFA_LIFETIME")).secretValue || "5m";
|
||||||
|
export const getJwtRefreshLifetime = async () =>
|
||||||
|
(await client.getSecret("JWT_REFRESH_LIFETIME")).secretValue || "90d";
|
||||||
|
export const getJwtServiceSecret = async () =>
|
||||||
|
(await client.getSecret("JWT_SERVICE_SECRET")).secretValue; // TODO: deprecate (related to ST V1)
|
||||||
|
export const getJwtSignupLifetime = async () =>
|
||||||
|
(await client.getSecret("JWT_SIGNUP_LIFETIME")).secretValue || "15m";
|
||||||
|
export const getJwtProviderAuthLifetime = async () =>
|
||||||
|
(await client.getSecret("JWT_PROVIDER_AUTH_LIFETIME")).secretValue || "15m";
|
||||||
|
export const getMongoURL = async () => (await client.getSecret("MONGO_URL")).secretValue;
|
||||||
|
export const getNodeEnv = async () =>
|
||||||
|
(await client.getSecret("NODE_ENV")).secretValue || "production";
|
||||||
|
export const getVerboseErrorOutput = async () =>
|
||||||
|
(await client.getSecret("VERBOSE_ERROR_OUTPUT")).secretValue === "true" && true;
|
||||||
|
export const getLokiHost = async () => (await client.getSecret("LOKI_HOST")).secretValue;
|
||||||
|
export const getClientIdAzure = async () => (await client.getSecret("CLIENT_ID_AZURE")).secretValue;
|
||||||
|
export const getClientIdHeroku = async () =>
|
||||||
|
(await client.getSecret("CLIENT_ID_HEROKU")).secretValue;
|
||||||
|
export const getClientIdVercel = async () =>
|
||||||
|
(await client.getSecret("CLIENT_ID_VERCEL")).secretValue;
|
||||||
|
export const getClientIdNetlify = async () =>
|
||||||
|
(await client.getSecret("CLIENT_ID_NETLIFY")).secretValue;
|
||||||
|
export const getClientIdGitHub = async () =>
|
||||||
|
(await client.getSecret("CLIENT_ID_GITHUB")).secretValue;
|
||||||
|
export const getClientIdGitLab = async () =>
|
||||||
|
(await client.getSecret("CLIENT_ID_GITLAB")).secretValue;
|
||||||
|
export const getClientIdBitBucket = async () =>
|
||||||
|
(await client.getSecret("CLIENT_ID_BITBUCKET")).secretValue;
|
||||||
|
export const getClientIdGCPSecretManager = async () =>
|
||||||
|
(await client.getSecret("CLIENT_ID_GCP_SECRET_MANAGER")).secretValue;
|
||||||
|
export const getClientSecretAzure = async () =>
|
||||||
|
(await client.getSecret("CLIENT_SECRET_AZURE")).secretValue;
|
||||||
|
export const getClientSecretHeroku = async () =>
|
||||||
|
(await client.getSecret("CLIENT_SECRET_HEROKU")).secretValue;
|
||||||
|
export const getClientSecretVercel = async () =>
|
||||||
|
(await client.getSecret("CLIENT_SECRET_VERCEL")).secretValue;
|
||||||
|
export const getClientSecretNetlify = async () =>
|
||||||
|
(await client.getSecret("CLIENT_SECRET_NETLIFY")).secretValue;
|
||||||
|
export const getClientSecretGitHub = async () =>
|
||||||
|
(await client.getSecret("CLIENT_SECRET_GITHUB")).secretValue;
|
||||||
|
export const getClientSecretGitLab = async () =>
|
||||||
|
(await client.getSecret("CLIENT_SECRET_GITLAB")).secretValue;
|
||||||
|
export const getClientSecretBitBucket = async () =>
|
||||||
|
(await client.getSecret("CLIENT_SECRET_BITBUCKET")).secretValue;
|
||||||
|
export const getClientSecretGCPSecretManager = async () =>
|
||||||
|
(await client.getSecret("CLIENT_SECRET_GCP_SECRET_MANAGER")).secretValue;
|
||||||
|
export const getClientSlugVercel = async () =>
|
||||||
|
(await client.getSecret("CLIENT_SLUG_VERCEL")).secretValue;
|
||||||
|
|
||||||
|
export const getClientIdGoogleLogin = async () =>
|
||||||
|
(await client.getSecret("CLIENT_ID_GOOGLE_LOGIN")).secretValue;
|
||||||
|
export const getClientSecretGoogleLogin = async () =>
|
||||||
|
(await client.getSecret("CLIENT_SECRET_GOOGLE_LOGIN")).secretValue;
|
||||||
|
export const getClientIdGitHubLogin = async () =>
|
||||||
|
(await client.getSecret("CLIENT_ID_GITHUB_LOGIN")).secretValue;
|
||||||
|
export const getClientSecretGitHubLogin = async () =>
|
||||||
|
(await client.getSecret("CLIENT_SECRET_GITHUB_LOGIN")).secretValue;
|
||||||
|
export const getClientIdGitLabLogin = async () =>
|
||||||
|
(await client.getSecret("CLIENT_ID_GITLAB_LOGIN")).secretValue;
|
||||||
|
export const getClientSecretGitLabLogin = async () =>
|
||||||
|
(await client.getSecret("CLIENT_SECRET_GITLAB_LOGIN")).secretValue;
|
||||||
|
export const getUrlGitLabLogin = async () =>
|
||||||
|
(await client.getSecret("URL_GITLAB_LOGIN")).secretValue || GITLAB_URL;
|
||||||
|
|
||||||
|
export const getAwsCloudWatchLog = async () => {
|
||||||
|
const logGroupName =
|
||||||
|
(await client.getSecret("AWS_CLOUDWATCH_LOG_GROUP_NAME")).secretValue || "infisical-log-stream";
|
||||||
|
const region = (await client.getSecret("AWS_CLOUDWATCH_LOG_REGION")).secretValue;
|
||||||
|
const accessKeyId = (await client.getSecret("AWS_CLOUDWATCH_LOG_ACCESS_KEY_ID")).secretValue;
|
||||||
|
const accessKeySecret = (await client.getSecret("AWS_CLOUDWATCH_LOG_ACCESS_KEY_SECRET"))
|
||||||
|
.secretValue;
|
||||||
|
const interval = parseInt(
|
||||||
|
(await client.getSecret("AWS_CLOUDWATCH_LOG_INTERVAL")).secretValue || 1000,
|
||||||
|
10
|
||||||
|
);
|
||||||
|
if (!region || !accessKeyId || !accessKeySecret) return;
|
||||||
|
return { logGroupName, region, accessKeySecret, accessKeyId, interval };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPostHogHost = async () =>
|
||||||
|
(await client.getSecret("POSTHOG_HOST")).secretValue || "https://app.posthog.com";
|
||||||
|
export const getPostHogProjectApiKey = async () =>
|
||||||
|
(await client.getSecret("POSTHOG_PROJECT_API_KEY")).secretValue ||
|
||||||
|
"phc_nSin8j5q2zdhpFDI1ETmFNUIuTG4DwKVyIigrY10XiE";
|
||||||
|
export const getSentryDSN = async () => (await client.getSecret("SENTRY_DSN")).secretValue;
|
||||||
|
export const getSiteURL = async () => (await client.getSecret("SITE_URL")).secretValue;
|
||||||
|
export const getSmtpHost = async () => (await client.getSecret("SMTP_HOST")).secretValue;
|
||||||
|
export const getSmtpSecure = async () =>
|
||||||
|
(await client.getSecret("SMTP_SECURE")).secretValue === "true" || false;
|
||||||
|
export const getSmtpPort = async () =>
|
||||||
|
parseInt((await client.getSecret("SMTP_PORT")).secretValue) || 587;
|
||||||
|
export const getSmtpUsername = async () => (await client.getSecret("SMTP_USERNAME")).secretValue;
|
||||||
|
export const getSmtpPassword = async () => (await client.getSecret("SMTP_PASSWORD")).secretValue;
|
||||||
|
export const getSmtpFromAddress = async () =>
|
||||||
|
(await client.getSecret("SMTP_FROM_ADDRESS")).secretValue;
|
||||||
|
export const getSmtpFromName = async () =>
|
||||||
|
(await client.getSecret("SMTP_FROM_NAME")).secretValue || "Infisical";
|
||||||
|
|
||||||
|
export const getSecretScanningWebhookProxy = async () =>
|
||||||
|
(await client.getSecret("SECRET_SCANNING_WEBHOOK_PROXY")).secretValue;
|
||||||
|
export const getSecretScanningWebhookSecret = async () =>
|
||||||
|
(await client.getSecret("SECRET_SCANNING_WEBHOOK_SECRET")).secretValue;
|
||||||
|
export const getSecretScanningGitAppId = async () =>
|
||||||
|
(await client.getSecret("SECRET_SCANNING_GIT_APP_ID")).secretValue;
|
||||||
|
export const getSecretScanningPrivateKey = async () =>
|
||||||
|
(await client.getSecret("SECRET_SCANNING_PRIVATE_KEY")).secretValue;
|
||||||
|
|
||||||
|
export const getRedisUrl = async () => (await client.getSecret("REDIS_URL")).secretValue;
|
||||||
|
export const getIsInfisicalCloud = async () =>
|
||||||
|
(await client.getSecret("INFISICAL_CLOUD")).secretValue === "true";
|
||||||
|
|
||||||
|
export const getLicenseKey = async () => {
|
||||||
|
const secretValue = (await client.getSecret("LICENSE_KEY")).secretValue;
|
||||||
|
return secretValue === "" ? undefined : secretValue;
|
||||||
|
};
|
||||||
|
export const getLicenseServerKey = async () => {
|
||||||
|
const secretValue = (await client.getSecret("LICENSE_SERVER_KEY")).secretValue;
|
||||||
|
return secretValue === "" ? undefined : secretValue;
|
||||||
|
};
|
||||||
|
export const getLicenseServerUrl = async () =>
|
||||||
|
(await client.getSecret("LICENSE_SERVER_URL")).secretValue || "https://portal.infisical.com";
|
||||||
|
|
||||||
|
export const getTelemetryEnabled = async () =>
|
||||||
|
(await client.getSecret("TELEMETRY_ENABLED")).secretValue !== "false" && true;
|
||||||
|
export const getLoopsApiKey = async () => (await client.getSecret("LOOPS_API_KEY")).secretValue;
|
||||||
|
export const getSmtpConfigured = async () =>
|
||||||
|
(await client.getSecret("SMTP_HOST")).secretValue == "" ||
|
||||||
|
(await client.getSecret("SMTP_HOST")).secretValue == undefined
|
||||||
|
? false
|
||||||
|
: true;
|
||||||
|
export const getHttpsEnabled = async () => {
|
||||||
|
if ((await getNodeEnv()) != "production") {
|
||||||
|
// no https for anything other than prod
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
(await client.getSecret("HTTPS_ENABLED")).secretValue == undefined ||
|
||||||
|
(await client.getSecret("HTTPS_ENABLED")).secretValue == ""
|
||||||
|
) {
|
||||||
|
// default when no value present
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (await client.getSecret("HTTPS_ENABLED")).secretValue === "true" && true;
|
||||||
|
};
|
24
backend-mongo/src/config/serverConfig.ts
Normal file
24
backend-mongo/src/config/serverConfig.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { IServerConfig, ServerConfig } from "../models/serverConfig";
|
||||||
|
|
||||||
|
let serverConfig: IServerConfig;
|
||||||
|
|
||||||
|
export const serverConfigInit = async () => {
|
||||||
|
const cfg = await ServerConfig.findOne({}).lean();
|
||||||
|
if (!cfg) {
|
||||||
|
const cfg = new ServerConfig();
|
||||||
|
await cfg.save();
|
||||||
|
serverConfig = cfg.toObject();
|
||||||
|
} else {
|
||||||
|
serverConfig = cfg;
|
||||||
|
}
|
||||||
|
return serverConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getServerConfig = () => serverConfig;
|
||||||
|
|
||||||
|
export const updateServerConfig = async (data: Partial<IServerConfig>) => {
|
||||||
|
const cfg = await ServerConfig.findByIdAndUpdate(serverConfig._id, data, { new: true });
|
||||||
|
if (!cfg) throw new Error("Failed to update server config");
|
||||||
|
serverConfig = cfg.toObject();
|
||||||
|
return serverConfig;
|
||||||
|
};
|
101
backend-mongo/src/controllers/v1/adminController.ts
Normal file
101
backend-mongo/src/controllers/v1/adminController.ts
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import { Request, Response } from "express";
|
||||||
|
import { getHttpsEnabled, getIsMigrationMode } from "../../config";
|
||||||
|
import { getServerConfig, updateServerConfig as setServerConfig } from "../../config/serverConfig";
|
||||||
|
import { initializeDefaultOrg, issueAuthTokens } from "../../helpers";
|
||||||
|
import { validateRequest } from "../../helpers/validation";
|
||||||
|
import { User } from "../../models";
|
||||||
|
import { TelemetryService } from "../../services";
|
||||||
|
import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors";
|
||||||
|
import * as reqValidator from "../../validation/admin";
|
||||||
|
|
||||||
|
export const getServerConfigInfo = async (_req: Request, res: Response) => {
|
||||||
|
const config = getServerConfig();
|
||||||
|
const isMigrationModeOn = await getIsMigrationMode();
|
||||||
|
return res.send({ config: { ...config, isMigrationModeOn } });
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateServerConfig = async (req: Request, res: Response) => {
|
||||||
|
const {
|
||||||
|
body: { allowSignUp }
|
||||||
|
} = await validateRequest(reqValidator.UpdateServerConfigV1, req);
|
||||||
|
const config = await setServerConfig({ allowSignUp });
|
||||||
|
return res.send({ config });
|
||||||
|
};
|
||||||
|
|
||||||
|
export const adminSignUp = async (req: Request, res: Response) => {
|
||||||
|
const cfg = getServerConfig();
|
||||||
|
if (cfg.initialized) throw UnauthorizedRequestError({ message: "Admin has been created" });
|
||||||
|
const {
|
||||||
|
body: {
|
||||||
|
email,
|
||||||
|
publicKey,
|
||||||
|
salt,
|
||||||
|
lastName,
|
||||||
|
verifier,
|
||||||
|
firstName,
|
||||||
|
protectedKey,
|
||||||
|
protectedKeyIV,
|
||||||
|
protectedKeyTag,
|
||||||
|
encryptedPrivateKey,
|
||||||
|
encryptedPrivateKeyIV,
|
||||||
|
encryptedPrivateKeyTag
|
||||||
|
}
|
||||||
|
} = await validateRequest(reqValidator.SignupV1, req);
|
||||||
|
let user = await User.findOne({ email });
|
||||||
|
if (user) throw BadRequestError({ message: "User already exist" });
|
||||||
|
user = new User({
|
||||||
|
email,
|
||||||
|
firstName,
|
||||||
|
lastName,
|
||||||
|
encryptionVersion: 2,
|
||||||
|
protectedKey,
|
||||||
|
protectedKeyIV,
|
||||||
|
protectedKeyTag,
|
||||||
|
publicKey,
|
||||||
|
encryptedPrivateKey,
|
||||||
|
iv: encryptedPrivateKeyIV,
|
||||||
|
tag: encryptedPrivateKeyTag,
|
||||||
|
salt,
|
||||||
|
verifier,
|
||||||
|
superAdmin: true
|
||||||
|
});
|
||||||
|
await user.save();
|
||||||
|
await initializeDefaultOrg({ organizationName: "Admin Org", user });
|
||||||
|
|
||||||
|
await setServerConfig({ initialized: true });
|
||||||
|
|
||||||
|
// issue tokens
|
||||||
|
const tokens = await issueAuthTokens({
|
||||||
|
userId: user._id,
|
||||||
|
ip: req.realIP,
|
||||||
|
userAgent: req.headers["user-agent"] ?? ""
|
||||||
|
});
|
||||||
|
|
||||||
|
const token = tokens.token;
|
||||||
|
|
||||||
|
const postHogClient = await TelemetryService.getPostHogClient();
|
||||||
|
if (postHogClient) {
|
||||||
|
postHogClient.capture({
|
||||||
|
event: "admin initialization",
|
||||||
|
properties: {
|
||||||
|
email: user.email,
|
||||||
|
lastName,
|
||||||
|
firstName
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// store (refresh) token in httpOnly cookie
|
||||||
|
res.cookie("jid", tokens.refreshToken, {
|
||||||
|
httpOnly: true,
|
||||||
|
path: "/",
|
||||||
|
sameSite: "strict",
|
||||||
|
secure: await getHttpsEnabled()
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
message: "Successfully set up admin account",
|
||||||
|
user,
|
||||||
|
token
|
||||||
|
});
|
||||||
|
};
|
@ -3,31 +3,41 @@ import jwt from "jsonwebtoken";
|
|||||||
import * as bigintConversion from "bigint-conversion";
|
import * as bigintConversion from "bigint-conversion";
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
const jsrp = require("jsrp");
|
const jsrp = require("jsrp");
|
||||||
import { LoginSRPDetail, TokenVersion, User } from "../../models";
|
import {
|
||||||
|
LoginSRPDetail,
|
||||||
|
TokenVersion,
|
||||||
|
User
|
||||||
|
} from "../../models";
|
||||||
import { clearTokens, createToken, issueAuthTokens } from "../../helpers/auth";
|
import { clearTokens, createToken, issueAuthTokens } from "../../helpers/auth";
|
||||||
import { checkUserDevice } from "../../helpers/user";
|
import { checkUserDevice } from "../../helpers/user";
|
||||||
|
import { AuthTokenType } from "../../variables";
|
||||||
import {
|
import {
|
||||||
ACTION_LOGIN,
|
BadRequestError,
|
||||||
ACTION_LOGOUT,
|
UnauthorizedRequestError
|
||||||
AuthTokenType
|
} from "../../utils/errors";
|
||||||
} from "../../variables";
|
|
||||||
import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors";
|
|
||||||
import { EELogService } from "../../ee/services";
|
|
||||||
import { getUserAgentType } from "../../utils/posthog";
|
|
||||||
import {
|
import {
|
||||||
getAuthSecret,
|
getAuthSecret,
|
||||||
getHttpsEnabled,
|
getHttpsEnabled,
|
||||||
getJwtAuthLifetime
|
getJwtAuthLifetime,
|
||||||
} from "../../config";
|
} from "../../config";
|
||||||
import { ActorType } from "../../ee/models";
|
import { ActorType } from "../../ee/models";
|
||||||
import { validateRequest } from "../../helpers/validation";
|
import { validateRequest } from "../../helpers/validation";
|
||||||
import * as reqValidator from "../../validation/auth";
|
import * as reqValidator from "../../validation/auth";
|
||||||
|
|
||||||
declare module "jsonwebtoken" {
|
declare module "jsonwebtoken" {
|
||||||
|
export interface AuthnJwtPayload extends jwt.JwtPayload {
|
||||||
|
authTokenType: AuthTokenType;
|
||||||
|
}
|
||||||
export interface UserIDJwtPayload extends jwt.JwtPayload {
|
export interface UserIDJwtPayload extends jwt.JwtPayload {
|
||||||
userId: string;
|
userId: string;
|
||||||
refreshVersion?: number;
|
refreshVersion?: number;
|
||||||
}
|
}
|
||||||
|
export interface IdentityAccessTokenJwtPayload extends jwt.JwtPayload {
|
||||||
|
_id: string;
|
||||||
|
clientSecretId: string;
|
||||||
|
identityAccessTokenId: string;
|
||||||
|
authTokenType: string;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -137,19 +147,6 @@ export const login2 = async (req: Request, res: Response) => {
|
|||||||
secure: await getHttpsEnabled()
|
secure: await getHttpsEnabled()
|
||||||
});
|
});
|
||||||
|
|
||||||
const loginAction = await EELogService.createAction({
|
|
||||||
name: ACTION_LOGIN,
|
|
||||||
userId: user._id
|
|
||||||
});
|
|
||||||
|
|
||||||
loginAction &&
|
|
||||||
(await EELogService.createLog({
|
|
||||||
userId: user._id,
|
|
||||||
actions: [loginAction],
|
|
||||||
channel: getUserAgentType(req.headers["user-agent"]),
|
|
||||||
ipAddress: req.realIP
|
|
||||||
}));
|
|
||||||
|
|
||||||
// return (access) token in response
|
// return (access) token in response
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
token: tokens.token,
|
token: tokens.token,
|
||||||
@ -186,19 +183,6 @@ export const logout = async (req: Request, res: Response) => {
|
|||||||
secure: (await getHttpsEnabled()) as boolean
|
secure: (await getHttpsEnabled()) as boolean
|
||||||
});
|
});
|
||||||
|
|
||||||
const logoutAction = await EELogService.createAction({
|
|
||||||
name: ACTION_LOGOUT,
|
|
||||||
userId: req.user._id
|
|
||||||
});
|
|
||||||
|
|
||||||
logoutAction &&
|
|
||||||
(await EELogService.createLog({
|
|
||||||
userId: req.user._id,
|
|
||||||
actions: [logoutAction],
|
|
||||||
channel: getUserAgentType(req.headers["user-agent"]),
|
|
||||||
ipAddress: req.realIP
|
|
||||||
}));
|
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
message: "Successfully logged out."
|
message: "Successfully logged out."
|
||||||
});
|
});
|
@ -7,7 +7,7 @@ import * as reqValidator from "../../validation/bot";
|
|||||||
import {
|
import {
|
||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
ProjectPermissionSub,
|
ProjectPermissionSub,
|
||||||
getUserProjectPermissions
|
getAuthDataProjectPermissions
|
||||||
} from "../../ee/services/ProjectRoleService";
|
} from "../../ee/services/ProjectRoleService";
|
||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
import { BadRequestError } from "../../utils/errors";
|
import { BadRequestError } from "../../utils/errors";
|
||||||
@ -28,7 +28,11 @@ export const getBotByWorkspaceId = async (req: Request, res: Response) => {
|
|||||||
const {
|
const {
|
||||||
params: { workspaceId }
|
params: { workspaceId }
|
||||||
} = await validateRequest(reqValidator.GetBotByWorkspaceIdV1, req);
|
} = await validateRequest(reqValidator.GetBotByWorkspaceIdV1, req);
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
||||||
@ -70,7 +74,11 @@ export const setBotActiveState = async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
const userId = req.user._id;
|
const userId = req.user._id;
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(userId, bot.workspace.toString());
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: bot.workspace
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Edit,
|
ProjectPermissionActions.Edit,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
@ -1,4 +1,5 @@
|
|||||||
import * as authController from "./authController";
|
import * as authController from "./authController";
|
||||||
|
import * as universalAuthController from "./universalAuthController";
|
||||||
import * as botController from "./botController";
|
import * as botController from "./botController";
|
||||||
import * as integrationAuthController from "./integrationAuthController";
|
import * as integrationAuthController from "./integrationAuthController";
|
||||||
import * as integrationController from "./integrationController";
|
import * as integrationController from "./integrationController";
|
||||||
@ -16,8 +17,11 @@ import * as workspaceController from "./workspaceController";
|
|||||||
import * as secretScanningController from "./secretScanningController";
|
import * as secretScanningController from "./secretScanningController";
|
||||||
import * as webhookController from "./webhookController";
|
import * as webhookController from "./webhookController";
|
||||||
import * as secretImpsController from "./secretImpsController";
|
import * as secretImpsController from "./secretImpsController";
|
||||||
|
import * as adminController from "./adminController";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
authController,
|
authController,
|
||||||
|
universalAuthController,
|
||||||
botController,
|
botController,
|
||||||
integrationAuthController,
|
integrationAuthController,
|
||||||
integrationController,
|
integrationController,
|
||||||
@ -34,5 +38,6 @@ export {
|
|||||||
workspaceController,
|
workspaceController,
|
||||||
secretScanningController,
|
secretScanningController,
|
||||||
webhookController,
|
webhookController,
|
||||||
secretImpsController
|
secretImpsController,
|
||||||
|
adminController
|
||||||
};
|
};
|
@ -2,7 +2,7 @@ import { Request, Response } from "express";
|
|||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { standardRequest } from "../../config/request";
|
import { standardRequest } from "../../config/request";
|
||||||
import { getApps, getTeams, revokeAccess } from "../../integrations";
|
import { getApps, getTeams, revokeAccess } from "../../integrations";
|
||||||
import { Bot, IntegrationAuth, Workspace } from "../../models";
|
import { Bot, IIntegrationAuth, Integration, IntegrationAuth, Workspace } from "../../models";
|
||||||
import { EventType } from "../../ee/models";
|
import { EventType } from "../../ee/models";
|
||||||
import { IntegrationService } from "../../services";
|
import { IntegrationService } from "../../services";
|
||||||
import { EEAuditLogService } from "../../ee/services";
|
import { EEAuditLogService } from "../../ee/services";
|
||||||
@ -10,6 +10,7 @@ import {
|
|||||||
ALGORITHM_AES_256_GCM,
|
ALGORITHM_AES_256_GCM,
|
||||||
ENCODING_SCHEME_UTF8,
|
ENCODING_SCHEME_UTF8,
|
||||||
INTEGRATION_BITBUCKET_API_URL,
|
INTEGRATION_BITBUCKET_API_URL,
|
||||||
|
INTEGRATION_CHECKLY_API_URL,
|
||||||
INTEGRATION_GCP_SECRET_MANAGER,
|
INTEGRATION_GCP_SECRET_MANAGER,
|
||||||
INTEGRATION_NORTHFLANK_API_URL,
|
INTEGRATION_NORTHFLANK_API_URL,
|
||||||
INTEGRATION_QOVERY_API_URL,
|
INTEGRATION_QOVERY_API_URL,
|
||||||
@ -24,11 +25,10 @@ import * as reqValidator from "../../validation/integrationAuth";
|
|||||||
import {
|
import {
|
||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
ProjectPermissionSub,
|
ProjectPermissionSub,
|
||||||
getUserProjectPermissions
|
getAuthDataProjectPermissions
|
||||||
} from "../../ee/services/ProjectRoleService";
|
} from "../../ee/services/ProjectRoleService";
|
||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
import { getIntegrationAuthAccessHelper } from "../../helpers";
|
import { getIntegrationAuthAccessHelper } from "../../helpers";
|
||||||
import { ObjectId } from "mongodb";
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* Return integration authorization with id [integrationAuthId]
|
* Return integration authorization with id [integrationAuthId]
|
||||||
@ -40,15 +40,15 @@ export const getIntegrationAuth = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
const integrationAuth = await IntegrationAuth.findById(integrationAuthId);
|
const integrationAuth = await IntegrationAuth.findById(integrationAuthId);
|
||||||
|
|
||||||
if (!integrationAuth)
|
if (!integrationAuth) return res.status(400).send({
|
||||||
return res.status(400).send({
|
|
||||||
message: "Failed to find integration authorization"
|
message: "Failed to find integration authorization"
|
||||||
});
|
});
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
req.user._id,
|
authData: req.authData,
|
||||||
integrationAuth.workspace.toString()
|
workspaceId: integrationAuth.workspace
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
||||||
@ -79,7 +79,11 @@ export const oAuthExchange = async (req: Request, res: Response) => {
|
|||||||
} = await validateRequest(reqValidator.OauthExchangeV1, req);
|
} = await validateRequest(reqValidator.OauthExchangeV1, req);
|
||||||
if (!INTEGRATION_SET.has(integration)) throw new Error("Failed to validate integration");
|
if (!INTEGRATION_SET.has(integration)) throw new Error("Failed to validate integration");
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Create,
|
ProjectPermissionActions.Create,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
||||||
@ -126,12 +130,15 @@ export const oAuthExchange = async (req: Request, res: Response) => {
|
|||||||
export const saveIntegrationToken = async (req: Request, res: Response) => {
|
export const saveIntegrationToken = async (req: Request, res: Response) => {
|
||||||
// TODO: refactor
|
// TODO: refactor
|
||||||
// TODO: check if access token is valid for each integration
|
// TODO: check if access token is valid for each integration
|
||||||
let integrationAuth;
|
|
||||||
const {
|
const {
|
||||||
body: { workspaceId, integration, url, accessId, namespace, accessToken, refreshToken }
|
body: { workspaceId, integration, url, accessId, namespace, accessToken, refreshToken }
|
||||||
} = await validateRequest(reqValidator.SaveIntegrationAccessTokenV1, req);
|
} = await validateRequest(reqValidator.SaveIntegrationAccessTokenV1, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Create,
|
ProjectPermissionActions.Create,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
||||||
@ -144,12 +151,7 @@ export const saveIntegrationToken = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
if (!bot) throw new Error("Bot must be enabled to save integration access token");
|
if (!bot) throw new Error("Bot must be enabled to save integration access token");
|
||||||
|
|
||||||
integrationAuth = await IntegrationAuth.findOneAndUpdate(
|
let integrationAuth = await new IntegrationAuth({
|
||||||
{
|
|
||||||
workspace: new Types.ObjectId(workspaceId),
|
|
||||||
integration
|
|
||||||
},
|
|
||||||
{
|
|
||||||
workspace: new Types.ObjectId(workspaceId),
|
workspace: new Types.ObjectId(workspaceId),
|
||||||
integration,
|
integration,
|
||||||
url,
|
url,
|
||||||
@ -163,12 +165,7 @@ export const saveIntegrationToken = async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
: {})
|
: {})
|
||||||
},
|
}).save();
|
||||||
{
|
|
||||||
new: true,
|
|
||||||
upsert: true
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// encrypt and save integration access details
|
// encrypt and save integration access details
|
||||||
if (refreshToken) {
|
if (refreshToken) {
|
||||||
@ -180,12 +177,12 @@ export const saveIntegrationToken = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
// encrypt and save integration access details
|
// encrypt and save integration access details
|
||||||
if (accessId || accessToken) {
|
if (accessId || accessToken) {
|
||||||
integrationAuth = await IntegrationService.setIntegrationAuthAccess({
|
integrationAuth = (await IntegrationService.setIntegrationAuthAccess({
|
||||||
integrationAuthId: integrationAuth._id.toString(),
|
integrationAuthId: integrationAuth._id.toString(),
|
||||||
accessId,
|
accessId,
|
||||||
accessToken,
|
accessToken,
|
||||||
accessExpiresAt: undefined
|
accessExpiresAt: undefined
|
||||||
});
|
})) as IIntegrationAuth;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!integrationAuth) throw new Error("Failed to save integration access token");
|
if (!integrationAuth) throw new Error("Failed to save integration access token");
|
||||||
@ -222,13 +219,14 @@ export const getIntegrationAuthApps = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
||||||
const { integrationAuth, accessToken, accessId } = await getIntegrationAuthAccessHelper({
|
const { integrationAuth, accessToken, accessId } = await getIntegrationAuthAccessHelper({
|
||||||
integrationAuthId: new ObjectId(integrationAuthId)
|
integrationAuthId: new Types.ObjectId(integrationAuthId)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: integrationAuth.workspace
|
||||||
});
|
});
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
|
||||||
req.user._id,
|
|
||||||
integrationAuth.workspace.toString()
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
||||||
@ -260,13 +258,14 @@ export const getIntegrationAuthTeams = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
||||||
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
||||||
integrationAuthId: new ObjectId(integrationAuthId)
|
integrationAuthId: new Types.ObjectId(integrationAuthId)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: integrationAuth.workspace
|
||||||
});
|
});
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
|
||||||
req.user._id,
|
|
||||||
integrationAuth.workspace.toString()
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
||||||
@ -296,13 +295,14 @@ export const getIntegrationAuthVercelBranches = async (req: Request, res: Respon
|
|||||||
|
|
||||||
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
||||||
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
||||||
integrationAuthId: new ObjectId(integrationAuthId)
|
integrationAuthId: new Types.ObjectId(integrationAuthId)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: integrationAuth.workspace
|
||||||
});
|
});
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
|
||||||
req.user._id,
|
|
||||||
integrationAuth.workspace.toString()
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
||||||
@ -345,6 +345,60 @@ export const getIntegrationAuthVercelBranches = async (req: Request, res: Respon
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return list of Checkly groups for a specific user
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
*/
|
||||||
|
export const getIntegrationAuthChecklyGroups = async (req: Request, res: Response) => {
|
||||||
|
const {
|
||||||
|
params: { integrationAuthId },
|
||||||
|
query: { accountId }
|
||||||
|
} = await validateRequest(reqValidator.GetIntegrationAuthChecklyGroupsV1, req);
|
||||||
|
|
||||||
|
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
||||||
|
integrationAuthId: new Types.ObjectId(integrationAuthId)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: integrationAuth.workspace
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Read,
|
||||||
|
ProjectPermissionSub.Integrations
|
||||||
|
);
|
||||||
|
|
||||||
|
interface ChecklyGroup {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accountId && accountId !== "") {
|
||||||
|
const { data }: { data: ChecklyGroup[] } = (
|
||||||
|
await standardRequest.get(`${INTEGRATION_CHECKLY_API_URL}/v1/check-groups`, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${accessToken}`,
|
||||||
|
Accept: "application/json",
|
||||||
|
"X-Checkly-Account": accountId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
groups: data.map((g: ChecklyGroup) => ({
|
||||||
|
name: g.name,
|
||||||
|
groupId: g.id,
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
groups: []
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return list of Qovery Orgs for a specific user
|
* Return list of Qovery Orgs for a specific user
|
||||||
* @param req
|
* @param req
|
||||||
@ -357,13 +411,14 @@ export const getIntegrationAuthQoveryOrgs = async (req: Request, res: Response)
|
|||||||
|
|
||||||
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
||||||
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
||||||
integrationAuthId: new ObjectId(integrationAuthId)
|
integrationAuthId: new Types.ObjectId(integrationAuthId)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: integrationAuth.workspace
|
||||||
});
|
});
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
|
||||||
req.user._id,
|
|
||||||
integrationAuth.workspace.toString()
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
||||||
@ -409,13 +464,14 @@ export const getIntegrationAuthQoveryProjects = async (req: Request, res: Respon
|
|||||||
|
|
||||||
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
||||||
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
||||||
integrationAuthId: new ObjectId(integrationAuthId)
|
integrationAuthId: new Types.ObjectId(integrationAuthId)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: integrationAuth.workspace
|
||||||
});
|
});
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
|
||||||
req.user._id,
|
|
||||||
integrationAuth.workspace.toString()
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
||||||
@ -470,13 +526,14 @@ export const getIntegrationAuthQoveryEnvironments = async (req: Request, res: Re
|
|||||||
|
|
||||||
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
||||||
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
||||||
integrationAuthId: new ObjectId(integrationAuthId)
|
integrationAuthId: new Types.ObjectId(integrationAuthId)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: integrationAuth.workspace
|
||||||
});
|
});
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
|
||||||
req.user._id,
|
|
||||||
integrationAuth.workspace.toString()
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
||||||
@ -531,13 +588,14 @@ export const getIntegrationAuthQoveryApps = async (req: Request, res: Response)
|
|||||||
|
|
||||||
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
||||||
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
||||||
integrationAuthId: new ObjectId(integrationAuthId)
|
integrationAuthId: new Types.ObjectId(integrationAuthId)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: integrationAuth.workspace
|
||||||
});
|
});
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
|
||||||
req.user._id,
|
|
||||||
integrationAuth.workspace.toString()
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
||||||
@ -592,13 +650,14 @@ export const getIntegrationAuthQoveryContainers = async (req: Request, res: Resp
|
|||||||
|
|
||||||
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
||||||
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
||||||
integrationAuthId: new ObjectId(integrationAuthId)
|
integrationAuthId: new Types.ObjectId(integrationAuthId)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: integrationAuth.workspace
|
||||||
});
|
});
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
|
||||||
req.user._id,
|
|
||||||
integrationAuth.workspace.toString()
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
||||||
@ -653,13 +712,14 @@ export const getIntegrationAuthQoveryJobs = async (req: Request, res: Response)
|
|||||||
|
|
||||||
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
||||||
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
||||||
integrationAuthId: new ObjectId(integrationAuthId)
|
integrationAuthId: new Types.ObjectId(integrationAuthId)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: integrationAuth.workspace
|
||||||
});
|
});
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
|
||||||
req.user._id,
|
|
||||||
integrationAuth.workspace.toString()
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
||||||
@ -715,13 +775,14 @@ export const getIntegrationAuthRailwayEnvironments = async (req: Request, res: R
|
|||||||
|
|
||||||
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
||||||
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
||||||
integrationAuthId: new ObjectId(integrationAuthId)
|
integrationAuthId: new Types.ObjectId(integrationAuthId)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: integrationAuth.workspace
|
||||||
});
|
});
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
|
||||||
req.user._id,
|
|
||||||
integrationAuth.workspace.toString()
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
||||||
@ -808,13 +869,14 @@ export const getIntegrationAuthRailwayServices = async (req: Request, res: Respo
|
|||||||
|
|
||||||
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
||||||
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
||||||
integrationAuthId: new ObjectId(integrationAuthId)
|
integrationAuthId: new Types.ObjectId(integrationAuthId)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: integrationAuth.workspace
|
||||||
});
|
});
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
|
||||||
req.user._id,
|
|
||||||
integrationAuth.workspace.toString()
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
||||||
@ -932,13 +994,14 @@ export const getIntegrationAuthBitBucketWorkspaces = async (req: Request, res: R
|
|||||||
|
|
||||||
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
||||||
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
||||||
integrationAuthId: new ObjectId(integrationAuthId)
|
integrationAuthId: new Types.ObjectId(integrationAuthId)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: integrationAuth.workspace
|
||||||
});
|
});
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
|
||||||
req.user._id,
|
|
||||||
integrationAuth.workspace.toString()
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
||||||
@ -988,13 +1051,14 @@ export const getIntegrationAuthNorthflankSecretGroups = async (req: Request, res
|
|||||||
|
|
||||||
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
||||||
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
||||||
integrationAuthId: new ObjectId(integrationAuthId)
|
integrationAuthId: new Types.ObjectId(integrationAuthId)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: integrationAuth.workspace
|
||||||
});
|
});
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
|
||||||
req.user._id,
|
|
||||||
integrationAuth.workspace.toString()
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
||||||
@ -1076,13 +1140,14 @@ export const getIntegrationAuthTeamCityBuildConfigs = async (req: Request, res:
|
|||||||
|
|
||||||
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
||||||
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
||||||
integrationAuthId: new ObjectId(integrationAuthId)
|
integrationAuthId: new Types.ObjectId(integrationAuthId)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: integrationAuth.workspace
|
||||||
});
|
});
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
|
||||||
req.user._id,
|
|
||||||
integrationAuth.workspace.toString()
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
||||||
@ -1132,26 +1197,78 @@ export const getIntegrationAuthTeamCityBuildConfigs = async (req: Request, res:
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete all integration authorizations and integrations for workspace with id [workspaceId]
|
||||||
|
* with integration name [integration]
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const deleteIntegrationAuths = async (req: Request, res: Response) => {
|
||||||
|
const {
|
||||||
|
query: { integration, workspaceId }
|
||||||
|
} = await validateRequest(reqValidator.DeleteIntegrationAuthsV1, req);
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Delete,
|
||||||
|
ProjectPermissionSub.Integrations
|
||||||
|
);
|
||||||
|
|
||||||
|
const integrationAuths = await IntegrationAuth.deleteMany({
|
||||||
|
integration,
|
||||||
|
workspace: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
const integrations = await Integration.deleteMany({
|
||||||
|
integration,
|
||||||
|
workspace: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
await EEAuditLogService.createAuditLog(
|
||||||
|
req.authData,
|
||||||
|
{
|
||||||
|
type: EventType.UNAUTHORIZE_INTEGRATION,
|
||||||
|
metadata: {
|
||||||
|
integration
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
integrationAuths,
|
||||||
|
integrations
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete integration authorization with id [integrationAuthId]
|
* Delete integration authorization with id [integrationAuthId]
|
||||||
* @param req
|
* @param req
|
||||||
* @param res
|
* @param res
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const deleteIntegrationAuth = async (req: Request, res: Response) => {
|
export const deleteIntegrationAuthById = async (req: Request, res: Response) => {
|
||||||
const {
|
const {
|
||||||
params: { integrationAuthId }
|
params: { integrationAuthId }
|
||||||
} = await validateRequest(reqValidator.DeleteIntegrationAuthV1, req);
|
} = await validateRequest(reqValidator.DeleteIntegrationAuthV1, req);
|
||||||
|
|
||||||
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
// TODO(akhilmhdh): remove class -> static function path and makes these into reusable independent functions
|
||||||
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
const { integrationAuth, accessToken } = await getIntegrationAuthAccessHelper({
|
||||||
integrationAuthId: new ObjectId(integrationAuthId)
|
integrationAuthId: new Types.ObjectId(integrationAuthId)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: integrationAuth.workspace
|
||||||
});
|
});
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
|
||||||
req.user._id,
|
|
||||||
integrationAuth.workspace.toString()
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Delete,
|
ProjectPermissionActions.Delete,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
@ -13,7 +13,7 @@ import * as reqValidator from "../../validation/integration";
|
|||||||
import {
|
import {
|
||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
ProjectPermissionSub,
|
ProjectPermissionSub,
|
||||||
getUserProjectPermissions
|
getAuthDataProjectPermissions
|
||||||
} from "../../ee/services/ProjectRoleService";
|
} from "../../ee/services/ProjectRoleService";
|
||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
@ -52,10 +52,11 @@ export const createIntegration = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
if (!integrationAuth) throw BadRequestError({ message: "Integration auth not found" });
|
if (!integrationAuth) throw BadRequestError({ message: "Integration auth not found" });
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
req.user._id,
|
authData: req.authData,
|
||||||
integrationAuth.workspace._id.toString()
|
workspaceId: integrationAuth.workspace._id
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Create,
|
ProjectPermissionActions.Create,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
||||||
@ -164,10 +165,11 @@ export const updateIntegration = async (req: Request, res: Response) => {
|
|||||||
const integration = await Integration.findById(integrationId);
|
const integration = await Integration.findById(integrationId);
|
||||||
if (!integration) throw BadRequestError({ message: "Integration not found" });
|
if (!integration) throw BadRequestError({ message: "Integration not found" });
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
req.user._id,
|
authData: req.authData,
|
||||||
integration.workspace.toString()
|
workspaceId: integration.workspace
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Edit,
|
ProjectPermissionActions.Edit,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
||||||
@ -234,10 +236,11 @@ export const deleteIntegration = async (req: Request, res: Response) => {
|
|||||||
const integration = await Integration.findById(integrationId);
|
const integration = await Integration.findById(integrationId);
|
||||||
if (!integration) throw BadRequestError({ message: "Integration not found" });
|
if (!integration) throw BadRequestError({ message: "Integration not found" });
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
req.user._id,
|
authData: req.authData,
|
||||||
integration.workspace.toString()
|
workspaceId: integration.workspace
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Delete,
|
ProjectPermissionActions.Delete,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
||||||
@ -249,6 +252,21 @@ export const deleteIntegration = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
if (!deletedIntegration) throw new Error("Failed to find integration");
|
if (!deletedIntegration) throw new Error("Failed to find integration");
|
||||||
|
|
||||||
|
const numOtherIntegrationsUsingSameAuth = await Integration.countDocuments({
|
||||||
|
integrationAuth: deletedIntegration.integrationAuth,
|
||||||
|
_id: {
|
||||||
|
$nin: [deletedIntegration._id]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (numOtherIntegrationsUsingSameAuth === 0) {
|
||||||
|
// no other integrations are using the same integration auth
|
||||||
|
// -> delete integration auth associated with the integration being deleted
|
||||||
|
await IntegrationAuth.deleteOne({
|
||||||
|
_id: deletedIntegration.integrationAuth
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
await EEAuditLogService.createAuditLog(
|
await EEAuditLogService.createAuditLog(
|
||||||
req.authData,
|
req.authData,
|
||||||
{
|
{
|
||||||
@ -285,7 +303,11 @@ export const manualSync = async (req: Request, res: Response) => {
|
|||||||
body: { workspaceId, environment }
|
body: { workspaceId, environment }
|
||||||
} = await validateRequest(reqValidator.ManualSyncV1, req);
|
} = await validateRequest(reqValidator.ManualSyncV1, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Edit,
|
ProjectPermissionActions.Edit,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
@ -9,7 +9,7 @@ import * as reqValidator from "../../validation/key";
|
|||||||
import {
|
import {
|
||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
ProjectPermissionSub,
|
ProjectPermissionSub,
|
||||||
getUserProjectPermissions
|
getAuthDataProjectPermissions
|
||||||
} from "../../ee/services/ProjectRoleService";
|
} from "../../ee/services/ProjectRoleService";
|
||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
@ -26,7 +26,11 @@ export const uploadKey = async (req: Request, res: Response) => {
|
|||||||
body: { key }
|
body: { key }
|
||||||
} = await validateRequest(reqValidator.UploadKeyV1, req);
|
} = await validateRequest(reqValidator.UploadKeyV1, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Edit,
|
ProjectPermissionActions.Edit,
|
||||||
ProjectPermissionSub.Member
|
ProjectPermissionSub.Member
|
@ -4,15 +4,15 @@ import { IUser, Key, Membership, MembershipOrg, User, Workspace } from "../../mo
|
|||||||
import { EventType, Role } from "../../ee/models";
|
import { EventType, Role } from "../../ee/models";
|
||||||
import { deleteMembership as deleteMember, findMembership } from "../../helpers/membership";
|
import { deleteMembership as deleteMember, findMembership } from "../../helpers/membership";
|
||||||
import { sendMail } from "../../helpers/nodemailer";
|
import { sendMail } from "../../helpers/nodemailer";
|
||||||
import { ACCEPTED, ADMIN, CUSTOM, MEMBER, VIEWER } from "../../variables";
|
import { ACCEPTED, ADMIN, CUSTOM, MEMBER, NO_ACCESS, VIEWER } from "../../variables";
|
||||||
import { getSiteURL } from "../../config";
|
import { getSiteURL } from "../../config";
|
||||||
import { EEAuditLogService } from "../../ee/services";
|
import { EEAuditLogService, EELicenseService } from "../../ee/services";
|
||||||
import { validateRequest } from "../../helpers/validation";
|
import { validateRequest } from "../../helpers/validation";
|
||||||
import * as reqValidator from "../../validation/membership";
|
import * as reqValidator from "../../validation/membership";
|
||||||
import {
|
import {
|
||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
ProjectPermissionSub,
|
ProjectPermissionSub,
|
||||||
getUserProjectPermissions
|
getAuthDataProjectPermissions
|
||||||
} from "../../ee/services/ProjectRoleService";
|
} from "../../ee/services/ProjectRoleService";
|
||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
import { BadRequestError } from "../../utils/errors";
|
import { BadRequestError } from "../../utils/errors";
|
||||||
@ -64,10 +64,11 @@ export const deleteMembership = async (req: Request, res: Response) => {
|
|||||||
throw new Error("Failed to delete workspace membership that doesn't exist");
|
throw new Error("Failed to delete workspace membership that doesn't exist");
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
req.user._id,
|
authData: req.authData,
|
||||||
membershipToDelete.workspace.toString()
|
workspaceId: membershipToDelete.workspace
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Delete,
|
ProjectPermissionActions.Delete,
|
||||||
ProjectPermissionSub.Member
|
ProjectPermissionSub.Member
|
||||||
@ -118,16 +119,17 @@ export const changeMembershipRole = async (req: Request, res: Response) => {
|
|||||||
throw new Error("Failed to find membership to change role");
|
throw new Error("Failed to find membership to change role");
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
req.user._id,
|
authData: req.authData,
|
||||||
membershipToChangeRole.workspace.toString()
|
workspaceId: membershipToChangeRole.workspace
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Edit,
|
ProjectPermissionActions.Edit,
|
||||||
ProjectPermissionSub.Member
|
ProjectPermissionSub.Member
|
||||||
);
|
);
|
||||||
|
|
||||||
const isCustomRole = ![ADMIN, MEMBER, VIEWER].includes(role);
|
const isCustomRole = ![ADMIN, MEMBER, VIEWER, NO_ACCESS].includes(role);
|
||||||
if (isCustomRole) {
|
if (isCustomRole) {
|
||||||
const wsRole = await Role.findOne({
|
const wsRole = await Role.findOne({
|
||||||
slug: role,
|
slug: role,
|
||||||
@ -135,6 +137,13 @@ export const changeMembershipRole = async (req: Request, res: Response) => {
|
|||||||
workspace: membershipToChangeRole.workspace
|
workspace: membershipToChangeRole.workspace
|
||||||
});
|
});
|
||||||
if (!wsRole) throw BadRequestError({ message: "Role not found" });
|
if (!wsRole) throw BadRequestError({ message: "Role not found" });
|
||||||
|
|
||||||
|
const plan = await EELicenseService.getPlan(wsRole.organization);
|
||||||
|
|
||||||
|
if (!plan.rbac) return res.status(400).send({
|
||||||
|
message: "Failed to assign custom role due to RBAC restriction. Upgrade plan to assign custom role to member."
|
||||||
|
});
|
||||||
|
|
||||||
const membership = await Membership.findByIdAndUpdate(membershipId, {
|
const membership = await Membership.findByIdAndUpdate(membershipId, {
|
||||||
role: CUSTOM,
|
role: CUSTOM,
|
||||||
customRole: wsRole
|
customRole: wsRole
|
||||||
@ -191,7 +200,12 @@ export const inviteUserToWorkspace = async (req: Request, res: Response) => {
|
|||||||
params: { workspaceId },
|
params: { workspaceId },
|
||||||
body: { email }
|
body: { email }
|
||||||
} = await validateRequest(InviteUserToWorkspaceV1, req);
|
} = await validateRequest(InviteUserToWorkspaceV1, req);
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Create,
|
ProjectPermissionActions.Create,
|
||||||
ProjectPermissionSub.Member
|
ProjectPermissionSub.Member
|
@ -21,7 +21,7 @@ import { validateRequest } from "../../helpers/validation";
|
|||||||
import {
|
import {
|
||||||
OrgPermissionActions,
|
OrgPermissionActions,
|
||||||
OrgPermissionSubjects,
|
OrgPermissionSubjects,
|
||||||
getUserOrgPermissions
|
getAuthDataOrgPermissions
|
||||||
} from "../../ee/services/RoleService";
|
} from "../../ee/services/RoleService";
|
||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
@ -45,10 +45,11 @@ export const deleteMembershipOrg = async (req: Request, _res: Response) => {
|
|||||||
throw new Error("Failed to delete organization membership that doesn't exist");
|
throw new Error("Failed to delete organization membership that doesn't exist");
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission, membership: membershipOrg } = await getUserOrgPermissions(
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
req.user._id,
|
authData: req.authData,
|
||||||
membershipOrgToDelete.organization.toString()
|
organizationId: membershipOrgToDelete.organization
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Delete,
|
OrgPermissionActions.Delete,
|
||||||
OrgPermissionSubjects.Member
|
OrgPermissionSubjects.Member
|
||||||
@ -60,7 +61,7 @@ export const deleteMembershipOrg = async (req: Request, _res: Response) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await updateSubscriptionOrgQuantity({
|
await updateSubscriptionOrgQuantity({
|
||||||
organizationId: membershipOrg.organization.toString()
|
organizationId: membershipOrgToDelete.organization.toString()
|
||||||
});
|
});
|
||||||
|
|
||||||
return membershipOrgToDelete;
|
return membershipOrgToDelete;
|
||||||
@ -96,7 +97,11 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => {
|
|||||||
body: { inviteeEmail, organizationId }
|
body: { inviteeEmail, organizationId }
|
||||||
} = await validateRequest(reqValidator.InviteUserToOrgv1, req);
|
} = await validateRequest(reqValidator.InviteUserToOrgv1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Create,
|
OrgPermissionActions.Create,
|
||||||
OrgPermissionSubjects.Member
|
OrgPermissionSubjects.Member
|
@ -1,4 +1,5 @@
|
|||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
|
import { Types } from "mongoose";
|
||||||
import {
|
import {
|
||||||
IncidentContactOrg,
|
IncidentContactOrg,
|
||||||
Membership,
|
Membership,
|
||||||
@ -14,7 +15,7 @@ import { ACCEPTED } from "../../variables";
|
|||||||
import {
|
import {
|
||||||
OrgPermissionActions,
|
OrgPermissionActions,
|
||||||
OrgPermissionSubjects,
|
OrgPermissionSubjects,
|
||||||
getUserOrgPermissions
|
getAuthDataOrgPermissions
|
||||||
} from "../../ee/services/RoleService";
|
} from "../../ee/services/RoleService";
|
||||||
import { OrganizationNotFoundError } from "../../utils/errors";
|
import { OrganizationNotFoundError } from "../../utils/errors";
|
||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
@ -44,7 +45,10 @@ export const getOrganization = async (req: Request, res: Response) => {
|
|||||||
} = await validateRequest(reqValidator.GetOrgv1, req);
|
} = await validateRequest(reqValidator.GetOrgv1, req);
|
||||||
|
|
||||||
// ensure user has membership
|
// ensure user has membership
|
||||||
await getUserOrgPermissions(req.user._id, organizationId);
|
await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
})
|
||||||
|
|
||||||
const organization = await Organization.findById(organizationId);
|
const organization = await Organization.findById(organizationId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
@ -69,7 +73,11 @@ export const getOrganizationMembers = async (req: Request, res: Response) => {
|
|||||||
params: { organizationId }
|
params: { organizationId }
|
||||||
} = await validateRequest(reqValidator.GetOrgMembersv1, req);
|
} = await validateRequest(reqValidator.GetOrgMembersv1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Read,
|
OrgPermissionActions.Read,
|
||||||
OrgPermissionSubjects.Member
|
OrgPermissionSubjects.Member
|
||||||
@ -95,7 +103,10 @@ export const getOrganizationWorkspaces = async (req: Request, res: Response) =>
|
|||||||
params: { organizationId }
|
params: { organizationId }
|
||||||
} = await validateRequest(reqValidator.GetOrgWorkspacesv1, req);
|
} = await validateRequest(reqValidator.GetOrgWorkspacesv1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
})
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Read,
|
OrgPermissionActions.Read,
|
||||||
OrgPermissionSubjects.Workspace
|
OrgPermissionSubjects.Workspace
|
||||||
@ -137,7 +148,10 @@ export const changeOrganizationName = async (req: Request, res: Response) => {
|
|||||||
body: { name }
|
body: { name }
|
||||||
} = await validateRequest(reqValidator.ChangeOrgNamev1, req);
|
} = await validateRequest(reqValidator.ChangeOrgNamev1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Edit,
|
OrgPermissionActions.Edit,
|
||||||
OrgPermissionSubjects.Settings
|
OrgPermissionSubjects.Settings
|
||||||
@ -172,7 +186,10 @@ export const getOrganizationIncidentContacts = async (req: Request, res: Respons
|
|||||||
params: { organizationId }
|
params: { organizationId }
|
||||||
} = await validateRequest(reqValidator.GetOrgIncidentContactv1, req);
|
} = await validateRequest(reqValidator.GetOrgIncidentContactv1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Read,
|
OrgPermissionActions.Read,
|
||||||
OrgPermissionSubjects.IncidentAccount
|
OrgPermissionSubjects.IncidentAccount
|
||||||
@ -199,7 +216,10 @@ export const addOrganizationIncidentContact = async (req: Request, res: Response
|
|||||||
body: { email }
|
body: { email }
|
||||||
} = await validateRequest(reqValidator.CreateOrgIncideContact, req);
|
} = await validateRequest(reqValidator.CreateOrgIncideContact, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Create,
|
OrgPermissionActions.Create,
|
||||||
OrgPermissionSubjects.IncidentAccount
|
OrgPermissionSubjects.IncidentAccount
|
||||||
@ -228,7 +248,10 @@ export const deleteOrganizationIncidentContact = async (req: Request, res: Respo
|
|||||||
body: { email }
|
body: { email }
|
||||||
} = await validateRequest(reqValidator.DelOrgIncideContact, req);
|
} = await validateRequest(reqValidator.DelOrgIncideContact, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Delete,
|
OrgPermissionActions.Delete,
|
||||||
OrgPermissionSubjects.IncidentAccount
|
OrgPermissionSubjects.IncidentAccount
|
||||||
@ -257,7 +280,10 @@ export const createOrganizationPortalSession = async (req: Request, res: Respons
|
|||||||
params: { organizationId }
|
params: { organizationId }
|
||||||
} = await validateRequest(reqValidator.GetOrgPlanBillingInfov1, req);
|
} = await validateRequest(reqValidator.GetOrgPlanBillingInfov1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Edit,
|
OrgPermissionActions.Edit,
|
||||||
OrgPermissionSubjects.Billing
|
OrgPermissionSubjects.Billing
|
||||||
@ -321,7 +347,10 @@ export const getOrganizationMembersAndTheirWorkspaces = async (req: Request, res
|
|||||||
params: { organizationId }
|
params: { organizationId }
|
||||||
} = await validateRequest(reqValidator.GetOrgMembersv1, req);
|
} = await validateRequest(reqValidator.GetOrgMembersv1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Read,
|
OrgPermissionActions.Read,
|
||||||
OrgPermissionSubjects.Member
|
OrgPermissionSubjects.Member
|
@ -1,4 +1,6 @@
|
|||||||
|
|
||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
|
import { Types } from "mongoose";
|
||||||
import { isValidScope } from "../../helpers";
|
import { isValidScope } from "../../helpers";
|
||||||
import { Folder, IServiceTokenData, SecretImport, ServiceTokenData } from "../../models";
|
import { Folder, IServiceTokenData, SecretImport, ServiceTokenData } from "../../models";
|
||||||
import { getAllImportedSecrets } from "../../services/SecretImportService";
|
import { getAllImportedSecrets } from "../../services/SecretImportService";
|
||||||
@ -15,14 +17,14 @@ import * as reqValidator from "../../validation/secretImports";
|
|||||||
import {
|
import {
|
||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
ProjectPermissionSub,
|
ProjectPermissionSub,
|
||||||
getUserProjectPermissions
|
getAuthDataProjectPermissions
|
||||||
} from "../../ee/services/ProjectRoleService";
|
} from "../../ee/services/ProjectRoleService";
|
||||||
import { ForbiddenError, subject } from "@casl/ability";
|
import { ForbiddenError, subject } from "@casl/ability";
|
||||||
|
|
||||||
export const createSecretImp = async (req: Request, res: Response) => {
|
export const createSecretImp = async (req: Request, res: Response) => {
|
||||||
/*
|
/*
|
||||||
#swagger.summary = 'Create secret import'
|
#swagger.summary = 'Create secret import'
|
||||||
#swagger.description = 'Create a new secret import for a specified workspace and environment'
|
#swagger.description = 'Create secret import'
|
||||||
|
|
||||||
#swagger.requestBody = {
|
#swagger.requestBody = {
|
||||||
content: {
|
content: {
|
||||||
@ -32,36 +34,36 @@ export const createSecretImp = async (req: Request, res: Response) => {
|
|||||||
"properties": {
|
"properties": {
|
||||||
"workspaceId": {
|
"workspaceId": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "ID of the workspace where the secret import will be created",
|
"description": "ID of workspace where to create secret import",
|
||||||
"example": "someWorkspaceId"
|
"example": "someWorkspaceId"
|
||||||
},
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Environment to import to",
|
"description": "Slug of environment where to create secret import",
|
||||||
"example": "production"
|
"example": "dev"
|
||||||
},
|
},
|
||||||
"folderId": {
|
"directory": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Folder ID. Use root for the root folder.",
|
"description": "Path where to create secret import like / or /foo/bar. Default is /",
|
||||||
"example": "my_folder"
|
"example": "/foo/bar"
|
||||||
},
|
},
|
||||||
"secretImport": {
|
"secretImport": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"environment": {
|
"environment": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Import from environment",
|
"description": "Slug of environment to import from",
|
||||||
"example": "development"
|
"example": "development"
|
||||||
},
|
},
|
||||||
"secretPath": {
|
"secretPath": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Import from secret path",
|
"description": "Path where to import from like / or /foo/bar.",
|
||||||
"example": "/user/oauth"
|
"example": "/user/oauth"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["workspaceId", "environment", "folderName"]
|
"required": ["workspaceId", "environment", "directory", "secretImport"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,11 +107,21 @@ export const createSecretImp = async (req: Request, res: Response) => {
|
|||||||
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Create,
|
ProjectPermissionActions.Create,
|
||||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath: directory })
|
subject(ProjectPermissionSub.Secrets, { environment, secretPath: directory })
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
subject(ProjectPermissionSub.Secrets, { environment: secretImport.environment, secretPath: secretImport.secretPath })
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const folders = await Folder.findOne({
|
const folders = await Folder.findOne({
|
||||||
@ -206,12 +218,12 @@ export const createSecretImp = async (req: Request, res: Response) => {
|
|||||||
*/
|
*/
|
||||||
export const updateSecretImport = async (req: Request, res: Response) => {
|
export const updateSecretImport = async (req: Request, res: Response) => {
|
||||||
/*
|
/*
|
||||||
#swagger.summary = 'Update a secret import'
|
#swagger.summary = 'Update secret import'
|
||||||
#swagger.description = 'Updates an existing secret import based on the provided ID and new import details'
|
#swagger.description = 'Update secret import'
|
||||||
|
|
||||||
#swagger.parameters['id'] = {
|
#swagger.parameters['id'] = {
|
||||||
in: 'path',
|
in: 'path',
|
||||||
description: 'ID of the secret import to be updated',
|
description: 'ID of secret import to update',
|
||||||
required: true,
|
required: true,
|
||||||
type: 'string',
|
type: 'string',
|
||||||
example: 'import12345'
|
example: 'import12345'
|
||||||
@ -225,19 +237,19 @@ export const updateSecretImport = async (req: Request, res: Response) => {
|
|||||||
"properties": {
|
"properties": {
|
||||||
"secretImports": {
|
"secretImports": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"description": "List of new secret imports",
|
"description": "List of secret imports to update to",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"environment": {
|
"environment": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Environment of the secret import",
|
"description": "Slug of environment to import from",
|
||||||
"example": "production"
|
"example": "dev"
|
||||||
},
|
},
|
||||||
"secretPath": {
|
"secretPath": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Path of the secret import",
|
"description": "Path where to import secrets from like / or /foo/bar",
|
||||||
"example": "/path/to/secret"
|
"example": "/foo/bar"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["environment", "secretPath"]
|
"required": ["environment", "secretPath"]
|
||||||
@ -313,10 +325,11 @@ export const updateSecretImport = async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// non token entry check
|
// non token entry check
|
||||||
const { permission } = await getUserProjectPermissions(
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
req.user._id,
|
authData: req.authData,
|
||||||
importSecDoc.workspace.toString()
|
workspaceId: importSecDoc.workspace
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Edit,
|
ProjectPermissionActions.Edit,
|
||||||
subject(ProjectPermissionSub.Secrets, {
|
subject(ProjectPermissionSub.Secrets, {
|
||||||
@ -324,6 +337,13 @@ export const updateSecretImport = async (req: Request, res: Response) => {
|
|||||||
secretPath
|
secretPath
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
secretImports.forEach(({ environment, secretPath }) => {
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
||||||
|
);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const orderBefore = importSecDoc.imports;
|
const orderBefore = importSecDoc.imports;
|
||||||
@ -364,7 +384,7 @@ export const deleteSecretImport = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
#swagger.parameters['id'] = {
|
#swagger.parameters['id'] = {
|
||||||
in: 'path',
|
in: 'path',
|
||||||
description: 'ID of the secret import',
|
description: 'ID of parent secret import document from which to delete secret import',
|
||||||
required: true,
|
required: true,
|
||||||
type: 'string',
|
type: 'string',
|
||||||
example: '12345abcde'
|
example: '12345abcde'
|
||||||
@ -378,12 +398,12 @@ export const deleteSecretImport = async (req: Request, res: Response) => {
|
|||||||
"properties": {
|
"properties": {
|
||||||
"secretImportEnv": {
|
"secretImportEnv": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Import from environment",
|
"description": "Slug of environment of import to delete",
|
||||||
"example": "someWorkspaceId"
|
"example": "someWorkspaceId"
|
||||||
},
|
},
|
||||||
"secretImportPath": {
|
"secretImportPath": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Import from secret path",
|
"description": "Path like / or /foo/bar of import to delete",
|
||||||
"example": "production"
|
"example": "production"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -442,10 +462,11 @@ export const deleteSecretImport = async (req: Request, res: Response) => {
|
|||||||
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const { permission } = await getUserProjectPermissions(
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
req.user._id,
|
authData: req.authData,
|
||||||
importSecDoc.workspace.toString()
|
workspaceId: importSecDoc.workspace
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Delete,
|
ProjectPermissionActions.Delete,
|
||||||
subject(ProjectPermissionSub.Secrets, {
|
subject(ProjectPermissionSub.Secrets, {
|
||||||
@ -489,12 +510,12 @@ export const deleteSecretImport = async (req: Request, res: Response) => {
|
|||||||
*/
|
*/
|
||||||
export const getSecretImports = async (req: Request, res: Response) => {
|
export const getSecretImports = async (req: Request, res: Response) => {
|
||||||
/*
|
/*
|
||||||
#swagger.summary = 'Retrieve secret imports'
|
#swagger.summary = 'Get secret imports'
|
||||||
#swagger.description = 'Fetches the secret imports based on the workspaceId, environment, and folderId'
|
#swagger.description = 'Get secret imports'
|
||||||
|
|
||||||
#swagger.parameters['workspaceId'] = {
|
#swagger.parameters['workspaceId'] = {
|
||||||
in: 'query',
|
in: 'query',
|
||||||
description: 'ID of the workspace of secret imports to get',
|
description: 'ID of workspace where to get secret imports from',
|
||||||
required: true,
|
required: true,
|
||||||
type: 'string',
|
type: 'string',
|
||||||
example: 'workspace12345'
|
example: 'workspace12345'
|
||||||
@ -502,15 +523,15 @@ export const getSecretImports = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
#swagger.parameters['environment'] = {
|
#swagger.parameters['environment'] = {
|
||||||
in: 'query',
|
in: 'query',
|
||||||
description: 'Environment of secret imports to get',
|
description: 'Slug of environment where to get secret imports from',
|
||||||
required: true,
|
required: true,
|
||||||
type: 'string',
|
type: 'string',
|
||||||
example: 'production'
|
example: 'production'
|
||||||
}
|
}
|
||||||
|
|
||||||
#swagger.parameters['folderId'] = {
|
#swagger.parameters['directory'] = {
|
||||||
in: 'query',
|
in: 'query',
|
||||||
description: 'ID of the folder containing the secret imports. Default: root',
|
description: 'Path where to get secret imports from like / or /foo/bar. Default is /',
|
||||||
required: false,
|
required: false,
|
||||||
type: 'string',
|
type: 'string',
|
||||||
example: 'folder12345'
|
example: 'folder12345'
|
||||||
@ -524,8 +545,7 @@ export const getSecretImports = async (req: Request, res: Response) => {
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"secretImport": {
|
"secretImport": {
|
||||||
"type": "object",
|
$ref: '#/definitions/SecretImport'
|
||||||
"description": "Details of a secret import"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -551,7 +571,11 @@ export const getSecretImports = async (req: Request, res: Response) => {
|
|||||||
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
subject(ProjectPermissionSub.Secrets, {
|
subject(ProjectPermissionSub.Secrets, {
|
||||||
@ -605,7 +629,11 @@ export const getAllSecretsFromImport = async (req: Request, res: Response) => {
|
|||||||
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
subject(ProjectPermissionSub.Secrets, {
|
subject(ProjectPermissionSub.Secrets, {
|
||||||
@ -658,10 +686,11 @@ export const getAllSecretsFromImport = async (req: Request, res: Response) => {
|
|||||||
permissionCheckFn = (env: string, secPath: string) =>
|
permissionCheckFn = (env: string, secPath: string) =>
|
||||||
isValidScope(req.authData.authPayload as IServiceTokenData, env, secPath);
|
isValidScope(req.authData.authPayload as IServiceTokenData, env, secPath);
|
||||||
} else {
|
} else {
|
||||||
const { permission } = await getUserProjectPermissions(
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
req.user._id,
|
authData: req.authData,
|
||||||
importSecDoc.workspace.toString()
|
workspaceId: importSecDoc.workspace
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
subject(ProjectPermissionSub.Secrets, {
|
subject(ProjectPermissionSub.Secrets, {
|
@ -21,7 +21,7 @@ import * as reqValidator from "../../validation/secretScanning";
|
|||||||
import {
|
import {
|
||||||
OrgPermissionActions,
|
OrgPermissionActions,
|
||||||
OrgPermissionSubjects,
|
OrgPermissionSubjects,
|
||||||
getUserOrgPermissions
|
getAuthDataOrgPermissions
|
||||||
} from "../../ee/services/RoleService";
|
} from "../../ee/services/RoleService";
|
||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
@ -38,7 +38,10 @@ export const createInstallationSession = async (req: Request, res: Response) =>
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Create,
|
OrgPermissionActions.Create,
|
||||||
OrgPermissionSubjects.SecretScanning
|
OrgPermissionSubjects.SecretScanning
|
||||||
@ -71,10 +74,11 @@ export const linkInstallationToOrganization = async (req: Request, res: Response
|
|||||||
throw UnauthorizedRequestError();
|
throw UnauthorizedRequestError();
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
req.user._id,
|
authData: req.authData,
|
||||||
installationSession.organization.toString()
|
organizationId: installationSession.organization
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Edit,
|
OrgPermissionActions.Edit,
|
||||||
OrgPermissionSubjects.SecretScanning
|
OrgPermissionSubjects.SecretScanning
|
||||||
@ -142,7 +146,10 @@ export const getRisksForOrganization = async (req: Request, res: Response) => {
|
|||||||
params: { organizationId }
|
params: { organizationId }
|
||||||
} = await validateRequest(reqValidator.GetOrgRisksv1, req);
|
} = await validateRequest(reqValidator.GetOrgRisksv1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Read,
|
OrgPermissionActions.Read,
|
||||||
OrgPermissionSubjects.SecretScanning
|
OrgPermissionSubjects.SecretScanning
|
||||||
@ -162,7 +169,10 @@ export const updateRisksStatus = async (req: Request, res: Response) => {
|
|||||||
body: { status }
|
body: { status }
|
||||||
} = await validateRequest(reqValidator.UpdateRiskStatusv1, req);
|
} = await validateRequest(reqValidator.UpdateRiskStatusv1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Edit,
|
OrgPermissionActions.Edit,
|
||||||
OrgPermissionSubjects.SecretScanning
|
OrgPermissionSubjects.SecretScanning
|
@ -17,7 +17,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
ProjectPermissionSub,
|
ProjectPermissionSub,
|
||||||
getUserProjectPermissions
|
getAuthDataProjectPermissions
|
||||||
} from "../../ee/services/ProjectRoleService";
|
} from "../../ee/services/ProjectRoleService";
|
||||||
import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors";
|
import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors";
|
||||||
import * as reqValidator from "../../validation/folders";
|
import * as reqValidator from "../../validation/folders";
|
||||||
@ -27,11 +27,12 @@ const ERR_FOLDER_NOT_FOUND = BadRequestError({ message: "The folder doesn't exis
|
|||||||
// verify workspace id/environment
|
// verify workspace id/environment
|
||||||
export const createFolder = async (req: Request, res: Response) => {
|
export const createFolder = async (req: Request, res: Response) => {
|
||||||
/*
|
/*
|
||||||
#swagger.summary = 'Create a folder'
|
#swagger.summary = 'Create folder'
|
||||||
#swagger.description = 'Create a new folder in a specified workspace and environment'
|
#swagger.description = 'Create folder'
|
||||||
|
|
||||||
#swagger.security = [{
|
#swagger.security = [{
|
||||||
"apiKeyAuth": []
|
"apiKeyAuth": [],
|
||||||
|
"bearerAuth": []
|
||||||
}]
|
}]
|
||||||
|
|
||||||
#swagger.requestBody = {
|
#swagger.requestBody = {
|
||||||
@ -42,23 +43,23 @@ export const createFolder = async (req: Request, res: Response) => {
|
|||||||
"properties": {
|
"properties": {
|
||||||
"workspaceId": {
|
"workspaceId": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "ID of the workspace where the folder will be created",
|
"description": "ID of the workspace where to create folder",
|
||||||
"example": "someWorkspaceId"
|
"example": "someWorkspaceId"
|
||||||
},
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Environment where the folder will reside",
|
"description": "Slug of environment where to create folder",
|
||||||
"example": "production"
|
"example": "production"
|
||||||
},
|
},
|
||||||
"folderName": {
|
"folderName": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Name of the folder to be created",
|
"description": "Name of folder to create",
|
||||||
"example": "my_folder"
|
"example": "my_folder"
|
||||||
},
|
},
|
||||||
"parentFolderId": {
|
"directory": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "ID of the parent folder under which this folder will be created. If not specified, it will be created at the root level.",
|
"description": "Path where to create folder like / or /foo/bar. Default is /",
|
||||||
"example": "someParentFolderId"
|
"example": "/foo/bar"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["workspaceId", "environment", "folderName"]
|
"required": ["workspaceId", "environment", "folderName"]
|
||||||
@ -78,14 +79,21 @@ export const createFolder = async (req: Request, res: Response) => {
|
|||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"description": "ID of folder",
|
||||||
"example": "someFolderId"
|
"example": "someFolderId"
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"description": "Name of folder",
|
||||||
"example": "my_folder"
|
"example": "my_folder"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "Version of folder",
|
||||||
|
"example": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "Details of the created folder"
|
"description": "Details of created folder"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,7 +125,11 @@ export const createFolder = async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// user check
|
// user check
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Create,
|
ProjectPermissionActions.Create,
|
||||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath: directory })
|
subject(ProjectPermissionSub.Secrets, { environment, secretPath: directory })
|
||||||
@ -219,18 +231,18 @@ export const createFolder = async (req: Request, res: Response) => {
|
|||||||
*/
|
*/
|
||||||
export const updateFolderById = async (req: Request, res: Response) => {
|
export const updateFolderById = async (req: Request, res: Response) => {
|
||||||
/*
|
/*
|
||||||
#swagger.summary = 'Update a folder by ID'
|
#swagger.summary = 'Update folder'
|
||||||
#swagger.description = 'Update the name of a folder in a specified workspace and environment by its ID'
|
#swagger.description = 'Update folder'
|
||||||
|
|
||||||
#swagger.security = [{
|
#swagger.security = [{
|
||||||
"apiKeyAuth": []
|
"apiKeyAuth": [],
|
||||||
|
"bearerAuth": []
|
||||||
}]
|
}]
|
||||||
|
|
||||||
#swagger.parameters['folderId'] = {
|
#swagger.parameters['folderName'] = {
|
||||||
"description": "ID of the folder to be updated",
|
"description": "Name of folder to update",
|
||||||
"required": true,
|
"required": true,
|
||||||
"type": "string",
|
"type": "string"
|
||||||
"in": "path"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#swagger.requestBody = {
|
#swagger.requestBody = {
|
||||||
@ -241,18 +253,23 @@ export const updateFolderById = async (req: Request, res: Response) => {
|
|||||||
"properties": {
|
"properties": {
|
||||||
"workspaceId": {
|
"workspaceId": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "ID of the workspace where the folder is located",
|
"description": "ID of workspace where to update folder",
|
||||||
"example": "someWorkspaceId"
|
"example": "someWorkspaceId"
|
||||||
},
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Environment where the folder is located",
|
"description": "Slug of environment where to update folder",
|
||||||
"example": "production"
|
"example": "production"
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "New name for the folder",
|
"description": "Name of folder to update to",
|
||||||
"example": "updated_folder_name"
|
"example": "updated_folder_name"
|
||||||
|
},
|
||||||
|
"directory": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Path where to update folder like / or /foo/bar. Default is /",
|
||||||
|
"example": "/foo/bar"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["workspaceId", "environment", "name"]
|
"required": ["workspaceId", "environment", "name"]
|
||||||
@ -269,6 +286,7 @@ export const updateFolderById = async (req: Request, res: Response) => {
|
|||||||
"properties": {
|
"properties": {
|
||||||
"message": {
|
"message": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"description": "Success message",
|
||||||
"example": "Successfully updated folder"
|
"example": "Successfully updated folder"
|
||||||
},
|
},
|
||||||
"folder": {
|
"folder": {
|
||||||
@ -276,11 +294,13 @@ export const updateFolderById = async (req: Request, res: Response) => {
|
|||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"description": "Name of updated folder",
|
||||||
"example": "updated_folder_name"
|
"example": "updated_folder_name"
|
||||||
},
|
},
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"example": "someFolderId"
|
"description": "ID of created folder",
|
||||||
|
"example": "abc123"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "Details of the updated folder"
|
"description": "Details of the updated folder"
|
||||||
@ -316,7 +336,11 @@ export const updateFolderById = async (req: Request, res: Response) => {
|
|||||||
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Edit,
|
ProjectPermissionActions.Edit,
|
||||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath: directory })
|
subject(ProjectPermissionSub.Secrets, { environment, secretPath: directory })
|
||||||
@ -387,15 +411,16 @@ export const updateFolderById = async (req: Request, res: Response) => {
|
|||||||
*/
|
*/
|
||||||
export const deleteFolder = async (req: Request, res: Response) => {
|
export const deleteFolder = async (req: Request, res: Response) => {
|
||||||
/*
|
/*
|
||||||
#swagger.summary = 'Delete a folder by ID'
|
#swagger.summary = 'Delete folder'
|
||||||
#swagger.description = 'Delete the specified folder from a specified workspace and environment using its ID'
|
#swagger.description = 'Delete folder'
|
||||||
|
|
||||||
#swagger.security = [{
|
#swagger.security = [{
|
||||||
"apiKeyAuth": []
|
"apiKeyAuth": [],
|
||||||
|
"bearerAuth": []
|
||||||
}]
|
}]
|
||||||
|
|
||||||
#swagger.parameters['folderId'] = {
|
#swagger.parameters['folderName'] = {
|
||||||
"description": "ID of the folder to be deleted",
|
"description": "Name of folder to delete",
|
||||||
"required": true,
|
"required": true,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"in": "path"
|
"in": "path"
|
||||||
@ -409,13 +434,18 @@ export const deleteFolder = async (req: Request, res: Response) => {
|
|||||||
"properties": {
|
"properties": {
|
||||||
"workspaceId": {
|
"workspaceId": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "ID of the workspace where the folder is located",
|
"description": "ID of the workspace where to delete folder",
|
||||||
"example": "someWorkspaceId"
|
"example": "someWorkspaceId"
|
||||||
},
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Environment where the folder is located",
|
"description": "Slug of environment where to delete folder",
|
||||||
"example": "production"
|
"example": "production"
|
||||||
|
},
|
||||||
|
"directory": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Path where to delete folder like / or /foo/bar. Default is /",
|
||||||
|
"example": "/foo/bar"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["workspaceId", "environment"]
|
"required": ["workspaceId", "environment"]
|
||||||
@ -432,6 +462,7 @@ export const deleteFolder = async (req: Request, res: Response) => {
|
|||||||
"properties": {
|
"properties": {
|
||||||
"message": {
|
"message": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"description": "Success message",
|
||||||
"example": "successfully deleted folders"
|
"example": "successfully deleted folders"
|
||||||
},
|
},
|
||||||
"folders": {
|
"folders": {
|
||||||
@ -441,15 +472,17 @@ export const deleteFolder = async (req: Request, res: Response) => {
|
|||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"example": "someFolderId"
|
"description": "ID of deleted folder",
|
||||||
|
"example": "abc123"
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"description": "Name of deleted folder",
|
||||||
"example": "someFolderName"
|
"example": "someFolderName"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "List of IDs and names of the deleted folders"
|
"description": "List of IDs and names of deleted folders"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -477,7 +510,11 @@ export const deleteFolder = async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// check that user is a member of the workspace
|
// check that user is a member of the workspace
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Delete,
|
ProjectPermissionActions.Delete,
|
||||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath: directory })
|
subject(ProjectPermissionSub.Secrets, { environment, secretPath: directory })
|
||||||
@ -540,43 +577,37 @@ export const deleteFolder = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get folders for workspace with id [workspaceId] and environment [environment]
|
* Get folders for workspace with id [workspaceId] and environment [environment]
|
||||||
* considering [parentFolderId] and [parentFolderPath]
|
* considering directory/path [directory]
|
||||||
* @param req
|
* @param req
|
||||||
* @param res
|
* @param res
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const getFolders = async (req: Request, res: Response) => {
|
export const getFolders = async (req: Request, res: Response) => {
|
||||||
/*
|
/*
|
||||||
#swagger.summary = 'Retrieve folders based on specific conditions'
|
#swagger.summary = 'Get folders'
|
||||||
#swagger.description = 'Fetches folders from the specified workspace and environment, optionally providing either a parentFolderId or a parentFolderPath to narrow down results'
|
#swagger.description = 'Get folders'
|
||||||
|
|
||||||
#swagger.security = [{
|
#swagger.security = [{
|
||||||
"apiKeyAuth": []
|
"apiKeyAuth": [],
|
||||||
|
"bearerAuth": []
|
||||||
}]
|
}]
|
||||||
|
|
||||||
#swagger.parameters['workspaceId'] = {
|
#swagger.parameters['workspaceId'] = {
|
||||||
"description": "ID of the workspace from which the folders are to be fetched",
|
"description": "ID of the workspace where to get folders from",
|
||||||
"required": true,
|
"required": true,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
}
|
}
|
||||||
|
|
||||||
#swagger.parameters['environment'] = {
|
#swagger.parameters['environment'] = {
|
||||||
"description": "Environment where the folder is located",
|
"description": "Slug of environment where to get folders from",
|
||||||
"required": true,
|
"required": true,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
}
|
}
|
||||||
|
|
||||||
#swagger.parameters['parentFolderId'] = {
|
#swagger.parameters['directory'] = {
|
||||||
"description": "ID of the parent folder",
|
"description": "Path where to get fodlers from like / or /foo/bar. Default is /",
|
||||||
"required": false,
|
|
||||||
"type": "string",
|
|
||||||
"in": "query"
|
|
||||||
}
|
|
||||||
|
|
||||||
#swagger.parameters['parentFolderPath'] = {
|
|
||||||
"description": "Path of the parent folder, like /folder1/folder2",
|
|
||||||
"required": false,
|
"required": false,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
@ -604,23 +635,6 @@ export const getFolders = async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "List of folders"
|
"description": "List of folders"
|
||||||
},
|
|
||||||
"dir": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "parentFolderName"
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "parentFolderId"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"description": "List of directories"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -647,7 +661,10 @@ export const getFolders = async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// check that user is a member of the workspace
|
// check that user is a member of the workspace
|
||||||
await getUserProjectPermissions(req.user._id, workspaceId);
|
await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const folders = await Folder.findOne({ workspace: workspaceId, environment });
|
const folders = await Folder.findOne({ workspace: workspaceId, environment });
|
@ -2,10 +2,8 @@ import { Request, Response } from "express";
|
|||||||
import { AuthMethod, User } from "../../models";
|
import { AuthMethod, User } from "../../models";
|
||||||
import { checkEmailVerification, sendEmailVerification } from "../../helpers/signup";
|
import { checkEmailVerification, sendEmailVerification } from "../../helpers/signup";
|
||||||
import { createToken } from "../../helpers/auth";
|
import { createToken } from "../../helpers/auth";
|
||||||
import { BadRequestError } from "../../utils/errors";
|
|
||||||
import {
|
import {
|
||||||
getAuthSecret,
|
getAuthSecret,
|
||||||
getInviteOnlySignup,
|
|
||||||
getJwtSignupLifetime,
|
getJwtSignupLifetime,
|
||||||
getSmtpConfigured
|
getSmtpConfigured
|
||||||
} from "../../config";
|
} from "../../config";
|
||||||
@ -68,16 +66,6 @@ export const verifyEmailSignup = async (req: Request, res: Response) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await getInviteOnlySignup()) {
|
|
||||||
// Only one user can create an account without being invited. The rest need to be invited in order to make an account
|
|
||||||
const userCount = await User.countDocuments({});
|
|
||||||
if (userCount != 0) {
|
|
||||||
throw BadRequestError({
|
|
||||||
message: "New user sign ups are not allowed at this time. You must be invited to sign up."
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// verify email
|
// verify email
|
||||||
if (await getSmtpConfigured()) {
|
if (await getSmtpConfigured()) {
|
||||||
await checkEmailVerification({
|
await checkEmailVerification({
|
1269
backend-mongo/src/controllers/v1/universalAuthController.ts
Normal file
1269
backend-mongo/src/controllers/v1/universalAuthController.ts
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,27 +1,36 @@
|
|||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { client, getRootEncryptionKey } from "../../config";
|
import { client, getEncryptionKey, getRootEncryptionKey } from "../../config";
|
||||||
import { Webhook } from "../../models";
|
import { Webhook } from "../../models";
|
||||||
import { getWebhookPayload, triggerWebhookRequest } from "../../services/WebhookService";
|
import { getWebhookPayload, triggerWebhookRequest } from "../../services/WebhookService";
|
||||||
import { BadRequestError, ResourceNotFoundError } from "../../utils/errors";
|
import { BadRequestError, ResourceNotFoundError } from "../../utils/errors";
|
||||||
import { EEAuditLogService } from "../../ee/services";
|
import { EEAuditLogService } from "../../ee/services";
|
||||||
import { EventType } from "../../ee/models";
|
import { EventType } from "../../ee/models";
|
||||||
import { ALGORITHM_AES_256_GCM, ENCODING_SCHEME_BASE64 } from "../../variables";
|
import {
|
||||||
|
ALGORITHM_AES_256_GCM,
|
||||||
|
ENCODING_SCHEME_BASE64,
|
||||||
|
ENCODING_SCHEME_UTF8
|
||||||
|
} from "../../variables";
|
||||||
import { validateRequest } from "../../helpers/validation";
|
import { validateRequest } from "../../helpers/validation";
|
||||||
import * as reqValidator from "../../validation/webhooks";
|
import * as reqValidator from "../../validation/webhooks";
|
||||||
import {
|
import {
|
||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
ProjectPermissionSub,
|
ProjectPermissionSub,
|
||||||
getUserProjectPermissions
|
getAuthDataProjectPermissions
|
||||||
} from "../../ee/services/ProjectRoleService";
|
} from "../../ee/services/ProjectRoleService";
|
||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
import { encryptSymmetric128BitHexKeyUTF8 } from "../../utils/crypto";
|
||||||
|
|
||||||
export const createWebhook = async (req: Request, res: Response) => {
|
export const createWebhook = async (req: Request, res: Response) => {
|
||||||
const {
|
const {
|
||||||
body: { webhookUrl, webhookSecretKey, environment, workspaceId, secretPath }
|
body: { webhookUrl, webhookSecretKey, environment, workspaceId, secretPath }
|
||||||
} = await validateRequest(reqValidator.CreateWebhookV1, req);
|
} = await validateRequest(reqValidator.CreateWebhookV1, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Create,
|
ProjectPermissionActions.Create,
|
||||||
ProjectPermissionSub.Webhooks
|
ProjectPermissionSub.Webhooks
|
||||||
@ -31,17 +40,31 @@ export const createWebhook = async (req: Request, res: Response) => {
|
|||||||
workspace: workspaceId,
|
workspace: workspaceId,
|
||||||
environment,
|
environment,
|
||||||
secretPath,
|
secretPath,
|
||||||
url: webhookUrl,
|
url: webhookUrl
|
||||||
algorithm: ALGORITHM_AES_256_GCM,
|
|
||||||
keyEncoding: ENCODING_SCHEME_BASE64
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (webhookSecretKey) {
|
if (webhookSecretKey) {
|
||||||
|
const encryptionKey = await getEncryptionKey();
|
||||||
const rootEncryptionKey = await getRootEncryptionKey();
|
const rootEncryptionKey = await getRootEncryptionKey();
|
||||||
|
|
||||||
|
if (rootEncryptionKey) {
|
||||||
const { ciphertext, iv, tag } = client.encryptSymmetric(webhookSecretKey, rootEncryptionKey);
|
const { ciphertext, iv, tag } = client.encryptSymmetric(webhookSecretKey, rootEncryptionKey);
|
||||||
webhook.iv = iv;
|
webhook.iv = iv;
|
||||||
webhook.tag = tag;
|
webhook.tag = tag;
|
||||||
webhook.encryptedSecretKey = ciphertext;
|
webhook.encryptedSecretKey = ciphertext;
|
||||||
|
webhook.algorithm = ALGORITHM_AES_256_GCM;
|
||||||
|
webhook.keyEncoding = ENCODING_SCHEME_BASE64;
|
||||||
|
} else if (encryptionKey) {
|
||||||
|
const { ciphertext, iv, tag } = encryptSymmetric128BitHexKeyUTF8({
|
||||||
|
plaintext: webhookSecretKey,
|
||||||
|
key: encryptionKey
|
||||||
|
});
|
||||||
|
webhook.iv = iv;
|
||||||
|
webhook.tag = tag;
|
||||||
|
webhook.encryptedSecretKey = ciphertext;
|
||||||
|
webhook.algorithm = ALGORITHM_AES_256_GCM;
|
||||||
|
webhook.keyEncoding = ENCODING_SCHEME_UTF8;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await webhook.save();
|
await webhook.save();
|
||||||
@ -80,10 +103,10 @@ export const updateWebhook = async (req: Request, res: Response) => {
|
|||||||
throw BadRequestError({ message: "Webhook not found!!" });
|
throw BadRequestError({ message: "Webhook not found!!" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
req.user._id,
|
authData: req.authData,
|
||||||
webhook.workspace.toString()
|
workspaceId: webhook.workspace
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Edit,
|
ProjectPermissionActions.Edit,
|
||||||
ProjectPermissionSub.Webhooks
|
ProjectPermissionSub.Webhooks
|
||||||
@ -127,10 +150,11 @@ export const deleteWebhook = async (req: Request, res: Response) => {
|
|||||||
throw ResourceNotFoundError({ message: "Webhook not found!!" });
|
throw ResourceNotFoundError({ message: "Webhook not found!!" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
req.user._id,
|
authData: req.authData,
|
||||||
webhook.workspace.toString()
|
workspaceId: webhook.workspace
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Delete,
|
ProjectPermissionActions.Delete,
|
||||||
ProjectPermissionSub.Webhooks
|
ProjectPermissionSub.Webhooks
|
||||||
@ -174,10 +198,11 @@ export const testWebhook = async (req: Request, res: Response) => {
|
|||||||
throw BadRequestError({ message: "Webhook not found!!" });
|
throw BadRequestError({ message: "Webhook not found!!" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
req.user._id,
|
authData: req.authData,
|
||||||
webhook.workspace.toString()
|
workspaceId: webhook.workspace
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.Webhooks
|
ProjectPermissionSub.Webhooks
|
||||||
@ -218,7 +243,11 @@ export const listWebhooks = async (req: Request, res: Response) => {
|
|||||||
query: { environment, workspaceId, secretPath }
|
query: { environment, workspaceId, secretPath }
|
||||||
} = await validateRequest(reqValidator.ListWebhooksV1, req);
|
} = await validateRequest(reqValidator.ListWebhooksV1, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.Webhooks
|
ProjectPermissionSub.Webhooks
|
@ -17,7 +17,7 @@ import { OrganizationNotFoundError } from "../../utils/errors";
|
|||||||
import {
|
import {
|
||||||
OrgPermissionActions,
|
OrgPermissionActions,
|
||||||
OrgPermissionSubjects,
|
OrgPermissionSubjects,
|
||||||
getUserOrgPermissions
|
getAuthDataOrgPermissions
|
||||||
} from "../../ee/services/RoleService";
|
} from "../../ee/services/RoleService";
|
||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
import { validateRequest } from "../../helpers/validation";
|
import { validateRequest } from "../../helpers/validation";
|
||||||
@ -25,7 +25,7 @@ import * as reqValidator from "../../validation";
|
|||||||
import {
|
import {
|
||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
ProjectPermissionSub,
|
ProjectPermissionSub,
|
||||||
getUserProjectPermissions
|
getAuthDataProjectPermissions
|
||||||
} from "../../ee/services/ProjectRoleService";
|
} from "../../ee/services/ProjectRoleService";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -39,7 +39,11 @@ export const getWorkspacePublicKeys = async (req: Request, res: Response) => {
|
|||||||
params: { workspaceId }
|
params: { workspaceId }
|
||||||
} = await validateRequest(reqValidator.GetWorkspacePublicKeysV1, req);
|
} = await validateRequest(reqValidator.GetWorkspacePublicKeysV1, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.Member
|
ProjectPermissionSub.Member
|
||||||
@ -72,7 +76,11 @@ export const getWorkspaceMemberships = async (req: Request, res: Response) => {
|
|||||||
params: { workspaceId }
|
params: { workspaceId }
|
||||||
} = await validateRequest(reqValidator.GetWorkspaceMembershipsV1, req);
|
} = await validateRequest(reqValidator.GetWorkspaceMembershipsV1, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.Member
|
ProjectPermissionSub.Member
|
||||||
@ -144,7 +152,10 @@ export const createWorkspace = async (req: Request, res: Response) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Create,
|
OrgPermissionActions.Create,
|
||||||
OrgPermissionSubjects.Workspace
|
OrgPermissionSubjects.Workspace
|
||||||
@ -195,7 +206,11 @@ export const deleteWorkspace = async (req: Request, res: Response) => {
|
|||||||
params: { workspaceId }
|
params: { workspaceId }
|
||||||
} = await validateRequest(reqValidator.DeleteWorkspaceV1, req);
|
} = await validateRequest(reqValidator.DeleteWorkspaceV1, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Delete,
|
ProjectPermissionActions.Delete,
|
||||||
ProjectPermissionSub.Workspace
|
ProjectPermissionSub.Workspace
|
||||||
@ -223,7 +238,11 @@ export const changeWorkspaceName = async (req: Request, res: Response) => {
|
|||||||
body: { name }
|
body: { name }
|
||||||
} = await validateRequest(reqValidator.ChangeWorkspaceNameV1, req);
|
} = await validateRequest(reqValidator.ChangeWorkspaceNameV1, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Edit,
|
ProjectPermissionActions.Edit,
|
||||||
ProjectPermissionSub.Workspace
|
ProjectPermissionSub.Workspace
|
||||||
@ -257,7 +276,12 @@ export const getWorkspaceIntegrations = async (req: Request, res: Response) => {
|
|||||||
const {
|
const {
|
||||||
params: { workspaceId }
|
params: { workspaceId }
|
||||||
} = await validateRequest(reqValidator.GetWorkspaceIntegrationsV1, req);
|
} = await validateRequest(reqValidator.GetWorkspaceIntegrationsV1, req);
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
||||||
@ -283,7 +307,11 @@ export const getWorkspaceIntegrationAuthorizations = async (req: Request, res: R
|
|||||||
params: { workspaceId }
|
params: { workspaceId }
|
||||||
} = await validateRequest(reqValidator.GetWorkspaceIntegrationAuthorizationsV1, req);
|
} = await validateRequest(reqValidator.GetWorkspaceIntegrationAuthorizationsV1, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.Integrations
|
ProjectPermissionSub.Integrations
|
||||||
@ -309,7 +337,11 @@ export const getWorkspaceServiceTokens = async (req: Request, res: Response) =>
|
|||||||
params: { workspaceId }
|
params: { workspaceId }
|
||||||
} = await validateRequest(reqValidator.GetWorkspaceServiceTokensV1, req);
|
} = await validateRequest(reqValidator.GetWorkspaceServiceTokensV1, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.ServiceTokens
|
ProjectPermissionSub.ServiceTokens
|
@ -8,10 +8,8 @@ import { createToken, issueAuthTokens } from "../../helpers/auth";
|
|||||||
import { checkUserDevice } from "../../helpers/user";
|
import { checkUserDevice } from "../../helpers/user";
|
||||||
import { sendMail } from "../../helpers/nodemailer";
|
import { sendMail } from "../../helpers/nodemailer";
|
||||||
import { TokenService } from "../../services";
|
import { TokenService } from "../../services";
|
||||||
import { EELogService } from "../../ee/services";
|
|
||||||
import { BadRequestError, InternalServerError } from "../../utils/errors";
|
import { BadRequestError, InternalServerError } from "../../utils/errors";
|
||||||
import { ACTION_LOGIN, AuthTokenType, TOKEN_EMAIL_MFA } from "../../variables";
|
import { AuthTokenType, TOKEN_EMAIL_MFA } from "../../variables";
|
||||||
import { getUserAgentType } from "../../utils/posthog"; // TODO: move this
|
|
||||||
import { getAuthSecret, getHttpsEnabled, getJwtMfaLifetime } from "../../config";
|
import { getAuthSecret, getHttpsEnabled, getJwtMfaLifetime } from "../../config";
|
||||||
import { validateRequest } from "../../helpers/validation";
|
import { validateRequest } from "../../helpers/validation";
|
||||||
import * as reqValidator from "../../validation/auth";
|
import * as reqValidator from "../../validation/auth";
|
||||||
@ -190,19 +188,6 @@ export const login2 = async (req: Request, res: Response) => {
|
|||||||
response.protectedKeyTag = user.protectedKeyTag;
|
response.protectedKeyTag = user.protectedKeyTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
const loginAction = await EELogService.createAction({
|
|
||||||
name: ACTION_LOGIN,
|
|
||||||
userId: user._id
|
|
||||||
});
|
|
||||||
|
|
||||||
loginAction &&
|
|
||||||
(await EELogService.createLog({
|
|
||||||
userId: user._id,
|
|
||||||
actions: [loginAction],
|
|
||||||
channel: getUserAgentType(req.headers["user-agent"]),
|
|
||||||
ipAddress: req.ip
|
|
||||||
}));
|
|
||||||
|
|
||||||
return res.status(200).send(response);
|
return res.status(200).send(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,20 +204,16 @@ export const login2 = async (req: Request, res: Response) => {
|
|||||||
* @param res
|
* @param res
|
||||||
*/
|
*/
|
||||||
export const sendMfaToken = async (req: Request, res: Response) => {
|
export const sendMfaToken = async (req: Request, res: Response) => {
|
||||||
const {
|
|
||||||
body: { email }
|
|
||||||
} = await validateRequest(reqValidator.SendMfaTokenV2, req);
|
|
||||||
|
|
||||||
const code = await TokenService.createToken({
|
const code = await TokenService.createToken({
|
||||||
type: TOKEN_EMAIL_MFA,
|
type: TOKEN_EMAIL_MFA,
|
||||||
email
|
email: req.user.email
|
||||||
});
|
});
|
||||||
|
|
||||||
// send MFA code [code] to [email]
|
// send MFA code [code] to [email]
|
||||||
await sendMail({
|
await sendMail({
|
||||||
template: "emailMfa.handlebars",
|
template: "emailMfa.handlebars",
|
||||||
subjectLine: "Infisical MFA code",
|
subjectLine: "Infisical MFA code",
|
||||||
recipients: [email],
|
recipients: [req.user.email],
|
||||||
substitutions: {
|
substitutions: {
|
||||||
code
|
code
|
||||||
}
|
}
|
||||||
@ -251,17 +232,17 @@ export const sendMfaToken = async (req: Request, res: Response) => {
|
|||||||
*/
|
*/
|
||||||
export const verifyMfaToken = async (req: Request, res: Response) => {
|
export const verifyMfaToken = async (req: Request, res: Response) => {
|
||||||
const {
|
const {
|
||||||
body: { email, mfaToken }
|
body: { mfaToken }
|
||||||
} = await validateRequest(reqValidator.VerifyMfaTokenV2, req);
|
} = await validateRequest(reqValidator.VerifyMfaTokenV2, req);
|
||||||
|
|
||||||
await TokenService.validateToken({
|
await TokenService.validateToken({
|
||||||
type: TOKEN_EMAIL_MFA,
|
type: TOKEN_EMAIL_MFA,
|
||||||
email,
|
email: req.user.email,
|
||||||
token: mfaToken
|
token: mfaToken
|
||||||
});
|
});
|
||||||
|
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
email
|
email: req.user.email
|
||||||
}).select(
|
}).select(
|
||||||
"+salt +verifier +encryptionVersion +protectedKey +protectedKeyIV +protectedKeyTag +publicKey +encryptedPrivateKey +iv +tag +devices"
|
"+salt +verifier +encryptionVersion +protectedKey +protectedKeyIV +protectedKeyTag +publicKey +encryptedPrivateKey +iv +tag +devices"
|
||||||
);
|
);
|
||||||
@ -330,18 +311,5 @@ export const verifyMfaToken = async (req: Request, res: Response) => {
|
|||||||
resObj.protectedKeyTag = user.protectedKeyTag;
|
resObj.protectedKeyTag = user.protectedKeyTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
const loginAction = await EELogService.createAction({
|
|
||||||
name: ACTION_LOGIN,
|
|
||||||
userId: user._id
|
|
||||||
});
|
|
||||||
|
|
||||||
loginAction &&
|
|
||||||
(await EELogService.createLog({
|
|
||||||
userId: user._id,
|
|
||||||
actions: [loginAction],
|
|
||||||
channel: getUserAgentType(req.headers["user-agent"]),
|
|
||||||
ipAddress: req.realIP
|
|
||||||
}));
|
|
||||||
|
|
||||||
return res.status(200).send(resObj);
|
return res.status(200).send(resObj);
|
||||||
};
|
};
|
@ -12,18 +12,15 @@ import {
|
|||||||
import { EventType, SecretVersion } from "../../ee/models";
|
import { EventType, SecretVersion } from "../../ee/models";
|
||||||
import { EEAuditLogService, EELicenseService } from "../../ee/services";
|
import { EEAuditLogService, EELicenseService } from "../../ee/services";
|
||||||
import { BadRequestError, WorkspaceNotFoundError } from "../../utils/errors";
|
import { BadRequestError, WorkspaceNotFoundError } from "../../utils/errors";
|
||||||
import _ from "lodash";
|
|
||||||
import { PERMISSION_READ_SECRETS, PERMISSION_WRITE_SECRETS } from "../../variables";
|
|
||||||
import { validateRequest } from "../../helpers/validation";
|
import { validateRequest } from "../../helpers/validation";
|
||||||
import * as reqValidator from "../../validation/environments";
|
import * as reqValidator from "../../validation/environments";
|
||||||
import {
|
import {
|
||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
ProjectPermissionSub,
|
ProjectPermissionSub,
|
||||||
getUserProjectPermissions
|
getAuthDataProjectPermissions
|
||||||
} from "../../ee/services/ProjectRoleService";
|
} from "../../ee/services/ProjectRoleService";
|
||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
import { SecretImport } from "../../models";
|
import { SecretImport } from "../../models";
|
||||||
import { ServiceAccountWorkspacePermission } from "../../models";
|
|
||||||
import { Webhook } from "../../models";
|
import { Webhook } from "../../models";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -39,27 +36,14 @@ export const createWorkspaceEnvironment = async (req: Request, res: Response) =>
|
|||||||
#swagger.description = 'Create environment'
|
#swagger.description = 'Create environment'
|
||||||
|
|
||||||
#swagger.security = [{
|
#swagger.security = [{
|
||||||
"apiKeyAuth": []
|
"apiKeyAuth": [],
|
||||||
}]
|
}]
|
||||||
|
|
||||||
#swagger.parameters['workspaceId'] = {
|
#swagger.parameters['workspaceId'] = {
|
||||||
"description": "ID of project",
|
"description": "ID of workspace where to create environment",
|
||||||
"required": true,
|
"required": true,
|
||||||
"type": "string"
|
"type": "string",
|
||||||
}
|
"in": "path"
|
||||||
|
|
||||||
/*
|
|
||||||
#swagger.summary = 'Create environment'
|
|
||||||
#swagger.description = 'Create environment'
|
|
||||||
|
|
||||||
#swagger.security = [{
|
|
||||||
"apiKeyAuth": []
|
|
||||||
}]
|
|
||||||
|
|
||||||
#swagger.parameters['workspaceId'] = {
|
|
||||||
"description": "ID of project",
|
|
||||||
"required": true,
|
|
||||||
"type": "string"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#swagger.requestBody = {
|
#swagger.requestBody = {
|
||||||
@ -70,12 +54,12 @@ export const createWorkspaceEnvironment = async (req: Request, res: Response) =>
|
|||||||
"properties": {
|
"properties": {
|
||||||
"environmentName": {
|
"environmentName": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Name of the environment",
|
"description": "Name of the environment to create",
|
||||||
"example": "development"
|
"example": "development"
|
||||||
},
|
},
|
||||||
"environmentSlug": {
|
"environmentSlug": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Slug of the environment",
|
"description": "Slug of environment to create",
|
||||||
"example": "dev-environment"
|
"example": "dev-environment"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -93,27 +77,31 @@ export const createWorkspaceEnvironment = async (req: Request, res: Response) =>
|
|||||||
"properties": {
|
"properties": {
|
||||||
"message": {
|
"message": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"example": "Successfully created new environment"
|
"description": "Sucess message",
|
||||||
|
"example": "Successfully created environment"
|
||||||
},
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"example": "someWorkspaceId"
|
"description": "ID of workspace where environment was created",
|
||||||
|
"example": "abc123"
|
||||||
},
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"example": "someEnvironmentName"
|
"description": "Name of created environment",
|
||||||
|
"example": "Staging"
|
||||||
},
|
},
|
||||||
"slug": {
|
"slug": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"example": "someEnvironmentSlug"
|
"description": "Slug of created environment",
|
||||||
|
"example": "staging"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "Response after creating a new environment"
|
"description": "Details of the created environment"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -124,7 +112,11 @@ export const createWorkspaceEnvironment = async (req: Request, res: Response) =>
|
|||||||
body: { environmentName, environmentSlug }
|
body: { environmentName, environmentSlug }
|
||||||
} = await validateRequest(reqValidator.CreateWorkspaceEnvironmentV2, req);
|
} = await validateRequest(reqValidator.CreateWorkspaceEnvironmentV2, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Create,
|
ProjectPermissionActions.Create,
|
||||||
ProjectPermissionSub.Environments
|
ProjectPermissionSub.Environments
|
||||||
@ -201,7 +193,11 @@ export const reorderWorkspaceEnvironments = async (req: Request, res: Response)
|
|||||||
body: { environmentName, environmentSlug, otherEnvironmentSlug, otherEnvironmentName }
|
body: { environmentName, environmentSlug, otherEnvironmentSlug, otherEnvironmentName }
|
||||||
} = await validateRequest(reqValidator.ReorderWorkspaceEnvironmentsV2, req);
|
} = await validateRequest(reqValidator.ReorderWorkspaceEnvironmentsV2, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Edit,
|
ProjectPermissionActions.Edit,
|
||||||
ProjectPermissionSub.Environments
|
ProjectPermissionSub.Environments
|
||||||
@ -247,11 +243,15 @@ export const reorderWorkspaceEnvironments = async (req: Request, res: Response)
|
|||||||
*/
|
*/
|
||||||
export const renameWorkspaceEnvironment = async (req: Request, res: Response) => {
|
export const renameWorkspaceEnvironment = async (req: Request, res: Response) => {
|
||||||
/*
|
/*
|
||||||
#swagger.summary = 'Rename workspace environment'
|
#swagger.summary = 'Update environment'
|
||||||
#swagger.description = 'Rename a specific environment within a workspace'
|
#swagger.description = 'Update environment'
|
||||||
|
|
||||||
|
#swagger.security = [{
|
||||||
|
"apiKeyAuth": [],
|
||||||
|
}]
|
||||||
|
|
||||||
#swagger.parameters['workspaceId'] = {
|
#swagger.parameters['workspaceId'] = {
|
||||||
"description": "ID of the workspace",
|
"description": "ID of workspace where to update environment",
|
||||||
"required": true,
|
"required": true,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"in": "path"
|
"in": "path"
|
||||||
@ -265,17 +265,17 @@ export const renameWorkspaceEnvironment = async (req: Request, res: Response) =>
|
|||||||
"properties": {
|
"properties": {
|
||||||
"environmentName": {
|
"environmentName": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "New name for the environment",
|
"description": "Name of environment to update to",
|
||||||
"example": "Staging-Renamed"
|
"example": "Staging-Renamed"
|
||||||
},
|
},
|
||||||
"environmentSlug": {
|
"environmentSlug": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "New slug for the environment",
|
"description": "Slug of environment to update to",
|
||||||
"example": "staging-renamed"
|
"example": "staging-renamed"
|
||||||
},
|
},
|
||||||
"oldEnvironmentSlug": {
|
"oldEnvironmentSlug": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Current slug of the environment to rename",
|
"description": "Current slug of environment",
|
||||||
"example": "staging-old"
|
"example": "staging-old"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -293,21 +293,25 @@ export const renameWorkspaceEnvironment = async (req: Request, res: Response) =>
|
|||||||
"properties": {
|
"properties": {
|
||||||
"message": {
|
"message": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"description": "Success message",
|
||||||
"example": "Successfully update environment"
|
"example": "Successfully update environment"
|
||||||
},
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"example": "someWorkspaceId"
|
"description": "ID of workspace where environment was updated",
|
||||||
|
"example": "abc123"
|
||||||
},
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"description": "Name of updated environment",
|
||||||
"example": "Staging-Renamed"
|
"example": "Staging-Renamed"
|
||||||
},
|
},
|
||||||
"slug": {
|
"slug": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"description": "Slug of updated environment",
|
||||||
"example": "staging-renamed"
|
"example": "staging-renamed"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -324,7 +328,11 @@ export const renameWorkspaceEnvironment = async (req: Request, res: Response) =>
|
|||||||
body: { environmentName, environmentSlug, oldEnvironmentSlug }
|
body: { environmentName, environmentSlug, oldEnvironmentSlug }
|
||||||
} = await validateRequest(reqValidator.UpdateWorkspaceEnvironmentV2, req);
|
} = await validateRequest(reqValidator.UpdateWorkspaceEnvironmentV2, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Edit,
|
ProjectPermissionActions.Edit,
|
||||||
ProjectPermissionSub.Environments
|
ProjectPermissionSub.Environments
|
||||||
@ -400,11 +408,6 @@ export const renameWorkspaceEnvironment = async (req: Request, res: Response) =>
|
|||||||
{ arrayFilters: [{ "element.environment": oldEnvironmentSlug }] },
|
{ arrayFilters: [{ "element.environment": oldEnvironmentSlug }] },
|
||||||
);
|
);
|
||||||
|
|
||||||
await ServiceAccountWorkspacePermission.updateMany(
|
|
||||||
{ workspace: workspaceId, environment: oldEnvironmentSlug },
|
|
||||||
{ environment: environmentSlug }
|
|
||||||
);
|
|
||||||
|
|
||||||
await Webhook.updateMany(
|
await Webhook.updateMany(
|
||||||
{ workspace: workspaceId, environment: oldEnvironmentSlug },
|
{ workspace: workspaceId, environment: oldEnvironmentSlug },
|
||||||
{ environment: environmentSlug }
|
{ environment: environmentSlug }
|
||||||
@ -453,15 +456,15 @@ export const renameWorkspaceEnvironment = async (req: Request, res: Response) =>
|
|||||||
*/
|
*/
|
||||||
export const deleteWorkspaceEnvironment = async (req: Request, res: Response) => {
|
export const deleteWorkspaceEnvironment = async (req: Request, res: Response) => {
|
||||||
/*
|
/*
|
||||||
#swagger.summary = 'Delete workspace environment'
|
#swagger.summary = 'Delete environment'
|
||||||
#swagger.description = 'Delete a specific environment from a workspace'
|
#swagger.description = 'Delete environment'
|
||||||
|
|
||||||
#swagger.security = [{
|
#swagger.security = [{
|
||||||
"apiKeyAuth": []
|
"apiKeyAuth": []
|
||||||
}]
|
}]
|
||||||
|
|
||||||
#swagger.parameters['workspaceId'] = {
|
#swagger.parameters['workspaceId'] = {
|
||||||
"description": "ID of the workspace",
|
"description": "ID of workspace where to delete environment",
|
||||||
"required": true,
|
"required": true,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"in": "path"
|
"in": "path"
|
||||||
@ -475,8 +478,8 @@ export const deleteWorkspaceEnvironment = async (req: Request, res: Response) =>
|
|||||||
"properties": {
|
"properties": {
|
||||||
"environmentSlug": {
|
"environmentSlug": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Slug of the environment to delete",
|
"description": "Slug of environment to delete",
|
||||||
"example": "dev-environment"
|
"example": "dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["environmentSlug"]
|
"required": ["environmentSlug"]
|
||||||
@ -493,15 +496,18 @@ export const deleteWorkspaceEnvironment = async (req: Request, res: Response) =>
|
|||||||
"properties": {
|
"properties": {
|
||||||
"message": {
|
"message": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"description": "Success message",
|
||||||
"example": "Successfully deleted environment"
|
"example": "Successfully deleted environment"
|
||||||
},
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"example": "someWorkspaceId"
|
"description": "ID of workspace where environment was deleted",
|
||||||
|
"example": "abc123"
|
||||||
},
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"example": "dev-environment"
|
"description": "Slug of deleted environment",
|
||||||
|
"example": "dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "Response after deleting an environment from a workspace"
|
"description": "Response after deleting an environment from a workspace"
|
||||||
@ -515,7 +521,11 @@ export const deleteWorkspaceEnvironment = async (req: Request, res: Response) =>
|
|||||||
body: { environmentSlug }
|
body: { environmentSlug }
|
||||||
} = await validateRequest(reqValidator.DeleteWorkspaceEnvironmentV2, req);
|
} = await validateRequest(reqValidator.DeleteWorkspaceEnvironmentV2, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Delete,
|
ProjectPermissionActions.Delete,
|
||||||
ProjectPermissionSub.Environments
|
ProjectPermissionSub.Environments
|
||||||
@ -592,97 +602,3 @@ export const deleteWorkspaceEnvironment = async (req: Request, res: Response) =>
|
|||||||
environment: environmentSlug
|
environment: environmentSlug
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO(akhilmhdh) after rbac this can be completely removed
|
|
||||||
export const getAllAccessibleEnvironmentsOfWorkspace = async (req: Request, res: Response) => {
|
|
||||||
/*
|
|
||||||
#swagger.summary = 'Get all accessible environments of a workspace'
|
|
||||||
#swagger.description = 'Fetch all environments that the user has access to in a specified workspace'
|
|
||||||
|
|
||||||
#swagger.security = [{
|
|
||||||
"apiKeyAuth": []
|
|
||||||
}]
|
|
||||||
|
|
||||||
#swagger.parameters['workspaceId'] = {
|
|
||||||
"description": "ID of the workspace",
|
|
||||||
"required": true,
|
|
||||||
"type": "string",
|
|
||||||
"in": "path"
|
|
||||||
}
|
|
||||||
|
|
||||||
#swagger.responses[200] = {
|
|
||||||
content: {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"accessibleEnvironments": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Development"
|
|
||||||
},
|
|
||||||
"slug": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "development"
|
|
||||||
},
|
|
||||||
"isWriteDenied": {
|
|
||||||
"type": "boolean",
|
|
||||||
"example": false
|
|
||||||
},
|
|
||||||
"isReadDenied": {
|
|
||||||
"type": "boolean",
|
|
||||||
"example": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"description": "List of environments the user has access to in the specified workspace"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
const {
|
|
||||||
params: { workspaceId }
|
|
||||||
} = await validateRequest(reqValidator.GetAllAccessibileEnvironmentsOfWorkspaceV2, req);
|
|
||||||
|
|
||||||
const { membership: workspacesUserIsMemberOf } = await getUserProjectPermissions(
|
|
||||||
req.user._id,
|
|
||||||
workspaceId
|
|
||||||
);
|
|
||||||
|
|
||||||
const accessibleEnvironments: any = [];
|
|
||||||
const deniedPermission = workspacesUserIsMemberOf.deniedPermissions;
|
|
||||||
|
|
||||||
const relatedWorkspace = await Workspace.findById(workspaceId);
|
|
||||||
if (!relatedWorkspace) {
|
|
||||||
throw BadRequestError();
|
|
||||||
}
|
|
||||||
relatedWorkspace.environments.forEach((environment) => {
|
|
||||||
const isReadBlocked = _.some(deniedPermission, {
|
|
||||||
environmentSlug: environment.slug,
|
|
||||||
ability: PERMISSION_READ_SECRETS
|
|
||||||
});
|
|
||||||
const isWriteBlocked = _.some(deniedPermission, {
|
|
||||||
environmentSlug: environment.slug,
|
|
||||||
ability: PERMISSION_WRITE_SECRETS
|
|
||||||
});
|
|
||||||
if (isReadBlocked && isWriteBlocked) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
accessibleEnvironments.push({
|
|
||||||
name: environment.name,
|
|
||||||
slug: environment.slug,
|
|
||||||
isWriteDenied: isWriteBlocked,
|
|
||||||
isReadDenied: isReadBlocked
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
res.json({ accessibleEnvironments });
|
|
||||||
};
|
|
@ -6,9 +6,9 @@ import * as workspaceController from "./workspaceController";
|
|||||||
import * as serviceTokenDataController from "./serviceTokenDataController";
|
import * as serviceTokenDataController from "./serviceTokenDataController";
|
||||||
import * as secretController from "./secretController";
|
import * as secretController from "./secretController";
|
||||||
import * as secretsController from "./secretsController";
|
import * as secretsController from "./secretsController";
|
||||||
import * as serviceAccountsController from "./serviceAccountsController";
|
|
||||||
import * as environmentController from "./environmentController";
|
import * as environmentController from "./environmentController";
|
||||||
import * as tagController from "./tagController";
|
import * as tagController from "./tagController";
|
||||||
|
import * as membershipController from "./membershipController";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
authController,
|
authController,
|
||||||
@ -19,7 +19,7 @@ export {
|
|||||||
serviceTokenDataController,
|
serviceTokenDataController,
|
||||||
secretController,
|
secretController,
|
||||||
secretsController,
|
secretsController,
|
||||||
serviceAccountsController,
|
|
||||||
environmentController,
|
environmentController,
|
||||||
tagController,
|
tagController,
|
||||||
}
|
membershipController
|
||||||
|
};
|
107
backend-mongo/src/controllers/v2/membershipController.ts
Normal file
107
backend-mongo/src/controllers/v2/membershipController.ts
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
import { Request, Response } from "express";
|
||||||
|
import { Types } from "mongoose";
|
||||||
|
|
||||||
|
import { getSiteURL } from "../../config";
|
||||||
|
import { EventType } from "../../ee/models";
|
||||||
|
import { EEAuditLogService } from "../../ee/services";
|
||||||
|
import {
|
||||||
|
ProjectPermissionActions,
|
||||||
|
ProjectPermissionSub,
|
||||||
|
getAuthDataProjectPermissions
|
||||||
|
} from "../../ee/services/ProjectRoleService";
|
||||||
|
import { sendMail } from "../../helpers";
|
||||||
|
import { validateRequest } from "../../helpers/validation";
|
||||||
|
import { IUser, Key, Membership, MembershipOrg, Workspace } from "../../models";
|
||||||
|
import { BadRequestError } from "../../utils/errors";
|
||||||
|
import * as reqValidator from "../../validation/membership";
|
||||||
|
import { ACCEPTED, MEMBER } from "../../variables";
|
||||||
|
|
||||||
|
export const addUserToWorkspace = async (req: Request, res: Response) => {
|
||||||
|
const {
|
||||||
|
params: { workspaceId },
|
||||||
|
body: { members }
|
||||||
|
} = await validateRequest(reqValidator.AddUserToWorkspaceV2, req);
|
||||||
|
// check workspace
|
||||||
|
const workspace = await Workspace.findById(workspaceId);
|
||||||
|
if (!workspace) throw new Error("Failed to find workspace");
|
||||||
|
|
||||||
|
// check permission
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionSub.Member
|
||||||
|
);
|
||||||
|
|
||||||
|
// validate members are part of the organization
|
||||||
|
const orgMembers = await MembershipOrg.find({
|
||||||
|
status: ACCEPTED,
|
||||||
|
_id: { $in: members.map(({ orgMembershipId }) => orgMembershipId) },
|
||||||
|
organization: workspace.organization
|
||||||
|
})
|
||||||
|
.populate<{ user: IUser }>("user")
|
||||||
|
.select({ _id: 1, user: 1 })
|
||||||
|
.lean();
|
||||||
|
if (orgMembers.length !== members.length)
|
||||||
|
throw BadRequestError({ message: "Org member not found" });
|
||||||
|
|
||||||
|
const existingMember = await Membership.find({
|
||||||
|
workspace: workspaceId,
|
||||||
|
user: { $in: orgMembers.map(({ user }) => user) }
|
||||||
|
});
|
||||||
|
if (existingMember?.length)
|
||||||
|
throw BadRequestError({ message: "Some users are already part of workspace" });
|
||||||
|
|
||||||
|
await Membership.insertMany(
|
||||||
|
orgMembers.map(({ user }) => ({ user: user._id, workspace: workspaceId, role: MEMBER }))
|
||||||
|
);
|
||||||
|
|
||||||
|
const encKeyGroupedByOrgMemberId = members.reduce<Record<string, (typeof members)[number]>>(
|
||||||
|
(prev, curr) => ({ ...prev, [curr.orgMembershipId]: curr }),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
await Key.insertMany(
|
||||||
|
orgMembers.map(({ user, _id: id }) => ({
|
||||||
|
encryptedKey: encKeyGroupedByOrgMemberId[id.toString()].workspaceEncryptedKey,
|
||||||
|
nonce: encKeyGroupedByOrgMemberId[id.toString()].workspaceEncryptedNonce,
|
||||||
|
sender: req.user._id,
|
||||||
|
receiver: user._id,
|
||||||
|
workspace: workspaceId
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
|
await sendMail({
|
||||||
|
template: "workspaceInvitation.handlebars",
|
||||||
|
subjectLine: "Infisical workspace invitation",
|
||||||
|
recipients: orgMembers.map(({ user }) => user.email),
|
||||||
|
substitutions: {
|
||||||
|
inviterFirstName: req.user.firstName,
|
||||||
|
inviterEmail: req.user.email,
|
||||||
|
workspaceName: workspace.name,
|
||||||
|
callback_url: (await getSiteURL()) + "/login"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await EEAuditLogService.createAuditLog(
|
||||||
|
req.authData,
|
||||||
|
{
|
||||||
|
type: EventType.ADD_BATCH_WORKSPACE_MEMBER,
|
||||||
|
metadata: orgMembers.map(({ user }) => ({
|
||||||
|
userId: user._id.toString(),
|
||||||
|
email: user.email
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
success: true,
|
||||||
|
data: orgMembers
|
||||||
|
});
|
||||||
|
};
|
@ -1,9 +1,13 @@
|
|||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import {
|
import {
|
||||||
|
IWorkspace,
|
||||||
|
Identity,
|
||||||
|
IdentityMembership,
|
||||||
|
IdentityMembershipOrg,
|
||||||
Membership,
|
Membership,
|
||||||
MembershipOrg,
|
MembershipOrg,
|
||||||
ServiceAccount,
|
User,
|
||||||
Workspace
|
Workspace
|
||||||
} from "../../models";
|
} from "../../models";
|
||||||
import { Role } from "../../ee/models";
|
import { Role } from "../../ee/models";
|
||||||
@ -14,19 +18,16 @@ import {
|
|||||||
updateSubscriptionOrgQuantity
|
updateSubscriptionOrgQuantity
|
||||||
} from "../../helpers/organization";
|
} from "../../helpers/organization";
|
||||||
import { addMembershipsOrg } from "../../helpers/membershipOrg";
|
import { addMembershipsOrg } from "../../helpers/membershipOrg";
|
||||||
import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors";
|
import { BadRequestError, ResourceNotFoundError, UnauthorizedRequestError } from "../../utils/errors";
|
||||||
import {
|
import { ACCEPTED, ADMIN, CUSTOM, MEMBER, NO_ACCESS } from "../../variables";
|
||||||
ACCEPTED,
|
|
||||||
ADMIN,
|
|
||||||
CUSTOM
|
|
||||||
} from "../../variables";
|
|
||||||
import * as reqValidator from "../../validation/organization";
|
import * as reqValidator from "../../validation/organization";
|
||||||
import { validateRequest } from "../../helpers/validation";
|
import { validateRequest } from "../../helpers/validation";
|
||||||
import {
|
import {
|
||||||
OrgPermissionActions,
|
OrgPermissionActions,
|
||||||
OrgPermissionSubjects,
|
OrgPermissionSubjects,
|
||||||
getUserOrgPermissions
|
getAuthDataOrgPermissions
|
||||||
} from "../../ee/services/RoleService";
|
} from "../../ee/services/RoleService";
|
||||||
|
import { EELicenseService } from "../../ee/services";
|
||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,11 +37,12 @@ import { ForbiddenError } from "@casl/ability";
|
|||||||
*/
|
*/
|
||||||
export const getOrganizationMemberships = async (req: Request, res: Response) => {
|
export const getOrganizationMemberships = async (req: Request, res: Response) => {
|
||||||
/*
|
/*
|
||||||
#swagger.summary = 'Return organization memberships'
|
#swagger.summary = 'Return organization user memberships'
|
||||||
#swagger.description = 'Return organization memberships'
|
#swagger.description = 'Return organization user memberships'
|
||||||
|
|
||||||
#swagger.security = [{
|
#swagger.security = [{
|
||||||
"apiKeyAuth": []
|
"apiKeyAuth": [],
|
||||||
|
"bearerAuth": []
|
||||||
}]
|
}]
|
||||||
|
|
||||||
#swagger.parameters['organizationId'] = {
|
#swagger.parameters['organizationId'] = {
|
||||||
@ -72,7 +74,10 @@ export const getOrganizationMemberships = async (req: Request, res: Response) =>
|
|||||||
params: { organizationId }
|
params: { organizationId }
|
||||||
} = await validateRequest(reqValidator.GetOrgMembersv2, req);
|
} = await validateRequest(reqValidator.GetOrgMembersv2, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Read,
|
OrgPermissionActions.Read,
|
||||||
OrgPermissionSubjects.Member
|
OrgPermissionSubjects.Member
|
||||||
@ -94,11 +99,12 @@ export const getOrganizationMemberships = async (req: Request, res: Response) =>
|
|||||||
*/
|
*/
|
||||||
export const updateOrganizationMembership = async (req: Request, res: Response) => {
|
export const updateOrganizationMembership = async (req: Request, res: Response) => {
|
||||||
/*
|
/*
|
||||||
#swagger.summary = 'Update organization membership'
|
#swagger.summary = 'Update organization user membership'
|
||||||
#swagger.description = 'Update organization membership'
|
#swagger.description = 'Update organization user membership'
|
||||||
|
|
||||||
#swagger.security = [{
|
#swagger.security = [{
|
||||||
"apiKeyAuth": []
|
"apiKeyAuth": [],
|
||||||
|
"bearerAuth": []
|
||||||
}]
|
}]
|
||||||
|
|
||||||
#swagger.parameters['organizationId'] = {
|
#swagger.parameters['organizationId'] = {
|
||||||
@ -150,17 +156,33 @@ export const updateOrganizationMembership = async (req: Request, res: Response)
|
|||||||
params: { organizationId, membershipId },
|
params: { organizationId, membershipId },
|
||||||
body: { role }
|
body: { role }
|
||||||
} = await validateRequest(reqValidator.UpdateOrgMemberv2, req);
|
} = await validateRequest(reqValidator.UpdateOrgMemberv2, req);
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
|
||||||
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Edit,
|
OrgPermissionActions.Edit,
|
||||||
OrgPermissionSubjects.Member
|
OrgPermissionSubjects.Member
|
||||||
);
|
);
|
||||||
|
|
||||||
const isCustomRole = !["admin", "member", "owner"].includes(role);
|
const isCustomRole = ![ADMIN, MEMBER, NO_ACCESS].includes(role);
|
||||||
if (isCustomRole) {
|
if (isCustomRole) {
|
||||||
const orgRole = await Role.findOne({ slug: role, isOrgRole: true });
|
const orgRole = await Role.findOne({
|
||||||
|
slug: role,
|
||||||
|
isOrgRole: true,
|
||||||
|
organization: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
|
|
||||||
if (!orgRole) throw BadRequestError({ message: "Role not found" });
|
if (!orgRole) throw BadRequestError({ message: "Role not found" });
|
||||||
|
|
||||||
|
const plan = await EELicenseService.getPlan(new Types.ObjectId(organizationId));
|
||||||
|
|
||||||
|
if (!plan.rbac) return res.status(400).send({
|
||||||
|
message:
|
||||||
|
"Failed to assign custom role due to RBAC restriction. Upgrade plan to assign custom role to member."
|
||||||
|
});
|
||||||
|
|
||||||
const membership = await MembershipOrg.findByIdAndUpdate(membershipId, {
|
const membership = await MembershipOrg.findByIdAndUpdate(membershipId, {
|
||||||
role: CUSTOM,
|
role: CUSTOM,
|
||||||
customRole: orgRole
|
customRole: orgRole
|
||||||
@ -198,11 +220,12 @@ export const updateOrganizationMembership = async (req: Request, res: Response)
|
|||||||
*/
|
*/
|
||||||
export const deleteOrganizationMembership = async (req: Request, res: Response) => {
|
export const deleteOrganizationMembership = async (req: Request, res: Response) => {
|
||||||
/*
|
/*
|
||||||
#swagger.summary = 'Delete organization membership'
|
#swagger.summary = 'Delete organization user membership'
|
||||||
#swagger.description = 'Delete organization membership'
|
#swagger.description = 'Delete organization user membership'
|
||||||
|
|
||||||
#swagger.security = [{
|
#swagger.security = [{
|
||||||
"apiKeyAuth": []
|
"apiKeyAuth": [],
|
||||||
|
"bearerAuth": []
|
||||||
}]
|
}]
|
||||||
|
|
||||||
#swagger.parameters['organizationId'] = {
|
#swagger.parameters['organizationId'] = {
|
||||||
@ -236,7 +259,18 @@ export const deleteOrganizationMembership = async (req: Request, res: Response)
|
|||||||
const {
|
const {
|
||||||
params: { organizationId, membershipId }
|
params: { organizationId, membershipId }
|
||||||
} = await validateRequest(reqValidator.DeleteOrgMemberv2, req);
|
} = await validateRequest(reqValidator.DeleteOrgMemberv2, req);
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
|
||||||
|
const membershipOrg = await MembershipOrg.findOne({
|
||||||
|
_id: new Types.ObjectId(membershipId),
|
||||||
|
organization: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!membershipOrg) throw ResourceNotFoundError();
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: membershipOrg.organization
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Delete,
|
OrgPermissionActions.Delete,
|
||||||
OrgPermissionSubjects.Member
|
OrgPermissionSubjects.Member
|
||||||
@ -268,7 +302,8 @@ export const getOrganizationWorkspaces = async (req: Request, res: Response) =>
|
|||||||
#swagger.description = 'Return projects in organization that user is part of'
|
#swagger.description = 'Return projects in organization that user is part of'
|
||||||
|
|
||||||
#swagger.security = [{
|
#swagger.security = [{
|
||||||
"apiKeyAuth": []
|
"apiKeyAuth": [],
|
||||||
|
"bearerAuth": []
|
||||||
}]
|
}]
|
||||||
|
|
||||||
#swagger.parameters['organizationId'] = {
|
#swagger.parameters['organizationId'] = {
|
||||||
@ -296,11 +331,16 @@ export const getOrganizationWorkspaces = async (req: Request, res: Response) =>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const {
|
const {
|
||||||
params: { organizationId }
|
params: { organizationId }
|
||||||
} = await validateRequest(reqValidator.GetOrgWorkspacesv2, req);
|
} = await validateRequest(reqValidator.GetOrgWorkspacesv2, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Read,
|
OrgPermissionActions.Read,
|
||||||
OrgPermissionSubjects.Workspace
|
OrgPermissionSubjects.Workspace
|
||||||
@ -317,36 +357,33 @@ export const getOrganizationWorkspaces = async (req: Request, res: Response) =>
|
|||||||
).map((w) => w._id.toString())
|
).map((w) => w._id.toString())
|
||||||
);
|
);
|
||||||
|
|
||||||
const workspaces = (
|
let workspaces: IWorkspace[] = [];
|
||||||
await Membership.find({
|
|
||||||
user: req.user._id
|
if (req.authData.authPayload instanceof Identity) {
|
||||||
}).populate("workspace")
|
workspaces = (
|
||||||
|
await IdentityMembership.find({
|
||||||
|
identity: req.authData.authPayload._id
|
||||||
|
}).populate<{ workspace: IWorkspace }>("workspace")
|
||||||
)
|
)
|
||||||
.filter((m) => workspacesSet.has(m.workspace._id.toString()))
|
.filter((m) => workspacesSet.has(m.workspace._id.toString()))
|
||||||
.map((m) => m.workspace);
|
.map((m) => m.workspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.authData.authPayload instanceof User) {
|
||||||
|
workspaces = (
|
||||||
|
await Membership.find({
|
||||||
|
user: req.authData.authPayload._id
|
||||||
|
}).populate<{ workspace: IWorkspace }>("workspace")
|
||||||
|
)
|
||||||
|
.filter((m) => workspacesSet.has(m.workspace._id.toString()))
|
||||||
|
.map((m) => m.workspace);
|
||||||
|
}
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
workspaces
|
workspaces
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Return service accounts for organization with id [organizationId]
|
|
||||||
* @param req
|
|
||||||
* @param res
|
|
||||||
*/
|
|
||||||
export const getOrganizationServiceAccounts = async (req: Request, res: Response) => {
|
|
||||||
const { organizationId } = req.params;
|
|
||||||
|
|
||||||
const serviceAccounts = await ServiceAccount.find({
|
|
||||||
organization: new Types.ObjectId(organizationId)
|
|
||||||
});
|
|
||||||
|
|
||||||
return res.status(200).send({
|
|
||||||
serviceAccounts
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new organization named [organizationName]
|
* Create new organization named [organizationName]
|
||||||
* and add user as owner
|
* and add user as owner
|
||||||
@ -402,4 +439,67 @@ export const deleteOrganizationById = async (req: Request, res: Response) => {
|
|||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
organization
|
organization
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return list of identity memberships for organization with id [organizationId]
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getOrganizationIdentityMemberships = async (req: Request, res: Response) => {
|
||||||
|
/*
|
||||||
|
#swagger.summary = 'Return organization identity memberships'
|
||||||
|
#swagger.description = 'Return organization identity memberships'
|
||||||
|
|
||||||
|
#swagger.security = [{
|
||||||
|
"bearerAuth": []
|
||||||
|
}]
|
||||||
|
|
||||||
|
#swagger.parameters['organizationId'] = {
|
||||||
|
"description": "ID of organization",
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"in": "path"
|
||||||
|
}
|
||||||
|
|
||||||
|
#swagger.responses[200] = {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"identityMemberships": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
$ref: "#/components/schemas/IdentityMembershipOrg"
|
||||||
|
},
|
||||||
|
"description": "Identity memberships of organization"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const {
|
||||||
|
params: { organizationId }
|
||||||
|
} = await validateRequest(reqValidator.GetOrgIdentityMembershipsV2, req);
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
OrgPermissionActions.Read,
|
||||||
|
OrgPermissionSubjects.Identity
|
||||||
|
);
|
||||||
|
|
||||||
|
const identityMemberships = await IdentityMembershipOrg.find({
|
||||||
|
organization: new Types.ObjectId(organizationId)
|
||||||
|
}).populate("identity customRole");
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
identityMemberships
|
||||||
|
});
|
||||||
}
|
}
|
@ -11,7 +11,6 @@ import {
|
|||||||
ValidationError as RouteValidationError,
|
ValidationError as RouteValidationError,
|
||||||
UnauthorizedRequestError
|
UnauthorizedRequestError
|
||||||
} from "../../utils/errors";
|
} from "../../utils/errors";
|
||||||
import { AnyBulkWriteOperation } from "mongodb";
|
|
||||||
import {
|
import {
|
||||||
ALGORITHM_AES_256_GCM,
|
ALGORITHM_AES_256_GCM,
|
||||||
ENCODING_SCHEME_UTF8,
|
ENCODING_SCHEME_UTF8,
|
||||||
@ -19,7 +18,7 @@ import {
|
|||||||
SECRET_SHARED
|
SECRET_SHARED
|
||||||
} from "../../variables";
|
} from "../../variables";
|
||||||
import { TelemetryService } from "../../services";
|
import { TelemetryService } from "../../services";
|
||||||
import { ISecret, Secret, User } from "../../models";
|
import { Secret, User } from "../../models";
|
||||||
import { AccountNotFoundError } from "../../utils/errors";
|
import { AccountNotFoundError } from "../../utils/errors";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -145,22 +144,22 @@ export const deleteSecrets = async (req: Request, res: Response) => {
|
|||||||
const secretsUserCanDeleteSet: Set<string> = new Set(
|
const secretsUserCanDeleteSet: Set<string> = new Set(
|
||||||
secretIdsUserCanDelete.map((objectId) => objectId._id.toString())
|
secretIdsUserCanDelete.map((objectId) => objectId._id.toString())
|
||||||
);
|
);
|
||||||
const deleteOperationsToPerform: AnyBulkWriteOperation<ISecret>[] = [];
|
|
||||||
|
|
||||||
let numSecretsDeleted = 0;
|
// Filter out IDs that user can delete and then map them to delete operations
|
||||||
secretIdsToDelete.forEach((secretIdToDelete) => {
|
const deleteOperationsToPerform = secretIdsToDelete
|
||||||
if (secretsUserCanDeleteSet.has(secretIdToDelete)) {
|
.filter(secretIdToDelete => {
|
||||||
const deleteOperation = {
|
if (!secretsUserCanDeleteSet.has(secretIdToDelete)) {
|
||||||
deleteOne: { filter: { _id: new Types.ObjectId(secretIdToDelete) } }
|
|
||||||
};
|
|
||||||
deleteOperationsToPerform.push(deleteOperation);
|
|
||||||
numSecretsDeleted++;
|
|
||||||
} else {
|
|
||||||
throw RouteValidationError({
|
throw RouteValidationError({
|
||||||
message: "You cannot delete secrets that you do not have access to"
|
message: "You cannot delete secrets that you do not have access to"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
return true;
|
||||||
|
})
|
||||||
|
.map(secretIdToDelete => ({
|
||||||
|
deleteOne: { filter: { _id: new Types.ObjectId(secretIdToDelete) } }
|
||||||
|
}));
|
||||||
|
|
||||||
|
const numSecretsDeleted = deleteOperationsToPerform.length;
|
||||||
|
|
||||||
await Secret.bulkWrite(deleteOperationsToPerform);
|
await Secret.bulkWrite(deleteOperationsToPerform);
|
||||||
|
|
@ -1,12 +1,8 @@
|
|||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
import { Folder, ISecret, Secret, ServiceTokenData, Tag } from "../../models";
|
import { Folder, ISecret, Secret, ServiceTokenData, Tag } from "../../models";
|
||||||
import { AuditLog, EventType, IAction, SecretVersion } from "../../ee/models";
|
import { AuditLog, EventType, SecretVersion } from "../../ee/models";
|
||||||
import {
|
import {
|
||||||
ACTION_ADD_SECRETS,
|
|
||||||
ACTION_DELETE_SECRETS,
|
|
||||||
ACTION_READ_SECRETS,
|
|
||||||
ACTION_UPDATE_SECRETS,
|
|
||||||
ALGORITHM_AES_256_GCM,
|
ALGORITHM_AES_256_GCM,
|
||||||
ENCODING_SCHEME_UTF8,
|
ENCODING_SCHEME_UTF8,
|
||||||
K8_USER_AGENT_NAME,
|
K8_USER_AGENT_NAME,
|
||||||
@ -15,7 +11,7 @@ import {
|
|||||||
import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors";
|
import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors";
|
||||||
import { EventService } from "../../services";
|
import { EventService } from "../../services";
|
||||||
import { eventPushSecrets } from "../../events";
|
import { eventPushSecrets } from "../../events";
|
||||||
import { EEAuditLogService, EELogService, EESecretService } from "../../ee/services";
|
import { EEAuditLogService, EESecretService } from "../../ee/services";
|
||||||
import { SecretService, TelemetryService } from "../../services";
|
import { SecretService, TelemetryService } from "../../services";
|
||||||
import { getUserAgentType } from "../../utils/posthog";
|
import { getUserAgentType } from "../../utils/posthog";
|
||||||
import { PERMISSION_WRITE_SECRETS } from "../../variables";
|
import { PERMISSION_WRITE_SECRETS } from "../../variables";
|
||||||
@ -43,7 +39,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
ProjectPermissionSub,
|
ProjectPermissionSub,
|
||||||
getUserProjectPermissions
|
getAuthDataProjectPermissions
|
||||||
} from "../../ee/services/ProjectRoleService";
|
} from "../../ee/services/ProjectRoleService";
|
||||||
import { ForbiddenError, subject } from "@casl/ability";
|
import { ForbiddenError, subject } from "@casl/ability";
|
||||||
|
|
||||||
@ -82,7 +78,6 @@ export const batchSecrets = async (req: Request, res: Response) => {
|
|||||||
const createSecrets: any[] = [];
|
const createSecrets: any[] = [];
|
||||||
const updateSecrets: any[] = [];
|
const updateSecrets: any[] = [];
|
||||||
const deleteSecrets: { _id: Types.ObjectId; secretName: string }[] = [];
|
const deleteSecrets: { _id: Types.ObjectId; secretName: string }[] = [];
|
||||||
const actions: IAction[] = [];
|
|
||||||
|
|
||||||
// get secret blind index salt
|
// get secret blind index salt
|
||||||
const salt = await SecretService.getSecretBlindIndexSalt({
|
const salt = await SecretService.getSecretBlindIndexSalt({
|
||||||
@ -164,7 +159,11 @@ export const batchSecrets = async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
// not using service token using auth
|
// not using service token using auth
|
||||||
if (!(req.authData.authPayload instanceof ServiceTokenData)) {
|
if (!(req.authData.authPayload instanceof ServiceTokenData)) {
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
if (createSecrets.length)
|
if (createSecrets.length)
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Create,
|
ProjectPermissionActions.Create,
|
||||||
@ -224,16 +223,6 @@ export const batchSecrets = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
await AuditLog.insertMany(auditLogs);
|
await AuditLog.insertMany(auditLogs);
|
||||||
|
|
||||||
const addAction = (await EELogService.createAction({
|
|
||||||
name: ACTION_ADD_SECRETS,
|
|
||||||
userId: req.user?._id,
|
|
||||||
serviceAccountId: req.serviceAccount?._id,
|
|
||||||
serviceTokenDataId: req.serviceTokenData?._id,
|
|
||||||
workspaceId: new Types.ObjectId(workspaceId),
|
|
||||||
secretIds: createdSecrets.map((n) => n._id)
|
|
||||||
})) as IAction;
|
|
||||||
actions.push(addAction);
|
|
||||||
|
|
||||||
if (postHogClient) {
|
if (postHogClient) {
|
||||||
postHogClient.capture({
|
postHogClient.capture({
|
||||||
event: "secrets added",
|
event: "secrets added",
|
||||||
@ -350,14 +339,6 @@ export const batchSecrets = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
await AuditLog.insertMany(auditLogs);
|
await AuditLog.insertMany(auditLogs);
|
||||||
|
|
||||||
const updateAction = (await EELogService.createAction({
|
|
||||||
name: ACTION_UPDATE_SECRETS,
|
|
||||||
userId: req.user._id,
|
|
||||||
workspaceId: new Types.ObjectId(workspaceId),
|
|
||||||
secretIds: updatedSecrets.map((u) => u._id)
|
|
||||||
})) as IAction;
|
|
||||||
actions.push(updateAction);
|
|
||||||
|
|
||||||
if (postHogClient) {
|
if (postHogClient) {
|
||||||
postHogClient.capture({
|
postHogClient.capture({
|
||||||
event: "secrets modified",
|
event: "secrets modified",
|
||||||
@ -428,14 +409,6 @@ export const batchSecrets = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
await AuditLog.insertMany(auditLogs);
|
await AuditLog.insertMany(auditLogs);
|
||||||
|
|
||||||
const deleteAction = (await EELogService.createAction({
|
|
||||||
name: ACTION_DELETE_SECRETS,
|
|
||||||
userId: req.user._id,
|
|
||||||
workspaceId: new Types.ObjectId(workspaceId),
|
|
||||||
secretIds: deleteSecretIds
|
|
||||||
})) as IAction;
|
|
||||||
actions.push(deleteAction);
|
|
||||||
|
|
||||||
if (postHogClient) {
|
if (postHogClient) {
|
||||||
postHogClient.capture({
|
postHogClient.capture({
|
||||||
event: "secrets deleted",
|
event: "secrets deleted",
|
||||||
@ -451,17 +424,6 @@ export const batchSecrets = async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actions.length > 0) {
|
|
||||||
// (EE) create (audit) log
|
|
||||||
await EELogService.createLog({
|
|
||||||
userId: req.user._id.toString(),
|
|
||||||
workspaceId: new Types.ObjectId(workspaceId),
|
|
||||||
actions,
|
|
||||||
channel,
|
|
||||||
ipAddress: req.realIP
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// // trigger event - push secrets
|
// // trigger event - push secrets
|
||||||
await EventService.handleEvent({
|
await EventService.handleEvent({
|
||||||
event: eventPushSecrets({
|
event: eventPushSecrets({
|
||||||
@ -731,27 +693,6 @@ export const createSecrets = async (req: Request, res: Response) => {
|
|||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
const addAction = await EELogService.createAction({
|
|
||||||
name: ACTION_ADD_SECRETS,
|
|
||||||
userId: req.user?._id,
|
|
||||||
serviceAccountId: req.serviceAccount?._id,
|
|
||||||
serviceTokenDataId: req.serviceTokenData?._id,
|
|
||||||
workspaceId: new Types.ObjectId(workspaceId),
|
|
||||||
secretIds: newlyCreatedSecrets.map((n) => n._id)
|
|
||||||
});
|
|
||||||
|
|
||||||
// (EE) create (audit) log
|
|
||||||
addAction &&
|
|
||||||
(await EELogService.createLog({
|
|
||||||
userId: req.user?._id,
|
|
||||||
serviceAccountId: req.serviceAccount?._id,
|
|
||||||
serviceTokenDataId: req.serviceTokenData?._id,
|
|
||||||
workspaceId: new Types.ObjectId(workspaceId),
|
|
||||||
actions: [addAction],
|
|
||||||
channel,
|
|
||||||
ipAddress: req.realIP
|
|
||||||
}));
|
|
||||||
|
|
||||||
// (EE) take a secret snapshot
|
// (EE) take a secret snapshot
|
||||||
await EESecretService.takeSecretSnapshot({
|
await EESecretService.takeSecretSnapshot({
|
||||||
workspaceId: new Types.ObjectId(workspaceId),
|
workspaceId: new Types.ObjectId(workspaceId),
|
||||||
@ -960,22 +901,6 @@ export const getSecrets = async (req: Request, res: Response) => {
|
|||||||
secrets = await Secret.find(secretQuery).populate("tags");
|
secrets = await Secret.find(secretQuery).populate("tags");
|
||||||
}
|
}
|
||||||
|
|
||||||
// case: client authorization is via service account
|
|
||||||
if (req.serviceAccount) {
|
|
||||||
const secretQuery: any = {
|
|
||||||
workspace: workspaceId,
|
|
||||||
environment,
|
|
||||||
folder: folderId,
|
|
||||||
user: { $exists: false } // shared secrets only from workspace
|
|
||||||
};
|
|
||||||
|
|
||||||
if (tagIds.length > 0) {
|
|
||||||
secretQuery.tags = { $in: tagIds };
|
|
||||||
}
|
|
||||||
|
|
||||||
secrets = await Secret.find(secretQuery).populate("tags");
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(akhilmhdh) - secret-imp change this to org type
|
// TODO(akhilmhdh) - secret-imp change this to org type
|
||||||
let importedSecrets: any[] = [];
|
let importedSecrets: any[] = [];
|
||||||
if (include_imports) {
|
if (include_imports) {
|
||||||
@ -988,28 +913,6 @@ export const getSecrets = async (req: Request, res: Response) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const channel = getUserAgentType(req.headers["user-agent"]);
|
|
||||||
|
|
||||||
const readAction = await EELogService.createAction({
|
|
||||||
name: ACTION_READ_SECRETS,
|
|
||||||
userId: req.user?._id,
|
|
||||||
serviceAccountId: req.serviceAccount?._id,
|
|
||||||
serviceTokenDataId: req.serviceTokenData?._id,
|
|
||||||
workspaceId: new Types.ObjectId(workspaceId as string),
|
|
||||||
secretIds: secrets.map((n: any) => n._id)
|
|
||||||
});
|
|
||||||
|
|
||||||
readAction &&
|
|
||||||
(await EELogService.createLog({
|
|
||||||
userId: req.user?._id,
|
|
||||||
serviceAccountId: req.serviceAccount?._id,
|
|
||||||
serviceTokenDataId: req.serviceTokenData?._id,
|
|
||||||
workspaceId: new Types.ObjectId(workspaceId as string),
|
|
||||||
actions: [readAction],
|
|
||||||
channel,
|
|
||||||
ipAddress: req.realIP
|
|
||||||
}));
|
|
||||||
|
|
||||||
await EEAuditLogService.createAuditLog(
|
await EEAuditLogService.createAuditLog(
|
||||||
req.authData,
|
req.authData,
|
||||||
{
|
{
|
||||||
@ -1247,27 +1150,6 @@ export const updateSecrets = async (req: Request, res: Response) => {
|
|||||||
// });
|
// });
|
||||||
// }, 10000);
|
// }, 10000);
|
||||||
|
|
||||||
const updateAction = await EELogService.createAction({
|
|
||||||
name: ACTION_UPDATE_SECRETS,
|
|
||||||
userId: req.user?._id,
|
|
||||||
serviceAccountId: req.serviceAccount?._id,
|
|
||||||
serviceTokenDataId: req.serviceTokenData?._id,
|
|
||||||
workspaceId: new Types.ObjectId(key),
|
|
||||||
secretIds: workspaceSecretObj[key].map((secret: ISecret) => secret._id)
|
|
||||||
});
|
|
||||||
|
|
||||||
// (EE) create (audit) log
|
|
||||||
updateAction &&
|
|
||||||
(await EELogService.createLog({
|
|
||||||
userId: req.user?._id,
|
|
||||||
serviceAccountId: req.serviceAccount?._id,
|
|
||||||
serviceTokenDataId: req.serviceTokenData?._id,
|
|
||||||
workspaceId: new Types.ObjectId(key),
|
|
||||||
actions: [updateAction],
|
|
||||||
channel,
|
|
||||||
ipAddress: req.realIP
|
|
||||||
}));
|
|
||||||
|
|
||||||
// (EE) take a secret snapshot
|
// (EE) take a secret snapshot
|
||||||
// IMP(akhilmhdh): commented out due to unknown where the environment is
|
// IMP(akhilmhdh): commented out due to unknown where the environment is
|
||||||
// await EESecretService.takeSecretSnapshot({
|
// await EESecretService.takeSecretSnapshot({
|
||||||
@ -1387,26 +1269,6 @@ export const deleteSecrets = async (req: Request, res: Response) => {
|
|||||||
// workspaceId: new Types.ObjectId(key)
|
// workspaceId: new Types.ObjectId(key)
|
||||||
// })
|
// })
|
||||||
// });
|
// });
|
||||||
const deleteAction = await EELogService.createAction({
|
|
||||||
name: ACTION_DELETE_SECRETS,
|
|
||||||
userId: req.user?._id,
|
|
||||||
serviceAccountId: req.serviceAccount?._id,
|
|
||||||
serviceTokenDataId: req.serviceTokenData?._id,
|
|
||||||
workspaceId: new Types.ObjectId(key),
|
|
||||||
secretIds: workspaceSecretObj[key].map((secret: ISecret) => secret._id)
|
|
||||||
});
|
|
||||||
|
|
||||||
// (EE) create (audit) log
|
|
||||||
deleteAction &&
|
|
||||||
(await EELogService.createLog({
|
|
||||||
userId: req.user?._id,
|
|
||||||
serviceAccountId: req.serviceAccount?._id,
|
|
||||||
serviceTokenDataId: req.serviceTokenData?._id,
|
|
||||||
workspaceId: new Types.ObjectId(key),
|
|
||||||
actions: [deleteAction],
|
|
||||||
channel,
|
|
||||||
ipAddress: req.realIP
|
|
||||||
}));
|
|
||||||
|
|
||||||
// (EE) take a secret snapshot
|
// (EE) take a secret snapshot
|
||||||
// IMP(akhilmhdh): Not sure how to take secretSnapshot
|
// IMP(akhilmhdh): Not sure how to take secretSnapshot
|
@ -11,9 +11,9 @@ import * as reqValidator from "../../validation/serviceTokenData";
|
|||||||
import {
|
import {
|
||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
ProjectPermissionSub,
|
ProjectPermissionSub,
|
||||||
getUserProjectPermissions
|
getAuthDataProjectPermissions
|
||||||
} from "../../ee/services/ProjectRoleService";
|
} from "../../ee/services/ProjectRoleService";
|
||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError, subject } from "@casl/ability";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -75,12 +75,25 @@ export const createServiceTokenData = async (req: Request, res: Response) => {
|
|||||||
const {
|
const {
|
||||||
body: { workspaceId, permissions, tag, encryptedKey, scopes, name, expiresIn, iv }
|
body: { workspaceId, permissions, tag, encryptedKey, scopes, name, expiresIn, iv }
|
||||||
} = await validateRequest(reqValidator.CreateServiceTokenV2, req);
|
} = await validateRequest(reqValidator.CreateServiceTokenV2, req);
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Create,
|
ProjectPermissionActions.Create,
|
||||||
ProjectPermissionSub.ServiceTokens
|
ProjectPermissionSub.ServiceTokens
|
||||||
);
|
);
|
||||||
|
|
||||||
|
scopes.forEach(({ environment, secretPath }) => {
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
subject(ProjectPermissionSub.Secrets, { environment, secretPath: secretPath })
|
||||||
|
);
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
const secret = crypto.randomBytes(16).toString("hex");
|
const secret = crypto.randomBytes(16).toString("hex");
|
||||||
const secretHash = await bcrypt.hash(secret, await getSaltRounds());
|
const secretHash = await bcrypt.hash(secret, await getSaltRounds());
|
||||||
|
|
||||||
@ -151,10 +164,11 @@ export const deleteServiceTokenData = async (req: Request, res: Response) => {
|
|||||||
let serviceTokenData = await ServiceTokenData.findById(serviceTokenDataId);
|
let serviceTokenData = await ServiceTokenData.findById(serviceTokenDataId);
|
||||||
if (!serviceTokenData) throw BadRequestError({ message: "Service token not found" });
|
if (!serviceTokenData) throw BadRequestError({ message: "Service token not found" });
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
req.user._id,
|
authData: req.authData,
|
||||||
serviceTokenData.workspace.toString()
|
workspaceId: serviceTokenData.workspace
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Delete,
|
ProjectPermissionActions.Delete,
|
||||||
ProjectPermissionSub.ServiceTokens
|
ProjectPermissionSub.ServiceTokens
|
@ -7,7 +7,7 @@ import { validateRequest } from "../../helpers/validation";
|
|||||||
import {
|
import {
|
||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
ProjectPermissionSub,
|
ProjectPermissionSub,
|
||||||
getUserProjectPermissions
|
getAuthDataProjectPermissions
|
||||||
} from "../../ee/services/ProjectRoleService";
|
} from "../../ee/services/ProjectRoleService";
|
||||||
import * as reqValidator from "../../validation/tags";
|
import * as reqValidator from "../../validation/tags";
|
||||||
|
|
||||||
@ -17,7 +17,11 @@ export const createWorkspaceTag = async (req: Request, res: Response) => {
|
|||||||
params: { workspaceId }
|
params: { workspaceId }
|
||||||
} = await validateRequest(reqValidator.CreateWorkspaceTagsV2, req);
|
} = await validateRequest(reqValidator.CreateWorkspaceTagsV2, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Create,
|
ProjectPermissionActions.Create,
|
||||||
ProjectPermissionSub.Tags
|
ProjectPermissionSub.Tags
|
||||||
@ -45,10 +49,11 @@ export const deleteWorkspaceTag = async (req: Request, res: Response) => {
|
|||||||
throw BadRequestError();
|
throw BadRequestError();
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
req.user._id,
|
authData: req.authData,
|
||||||
tagFromDB.workspace.toString()
|
workspaceId: tagFromDB.workspace
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Delete,
|
ProjectPermissionActions.Delete,
|
||||||
ProjectPermissionSub.Tags
|
ProjectPermissionSub.Tags
|
||||||
@ -66,7 +71,12 @@ export const getWorkspaceTags = async (req: Request, res: Response) => {
|
|||||||
const {
|
const {
|
||||||
params: { workspaceId }
|
params: { workspaceId }
|
||||||
} = await validateRequest(reqValidator.GetWorkspaceTagsV2, req);
|
} = await validateRequest(reqValidator.GetWorkspaceTagsV2, req);
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.Tags
|
ProjectPermissionSub.Tags
|
883
backend-mongo/src/controllers/v2/workspaceController.ts
Normal file
883
backend-mongo/src/controllers/v2/workspaceController.ts
Normal file
@ -0,0 +1,883 @@
|
|||||||
|
import { Request, Response } from "express";
|
||||||
|
import { Types } from "mongoose";
|
||||||
|
import {
|
||||||
|
IIdentity,
|
||||||
|
IdentityMembership,
|
||||||
|
IdentityMembershipOrg,
|
||||||
|
Key,
|
||||||
|
Membership,
|
||||||
|
ServiceTokenData,
|
||||||
|
Workspace
|
||||||
|
} from "../../models";
|
||||||
|
import { IRole, Role } from "../../ee/models";
|
||||||
|
import {
|
||||||
|
pullSecrets as pull,
|
||||||
|
v2PushSecrets as push,
|
||||||
|
reformatPullSecrets
|
||||||
|
} from "../../helpers/secret";
|
||||||
|
import { pushKeys } from "../../helpers/key";
|
||||||
|
import { EventService, TelemetryService } from "../../services";
|
||||||
|
import { eventPushSecrets } from "../../events";
|
||||||
|
import { EEAuditLogService } from "../../ee/services";
|
||||||
|
import { EventType } from "../../ee/models";
|
||||||
|
import { validateRequest } from "../../helpers/validation";
|
||||||
|
import * as reqValidator from "../../validation";
|
||||||
|
import {
|
||||||
|
ProjectPermissionActions,
|
||||||
|
ProjectPermissionSub,
|
||||||
|
getAuthDataProjectPermissions,
|
||||||
|
getWorkspaceRolePermissions,
|
||||||
|
isAtLeastAsPrivilegedWorkspace
|
||||||
|
} from "../../ee/services/ProjectRoleService";
|
||||||
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
import { BadRequestError, ForbiddenRequestError, ResourceNotFoundError } from "../../utils/errors";
|
||||||
|
import { ADMIN, CUSTOM, MEMBER, NO_ACCESS, VIEWER } from "../../variables";
|
||||||
|
|
||||||
|
interface V2PushSecret {
|
||||||
|
type: string; // personal or shared
|
||||||
|
secretKeyCiphertext: string;
|
||||||
|
secretKeyIV: string;
|
||||||
|
secretKeyTag: string;
|
||||||
|
secretKeyHash: string;
|
||||||
|
secretValueCiphertext: string;
|
||||||
|
secretValueIV: string;
|
||||||
|
secretValueTag: string;
|
||||||
|
secretValueHash: string;
|
||||||
|
secretCommentCiphertext?: string;
|
||||||
|
secretCommentIV?: string;
|
||||||
|
secretCommentTag?: string;
|
||||||
|
secretCommentHash?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upload (encrypted) secrets to workspace with id [workspaceId]
|
||||||
|
* for environment [environment]
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const pushWorkspaceSecrets = async (req: Request, res: Response) => {
|
||||||
|
// upload (encrypted) secrets to workspace with id [workspaceId]
|
||||||
|
const postHogClient = await TelemetryService.getPostHogClient();
|
||||||
|
let { secrets }: { secrets: V2PushSecret[] } = req.body;
|
||||||
|
const { keys, environment, channel } = req.body;
|
||||||
|
const { workspaceId } = req.params;
|
||||||
|
|
||||||
|
// validate environment
|
||||||
|
const workspaceEnvs = req.membership.workspace.environments;
|
||||||
|
if (!workspaceEnvs.find(({ slug }: { slug: string }) => slug === environment)) {
|
||||||
|
throw new Error("Failed to validate environment");
|
||||||
|
}
|
||||||
|
|
||||||
|
// sanitize secrets
|
||||||
|
secrets = secrets.filter(
|
||||||
|
(s: V2PushSecret) => s.secretKeyCiphertext !== "" && s.secretValueCiphertext !== ""
|
||||||
|
);
|
||||||
|
|
||||||
|
await push({
|
||||||
|
userId: req.user._id,
|
||||||
|
workspaceId,
|
||||||
|
environment,
|
||||||
|
secrets,
|
||||||
|
channel: channel ? channel : "cli",
|
||||||
|
ipAddress: req.realIP
|
||||||
|
});
|
||||||
|
|
||||||
|
await pushKeys({
|
||||||
|
userId: req.user._id,
|
||||||
|
workspaceId,
|
||||||
|
keys
|
||||||
|
});
|
||||||
|
|
||||||
|
if (postHogClient) {
|
||||||
|
postHogClient.capture({
|
||||||
|
event: "secrets pushed",
|
||||||
|
distinctId: req.user.email,
|
||||||
|
properties: {
|
||||||
|
numberOfSecrets: secrets.length,
|
||||||
|
environment,
|
||||||
|
workspaceId,
|
||||||
|
channel: channel ? channel : "cli"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// trigger event - push secrets
|
||||||
|
EventService.handleEvent({
|
||||||
|
event: eventPushSecrets({
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId),
|
||||||
|
environment,
|
||||||
|
secretPath: "/"
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
message: "Successfully uploaded workspace secrets"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return (encrypted) secrets for workspace with id [workspaceId]
|
||||||
|
* for environment [environment]
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const pullSecrets = async (req: Request, res: Response) => {
|
||||||
|
let secrets;
|
||||||
|
const postHogClient = await TelemetryService.getPostHogClient();
|
||||||
|
const environment: string = req.query.environment as string;
|
||||||
|
const channel: string = req.query.channel as string;
|
||||||
|
const { workspaceId } = req.params;
|
||||||
|
|
||||||
|
let userId;
|
||||||
|
if (req.user) {
|
||||||
|
userId = req.user._id.toString();
|
||||||
|
} else if (req.serviceTokenData) {
|
||||||
|
userId = req.serviceTokenData.user.toString();
|
||||||
|
}
|
||||||
|
// validate environment
|
||||||
|
const workspaceEnvs = req.membership.workspace.environments;
|
||||||
|
if (!workspaceEnvs.find(({ slug }: { slug: string }) => slug === environment)) {
|
||||||
|
throw new Error("Failed to validate environment");
|
||||||
|
}
|
||||||
|
|
||||||
|
secrets = await pull({
|
||||||
|
userId,
|
||||||
|
workspaceId,
|
||||||
|
environment,
|
||||||
|
channel: channel ? channel : "cli",
|
||||||
|
ipAddress: req.realIP
|
||||||
|
});
|
||||||
|
|
||||||
|
if (channel !== "cli") {
|
||||||
|
secrets = reformatPullSecrets({ secrets });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (postHogClient) {
|
||||||
|
// capture secrets pushed event in production
|
||||||
|
postHogClient.capture({
|
||||||
|
distinctId: req.user.email,
|
||||||
|
event: "secrets pulled",
|
||||||
|
properties: {
|
||||||
|
numberOfSecrets: secrets.length,
|
||||||
|
environment,
|
||||||
|
workspaceId,
|
||||||
|
channel: channel ? channel : "cli"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
secrets
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getWorkspaceKey = async (req: Request, res: Response) => {
|
||||||
|
/*
|
||||||
|
#swagger.summary = 'Return encrypted project key'
|
||||||
|
#swagger.description = 'Return encrypted project key'
|
||||||
|
|
||||||
|
#swagger.security = [{
|
||||||
|
"apiKeyAuth": []
|
||||||
|
}]
|
||||||
|
|
||||||
|
#swagger.parameters['workspaceId'] = {
|
||||||
|
"description": "ID of project",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
|
||||||
|
#swagger.responses[200] = {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
$ref: "#/components/schemas/ProjectKey"
|
||||||
|
},
|
||||||
|
"description": "Encrypted project key for the given project"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const {
|
||||||
|
params: { workspaceId }
|
||||||
|
} = await validateRequest(reqValidator.GetWorkspaceKeyV2, req);
|
||||||
|
|
||||||
|
const key = await Key.findOne({
|
||||||
|
workspace: workspaceId,
|
||||||
|
receiver: req.user._id
|
||||||
|
}).populate("sender", "+publicKey");
|
||||||
|
|
||||||
|
if (!key) throw new Error(`getWorkspaceKey: Failed to find workspace key [workspaceId=${workspaceId}] [receiver=${req.user._id}]`);
|
||||||
|
|
||||||
|
await EEAuditLogService.createAuditLog(
|
||||||
|
req.authData,
|
||||||
|
{
|
||||||
|
type: EventType.GET_WORKSPACE_KEY,
|
||||||
|
metadata: {
|
||||||
|
keyId: key._id.toString()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return res.status(200).json(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getWorkspaceServiceTokenData = async (req: Request, res: Response) => {
|
||||||
|
const { workspaceId } = req.params;
|
||||||
|
|
||||||
|
const serviceTokenData = await ServiceTokenData.find({
|
||||||
|
workspace: workspaceId
|
||||||
|
}).select("+encryptedKey +iv +tag");
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
serviceTokenData
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return memberships for workspace with id [workspaceId]
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getWorkspaceMemberships = async (req: Request, res: Response) => {
|
||||||
|
/*
|
||||||
|
#swagger.summary = 'Return project user memberships'
|
||||||
|
#swagger.description = 'Return project user memberships'
|
||||||
|
|
||||||
|
#swagger.security = [{
|
||||||
|
"apiKeyAuth": [],
|
||||||
|
"bearerAuth": []
|
||||||
|
}]
|
||||||
|
|
||||||
|
#swagger.parameters['workspaceId'] = {
|
||||||
|
"description": "ID of project",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
|
||||||
|
#swagger.responses[200] = {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"memberships": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
$ref: "#/components/schemas/Membership"
|
||||||
|
},
|
||||||
|
"description": "Memberships of project"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const {
|
||||||
|
params: { workspaceId }
|
||||||
|
} = await validateRequest(reqValidator.GetWorkspaceMembershipsV2, req);
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Read,
|
||||||
|
ProjectPermissionSub.Member
|
||||||
|
);
|
||||||
|
|
||||||
|
const memberships = await Membership.find({
|
||||||
|
workspace: workspaceId
|
||||||
|
}).populate("user", "+publicKey");
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
memberships
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update role of membership with id [membershipId] to role [role]
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const updateWorkspaceMembership = async (req: Request, res: Response) => {
|
||||||
|
/*
|
||||||
|
#swagger.summary = 'Update project user membership'
|
||||||
|
#swagger.description = 'Update project user membership'
|
||||||
|
|
||||||
|
#swagger.security = [{
|
||||||
|
"apiKeyAuth": [],
|
||||||
|
"bearerAuth": []
|
||||||
|
}]
|
||||||
|
|
||||||
|
#swagger.parameters['workspaceId'] = {
|
||||||
|
"description": "ID of project",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
|
||||||
|
#swagger.parameters['membershipId'] = {
|
||||||
|
"description": "ID of project membership to update",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
|
||||||
|
#swagger.requestBody = {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"role": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Role to update to for project membership",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#swagger.responses[200] = {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"membership": {
|
||||||
|
$ref: "#/components/schemas/Membership",
|
||||||
|
"description": "Updated membership"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const {
|
||||||
|
params: { workspaceId, membershipId },
|
||||||
|
body: { role }
|
||||||
|
} = await validateRequest(reqValidator.UpdateWorkspaceMembershipsV2, req);
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionSub.Member
|
||||||
|
);
|
||||||
|
|
||||||
|
const membership = await Membership.findByIdAndUpdate(
|
||||||
|
membershipId,
|
||||||
|
{
|
||||||
|
role
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
membership
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete workspace membership with id [membershipId]
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const deleteWorkspaceMembership = async (req: Request, res: Response) => {
|
||||||
|
/*
|
||||||
|
#swagger.summary = 'Delete project user membership'
|
||||||
|
#swagger.description = 'Delete project user membership'
|
||||||
|
|
||||||
|
#swagger.security = [{
|
||||||
|
"apiKeyAuth": [],
|
||||||
|
"bearerAuth": []
|
||||||
|
}]
|
||||||
|
|
||||||
|
#swagger.parameters['workspaceId'] = {
|
||||||
|
"description": "ID of project",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
|
||||||
|
#swagger.parameters['membershipId'] = {
|
||||||
|
"description": "ID of project membership to delete",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
|
||||||
|
#swagger.responses[200] = {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"membership": {
|
||||||
|
$ref: "#/components/schemas/Membership",
|
||||||
|
"description": "Deleted membership"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const {
|
||||||
|
params: { workspaceId, membershipId }
|
||||||
|
} = await validateRequest(reqValidator.DeleteWorkspaceMembershipsV2, req);
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Delete,
|
||||||
|
ProjectPermissionSub.Member
|
||||||
|
);
|
||||||
|
|
||||||
|
const membership = await Membership.findByIdAndDelete(membershipId);
|
||||||
|
|
||||||
|
if (!membership) throw new Error("Failed to delete workspace membership");
|
||||||
|
|
||||||
|
await Key.deleteMany({
|
||||||
|
receiver: membership.user,
|
||||||
|
workspace: membership.workspace
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
membership
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change autoCapitilzation Rule of workspace
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const toggleAutoCapitalization = async (req: Request, res: Response) => {
|
||||||
|
const {
|
||||||
|
params: { workspaceId },
|
||||||
|
body: { autoCapitalization }
|
||||||
|
} = await validateRequest(reqValidator.ToggleAutoCapitalizationV2, req);
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionSub.Settings
|
||||||
|
);
|
||||||
|
|
||||||
|
const workspace = await Workspace.findOneAndUpdate(
|
||||||
|
{
|
||||||
|
_id: workspaceId
|
||||||
|
},
|
||||||
|
{
|
||||||
|
autoCapitalization
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
message: "Successfully changed autoCapitalization setting",
|
||||||
|
workspace
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add identity with id [identityId] to workspace
|
||||||
|
* with id [workspaceId]
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
*/
|
||||||
|
export const addIdentityToWorkspace = async (req: Request, res: Response) => {
|
||||||
|
const {
|
||||||
|
params: { workspaceId, identityId },
|
||||||
|
body: {
|
||||||
|
role
|
||||||
|
}
|
||||||
|
} = await validateRequest(reqValidator.AddIdentityToWorkspaceV2, req);
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionSub.Identity
|
||||||
|
);
|
||||||
|
|
||||||
|
let identityMembership = await IdentityMembership.findOne({
|
||||||
|
identity: new Types.ObjectId(identityId),
|
||||||
|
workspace: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (identityMembership) throw BadRequestError({
|
||||||
|
message: `Identity with id ${identityId} already exists in project with id ${workspaceId}`
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const workspace = await Workspace.findById(workspaceId);
|
||||||
|
if (!workspace) throw ResourceNotFoundError();
|
||||||
|
|
||||||
|
const identityMembershipOrg = await IdentityMembershipOrg.findOne({
|
||||||
|
identity: new Types.ObjectId(identityId),
|
||||||
|
organization: workspace.organization
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!identityMembershipOrg) throw ResourceNotFoundError({
|
||||||
|
message: `Failed to find identity with id ${identityId}`
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!identityMembershipOrg.organization.equals(workspace.organization)) throw BadRequestError({
|
||||||
|
message: "Failed to add identity to project in another organization"
|
||||||
|
});
|
||||||
|
|
||||||
|
const rolePermission = await getWorkspaceRolePermissions(role, workspaceId);
|
||||||
|
const isAsPrivilegedAsIntendedRole = isAtLeastAsPrivilegedWorkspace(permission, rolePermission);
|
||||||
|
|
||||||
|
if (!isAsPrivilegedAsIntendedRole) throw ForbiddenRequestError({
|
||||||
|
message: "Failed to add identity to project with more privileged role"
|
||||||
|
});
|
||||||
|
|
||||||
|
let customRole;
|
||||||
|
if (role) {
|
||||||
|
const isCustomRole = ![ADMIN, MEMBER, VIEWER, NO_ACCESS].includes(role);
|
||||||
|
if (isCustomRole) {
|
||||||
|
customRole = await Role.findOne({
|
||||||
|
slug: role,
|
||||||
|
isOrgRole: false,
|
||||||
|
workspace: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!customRole) throw BadRequestError({ message: "Role not found" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
identityMembership = await new IdentityMembership({
|
||||||
|
identity: identityMembershipOrg.identity,
|
||||||
|
workspace: new Types.ObjectId(workspaceId),
|
||||||
|
role: customRole ? CUSTOM : role,
|
||||||
|
customRole
|
||||||
|
}).save();
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
identityMembership
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update role of identity with id [identityId] in workspace
|
||||||
|
* with id [workspaceId] to [role]
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
*/
|
||||||
|
export const updateIdentityWorkspaceRole = async (req: Request, res: Response) => {
|
||||||
|
/*
|
||||||
|
#swagger.summary = 'Update project identity membership'
|
||||||
|
#swagger.description = 'Update project identity membership'
|
||||||
|
|
||||||
|
#swagger.security = [{
|
||||||
|
"bearerAuth": []
|
||||||
|
}]
|
||||||
|
|
||||||
|
#swagger.parameters['workspaceId'] = {
|
||||||
|
"description": "ID of project",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
|
||||||
|
#swagger.parameters['identityId'] = {
|
||||||
|
"description": "ID of identity whose membership to update in project",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
|
||||||
|
#swagger.requestBody = {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"role": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Role to update to for identity project membership",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#swagger.responses[200] = {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"identityMembership": {
|
||||||
|
$ref: "#/components/schemas/IdentityMembership",
|
||||||
|
"description": "Updated identity membership"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const {
|
||||||
|
params: { workspaceId, identityId },
|
||||||
|
body: {
|
||||||
|
role
|
||||||
|
}
|
||||||
|
} = await validateRequest(reqValidator.UpdateIdentityWorkspaceRoleV2, req);
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionSub.Identity
|
||||||
|
);
|
||||||
|
|
||||||
|
let identityMembership = await IdentityMembership
|
||||||
|
.findOne({
|
||||||
|
identity: new Types.ObjectId(identityId),
|
||||||
|
workspace: new Types.ObjectId(workspaceId)
|
||||||
|
})
|
||||||
|
.populate<{
|
||||||
|
identity: IIdentity,
|
||||||
|
customRole: IRole
|
||||||
|
}>("identity customRole");
|
||||||
|
|
||||||
|
if (!identityMembership) throw BadRequestError({
|
||||||
|
message: `Identity with id ${identityId} does not exist in project with id ${workspaceId}`
|
||||||
|
});
|
||||||
|
|
||||||
|
const identityRolePermission = await getWorkspaceRolePermissions(
|
||||||
|
identityMembership?.customRole?.slug ?? identityMembership.role,
|
||||||
|
identityMembership.workspace.toString()
|
||||||
|
);
|
||||||
|
const isAsPrivilegedAsIdentity = isAtLeastAsPrivilegedWorkspace(permission, identityRolePermission);
|
||||||
|
if (!isAsPrivilegedAsIdentity) throw ForbiddenRequestError({
|
||||||
|
message: "Failed to update role of more privileged identity"
|
||||||
|
});
|
||||||
|
|
||||||
|
const rolePermission = await getWorkspaceRolePermissions(role, workspaceId);
|
||||||
|
const isAsPrivilegedAsIntendedRole = isAtLeastAsPrivilegedWorkspace(permission, rolePermission);
|
||||||
|
|
||||||
|
if (!isAsPrivilegedAsIntendedRole) throw ForbiddenRequestError({
|
||||||
|
message: "Failed to update identity to a more privileged role"
|
||||||
|
});
|
||||||
|
|
||||||
|
let customRole;
|
||||||
|
if (role) {
|
||||||
|
const isCustomRole = ![ADMIN, MEMBER, VIEWER, NO_ACCESS].includes(role);
|
||||||
|
if (isCustomRole) {
|
||||||
|
customRole = await Role.findOne({
|
||||||
|
slug: role,
|
||||||
|
isOrgRole: false,
|
||||||
|
workspace: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!customRole) throw BadRequestError({ message: "Role not found" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
identityMembership = await IdentityMembership.findOneAndUpdate(
|
||||||
|
{
|
||||||
|
identity: identityMembership.identity._id,
|
||||||
|
workspace: new Types.ObjectId(workspaceId),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: customRole ? CUSTOM : role,
|
||||||
|
customRole
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
identityMembership
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete identity with id [identityId] from workspace
|
||||||
|
* with id [workspaceId]
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
*/
|
||||||
|
export const deleteIdentityFromWorkspace = async (req: Request, res: Response) => {
|
||||||
|
/*
|
||||||
|
#swagger.summary = 'Delete project identity membership'
|
||||||
|
#swagger.description = 'Delete project identity membership'
|
||||||
|
|
||||||
|
#swagger.security = [{
|
||||||
|
"bearerAuth": []
|
||||||
|
}]
|
||||||
|
|
||||||
|
#swagger.parameters['workspaceId'] = {
|
||||||
|
"description": "ID of project",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
|
||||||
|
#swagger.parameters['identityId'] = {
|
||||||
|
"description": "ID of identity whose membership to delete in project",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
|
||||||
|
#swagger.responses[200] = {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"identityMembership": {
|
||||||
|
$ref: "#/components/schemas/IdentityMembership",
|
||||||
|
"description": "Deleted identity membership"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const {
|
||||||
|
params: { workspaceId, identityId }
|
||||||
|
} = await validateRequest(reqValidator.DeleteIdentityFromWorkspaceV2, req);
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Delete,
|
||||||
|
ProjectPermissionSub.Identity
|
||||||
|
);
|
||||||
|
|
||||||
|
const identityMembership = await IdentityMembership
|
||||||
|
.findOne({
|
||||||
|
identity: new Types.ObjectId(identityId),
|
||||||
|
workspace: new Types.ObjectId(workspaceId)
|
||||||
|
})
|
||||||
|
.populate<{
|
||||||
|
identity: IIdentity,
|
||||||
|
customRole: IRole
|
||||||
|
}>("identity customRole");
|
||||||
|
|
||||||
|
if (!identityMembership) throw ResourceNotFoundError({
|
||||||
|
message: `Identity with id ${identityId} does not exist in project with id ${workspaceId}`
|
||||||
|
});
|
||||||
|
|
||||||
|
const identityRolePermission = await getWorkspaceRolePermissions(
|
||||||
|
identityMembership?.customRole?.slug ?? identityMembership.role,
|
||||||
|
identityMembership.workspace.toString()
|
||||||
|
);
|
||||||
|
const isAsPrivilegedAsIdentity = isAtLeastAsPrivilegedWorkspace(permission, identityRolePermission);
|
||||||
|
if (!isAsPrivilegedAsIdentity) throw ForbiddenRequestError({
|
||||||
|
message: "Failed to remove more privileged identity from project"
|
||||||
|
});
|
||||||
|
|
||||||
|
await IdentityMembership.findByIdAndDelete(identityMembership._id);
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
identityMembership
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return list of identity memberships for workspace with id [workspaceId]
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getWorkspaceIdentityMemberships = async (req: Request, res: Response) => {
|
||||||
|
/*
|
||||||
|
#swagger.summary = 'Return project identity memberships'
|
||||||
|
#swagger.description = 'Return project identity memberships'
|
||||||
|
|
||||||
|
#swagger.security = [{
|
||||||
|
"bearerAuth": []
|
||||||
|
}]
|
||||||
|
|
||||||
|
#swagger.parameters['workspaceId'] = {
|
||||||
|
"description": "ID of project",
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"in": "path"
|
||||||
|
}
|
||||||
|
|
||||||
|
#swagger.responses[200] = {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"identityMemberships": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
$ref: "#/components/schemas/IdentityMembership"
|
||||||
|
},
|
||||||
|
"description": "Identity memberships of project"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const {
|
||||||
|
params: { workspaceId }
|
||||||
|
} = await validateRequest(reqValidator.GetWorkspaceIdentityMembersV2, req);
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Read,
|
||||||
|
ProjectPermissionSub.Identity
|
||||||
|
);
|
||||||
|
|
||||||
|
const identityMemberships = await IdentityMembership.find({
|
||||||
|
workspace: new Types.ObjectId(workspaceId)
|
||||||
|
}).populate("identity customRole");
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
identityMemberships
|
||||||
|
});
|
||||||
|
}
|
@ -8,10 +8,8 @@ import { createToken, issueAuthTokens, validateProviderAuthToken } from "../../h
|
|||||||
import { checkUserDevice } from "../../helpers/user";
|
import { checkUserDevice } from "../../helpers/user";
|
||||||
import { sendMail } from "../../helpers/nodemailer";
|
import { sendMail } from "../../helpers/nodemailer";
|
||||||
import { TokenService } from "../../services";
|
import { TokenService } from "../../services";
|
||||||
import { EELogService } from "../../ee/services";
|
|
||||||
import { BadRequestError, InternalServerError } from "../../utils/errors";
|
import { BadRequestError, InternalServerError } from "../../utils/errors";
|
||||||
import { ACTION_LOGIN, AuthTokenType, TOKEN_EMAIL_MFA } from "../../variables";
|
import { AuthTokenType, TOKEN_EMAIL_MFA } from "../../variables";
|
||||||
import { getUserAgentType } from "../../utils/posthog"; // TODO: move this
|
|
||||||
import { getAuthSecret, getHttpsEnabled, getJwtMfaLifetime } from "../../config";
|
import { getAuthSecret, getHttpsEnabled, getJwtMfaLifetime } from "../../config";
|
||||||
import { AuthMethod } from "../../models/user";
|
import { AuthMethod } from "../../models/user";
|
||||||
import { validateRequest } from "../../helpers/validation";
|
import { validateRequest } from "../../helpers/validation";
|
||||||
@ -215,19 +213,6 @@ export const login2 = async (req: Request, res: Response) => {
|
|||||||
response.protectedKeyTag = user.protectedKeyTag;
|
response.protectedKeyTag = user.protectedKeyTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
const loginAction = await EELogService.createAction({
|
|
||||||
name: ACTION_LOGIN,
|
|
||||||
userId: user._id
|
|
||||||
});
|
|
||||||
|
|
||||||
loginAction &&
|
|
||||||
(await EELogService.createLog({
|
|
||||||
userId: user._id,
|
|
||||||
actions: [loginAction],
|
|
||||||
channel: getUserAgentType(req.headers["user-agent"]),
|
|
||||||
ipAddress: req.realIP
|
|
||||||
}));
|
|
||||||
|
|
||||||
return res.status(200).send(response);
|
return res.status(200).send(response);
|
||||||
}
|
}
|
||||||
|
|
@ -1,9 +1,11 @@
|
|||||||
|
import * as usersController from "./usersController";
|
||||||
import * as secretsController from "./secretsController";
|
import * as secretsController from "./secretsController";
|
||||||
import * as workspacesController from "./workspacesController";
|
import * as workspacesController from "./workspacesController";
|
||||||
import * as authController from "./authController";
|
import * as authController from "./authController";
|
||||||
import * as signupController from "./signupController";
|
import * as signupController from "./signupController";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
usersController,
|
||||||
authController,
|
authController,
|
||||||
secretsController,
|
secretsController,
|
||||||
signupController,
|
signupController,
|
1461
backend-mongo/src/controllers/v3/secretsController.ts
Normal file
1461
backend-mongo/src/controllers/v3/secretsController.ts
Normal file
File diff suppressed because it is too large
Load Diff
18
backend-mongo/src/controllers/v3/usersController.ts
Normal file
18
backend-mongo/src/controllers/v3/usersController.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { Request, Response } from "express";
|
||||||
|
import { APIKeyDataV2 } from "../../models";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return API keys belonging to current user.
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getMyAPIKeys = async (req: Request, res: Response) => {
|
||||||
|
const apiKeyData = await APIKeyDataV2.find({
|
||||||
|
user: req.user._id
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
apiKeyData
|
||||||
|
});
|
||||||
|
}
|
@ -1,9 +1,9 @@
|
|||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { validateRequest } from "../../helpers/validation";
|
import { validateRequest } from "../../helpers/validation";
|
||||||
import { Secret, ServiceTokenDataV3 } from "../../models";
|
import { Membership, Secret, User } from "../../models";
|
||||||
import { SecretService } from "../../services";
|
import { SecretService } from "../../services";
|
||||||
import { getUserProjectPermissions } from "../../ee/services/ProjectRoleService";
|
import { getAuthDataProjectPermissions } from "../../ee/services/ProjectRoleService";
|
||||||
import { UnauthorizedRequestError } from "../../utils/errors";
|
import { UnauthorizedRequestError } from "../../utils/errors";
|
||||||
import * as reqValidator from "../../validation/workspace";
|
import * as reqValidator from "../../validation/workspace";
|
||||||
|
|
||||||
@ -19,9 +19,22 @@ export const getWorkspaceBlindIndexStatus = async (req: Request, res: Response)
|
|||||||
params: { workspaceId }
|
params: { workspaceId }
|
||||||
} = await validateRequest(reqValidator.GetWorkspaceBlinkIndexStatusV3, req);
|
} = await validateRequest(reqValidator.GetWorkspaceBlinkIndexStatusV3, req);
|
||||||
|
|
||||||
const { membership } = await getUserProjectPermissions(req.user._id, workspaceId);
|
await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (req.authData.authPayload instanceof User) {
|
||||||
|
const membership = await Membership.findOne({
|
||||||
|
user: req.authData.authPayload._id,
|
||||||
|
workspace: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!membership) throw UnauthorizedRequestError();
|
||||||
|
|
||||||
if (membership.role !== "admin")
|
if (membership.role !== "admin")
|
||||||
throw UnauthorizedRequestError({ message: "User must be an admin" });
|
throw UnauthorizedRequestError({ message: "User must be an admin" });
|
||||||
|
}
|
||||||
|
|
||||||
const secretsWithoutBlindIndex = await Secret.countDocuments({
|
const secretsWithoutBlindIndex = await Secret.countDocuments({
|
||||||
workspace: new Types.ObjectId(workspaceId),
|
workspace: new Types.ObjectId(workspaceId),
|
||||||
@ -41,9 +54,22 @@ export const getWorkspaceSecrets = async (req: Request, res: Response) => {
|
|||||||
params: { workspaceId }
|
params: { workspaceId }
|
||||||
} = await validateRequest(reqValidator.GetWorkspaceSecretsV3, req);
|
} = await validateRequest(reqValidator.GetWorkspaceSecretsV3, req);
|
||||||
|
|
||||||
const { membership } = await getUserProjectPermissions(req.user._id, workspaceId);
|
await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (req.authData.authPayload instanceof User) {
|
||||||
|
const membership = await Membership.findOne({
|
||||||
|
user: req.authData.authPayload._id,
|
||||||
|
workspace: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!membership) throw UnauthorizedRequestError();
|
||||||
|
|
||||||
if (membership.role !== "admin")
|
if (membership.role !== "admin")
|
||||||
throw UnauthorizedRequestError({ message: "User must be an admin" });
|
throw UnauthorizedRequestError({ message: "User must be an admin" });
|
||||||
|
}
|
||||||
|
|
||||||
const secrets = await Secret.find({
|
const secrets = await Secret.find({
|
||||||
workspace: new Types.ObjectId(workspaceId)
|
workspace: new Types.ObjectId(workspaceId)
|
||||||
@ -65,9 +91,22 @@ export const nameWorkspaceSecrets = async (req: Request, res: Response) => {
|
|||||||
body: { secretsToUpdate }
|
body: { secretsToUpdate }
|
||||||
} = await validateRequest(reqValidator.NameWorkspaceSecretsV3, req);
|
} = await validateRequest(reqValidator.NameWorkspaceSecretsV3, req);
|
||||||
|
|
||||||
const { membership } = await getUserProjectPermissions(req.user._id, workspaceId);
|
await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (req.authData.authPayload instanceof User) {
|
||||||
|
const membership = await Membership.findOne({
|
||||||
|
user: req.authData.authPayload._id,
|
||||||
|
workspace: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!membership) throw UnauthorizedRequestError();
|
||||||
|
|
||||||
if (membership.role !== "admin")
|
if (membership.role !== "admin")
|
||||||
throw UnauthorizedRequestError({ message: "User must be an admin" });
|
throw UnauthorizedRequestError({ message: "User must be an admin" });
|
||||||
|
}
|
||||||
|
|
||||||
// get secret blind index salt
|
// get secret blind index salt
|
||||||
const salt = await SecretService.getSecretBlindIndexSalt({
|
const salt = await SecretService.getSecretBlindIndexSalt({
|
||||||
@ -101,17 +140,3 @@ export const nameWorkspaceSecrets = async (req: Request, res: Response) => {
|
|||||||
message: "Successfully named workspace secrets"
|
message: "Successfully named workspace secrets"
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getWorkspaceServiceTokenData = async (req: Request, res: Response) => {
|
|
||||||
const {
|
|
||||||
params: { workspaceId }
|
|
||||||
} = await validateRequest(reqValidator.GetWorkspaceServiceTokenDataV3, req);
|
|
||||||
|
|
||||||
const serviceTokenData = await ServiceTokenDataV3.find({
|
|
||||||
workspace: new Types.ObjectId(workspaceId)
|
|
||||||
});
|
|
||||||
|
|
||||||
return res.status(200).send({
|
|
||||||
serviceTokenData
|
|
||||||
});
|
|
||||||
}
|
|
460
backend-mongo/src/ee/controllers/v1/identitiesController.ts
Normal file
460
backend-mongo/src/ee/controllers/v1/identitiesController.ts
Normal file
@ -0,0 +1,460 @@
|
|||||||
|
import { Request, Response } from "express";
|
||||||
|
import { Types } from "mongoose";
|
||||||
|
import {
|
||||||
|
IIdentity,
|
||||||
|
Identity,
|
||||||
|
IdentityAccessToken,
|
||||||
|
IdentityMembership,
|
||||||
|
IdentityMembershipOrg,
|
||||||
|
IdentityUniversalAuth,
|
||||||
|
IdentityUniversalAuthClientSecret,
|
||||||
|
Organization
|
||||||
|
} from "../../../models";
|
||||||
|
import {
|
||||||
|
EventType,
|
||||||
|
IRole,
|
||||||
|
Role
|
||||||
|
} from "../../models";
|
||||||
|
import { validateRequest } from "../../../helpers/validation";
|
||||||
|
import * as reqValidator from "../../../validation/identities";
|
||||||
|
import {
|
||||||
|
getAuthDataOrgPermissions,
|
||||||
|
getOrgRolePermissions,
|
||||||
|
isAtLeastAsPrivilegedOrg
|
||||||
|
} from "../../services/RoleService";
|
||||||
|
import {
|
||||||
|
BadRequestError,
|
||||||
|
ForbiddenRequestError,
|
||||||
|
ResourceNotFoundError,
|
||||||
|
} from "../../../utils/errors";
|
||||||
|
import { ADMIN, CUSTOM, MEMBER, NO_ACCESS } from "../../../variables";
|
||||||
|
import {
|
||||||
|
OrgPermissionActions,
|
||||||
|
OrgPermissionSubjects
|
||||||
|
} from "../../services/RoleService";
|
||||||
|
import { EEAuditLogService } from "../../services";
|
||||||
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create identity
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const createIdentity = async (req: Request, res: Response) => {
|
||||||
|
/*
|
||||||
|
#swagger.summary = 'Create identity'
|
||||||
|
#swagger.description = 'Create identity'
|
||||||
|
|
||||||
|
#swagger.security = [{
|
||||||
|
"bearerAuth": []
|
||||||
|
}]
|
||||||
|
|
||||||
|
#swagger.requestBody = {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Name of entity to create",
|
||||||
|
"example": "development"
|
||||||
|
},
|
||||||
|
"organizationId": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "ID of organization where to create identity",
|
||||||
|
"example": "dev-environment"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Role to assume for organization membership",
|
||||||
|
"example": "no-access"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["name", "organizationId", "role"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#swagger.responses[200] = {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"identity": {
|
||||||
|
$ref: '#/definitions/Identity'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Details of the created identity"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const {
|
||||||
|
body: {
|
||||||
|
name,
|
||||||
|
organizationId,
|
||||||
|
role
|
||||||
|
}
|
||||||
|
} = await validateRequest(reqValidator.CreateIdentityV1, req);
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
OrgPermissionActions.Create,
|
||||||
|
OrgPermissionSubjects.Identity
|
||||||
|
);
|
||||||
|
|
||||||
|
const rolePermission = await getOrgRolePermissions(role, organizationId);
|
||||||
|
const hasRequiredPrivileges = isAtLeastAsPrivilegedOrg(permission, rolePermission);
|
||||||
|
|
||||||
|
if (!hasRequiredPrivileges) throw ForbiddenRequestError({
|
||||||
|
message: "Failed to create a more privileged identity"
|
||||||
|
});
|
||||||
|
|
||||||
|
const organization = await Organization.findById(organizationId);
|
||||||
|
if (!organization) throw BadRequestError({ message: `Organization with id ${organizationId} not found` });
|
||||||
|
|
||||||
|
const isCustomRole = ![ADMIN, MEMBER, NO_ACCESS].includes(role);
|
||||||
|
|
||||||
|
let customRole;
|
||||||
|
if (isCustomRole) {
|
||||||
|
customRole = await Role.findOne({
|
||||||
|
slug: role,
|
||||||
|
isOrgRole: true,
|
||||||
|
organization: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!customRole) throw BadRequestError({ message: "Role not found" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const identity = await new Identity({
|
||||||
|
name
|
||||||
|
}).save();
|
||||||
|
|
||||||
|
await new IdentityMembershipOrg({
|
||||||
|
identity: identity._id,
|
||||||
|
organization: new Types.ObjectId(organizationId),
|
||||||
|
role: isCustomRole ? CUSTOM : role,
|
||||||
|
customRole
|
||||||
|
}).save();
|
||||||
|
|
||||||
|
await EEAuditLogService.createAuditLog(
|
||||||
|
req.authData,
|
||||||
|
{
|
||||||
|
type: EventType.CREATE_IDENTITY,
|
||||||
|
metadata: {
|
||||||
|
identityId: identity._id.toString(),
|
||||||
|
name
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
identity
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update identity with id [identityId]
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const updateIdentity = async (req: Request, res: Response) => {
|
||||||
|
/*
|
||||||
|
#swagger.summary = 'Update identity'
|
||||||
|
#swagger.description = 'Update identity'
|
||||||
|
|
||||||
|
#swagger.security = [{
|
||||||
|
"bearerAuth": []
|
||||||
|
}]
|
||||||
|
|
||||||
|
#swagger.parameters['identityId'] = {
|
||||||
|
"description": "ID of identity to update",
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"in": "path"
|
||||||
|
}
|
||||||
|
|
||||||
|
#swagger.requestBody = {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Name of entity to update to",
|
||||||
|
"example": "development"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Role to update to for organization membership",
|
||||||
|
"example": "no-access"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#swagger.responses[200] = {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"identity": {
|
||||||
|
$ref: '#/definitions/Identity'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Details of the updated identity"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const {
|
||||||
|
params: { identityId },
|
||||||
|
body: {
|
||||||
|
name,
|
||||||
|
role
|
||||||
|
}
|
||||||
|
} = await validateRequest(reqValidator.UpdateIdentityV1, req);
|
||||||
|
|
||||||
|
const identityMembershipOrg = await IdentityMembershipOrg
|
||||||
|
.findOne({
|
||||||
|
identity: new Types.ObjectId(identityId)
|
||||||
|
})
|
||||||
|
.populate<{
|
||||||
|
identity: IIdentity,
|
||||||
|
customRole: IRole
|
||||||
|
}>("identity customRole");
|
||||||
|
|
||||||
|
if (!identityMembershipOrg) throw ResourceNotFoundError({
|
||||||
|
message: `Failed to find identity with id ${identityId}`
|
||||||
|
});
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: identityMembershipOrg.organization
|
||||||
|
});
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
OrgPermissionActions.Edit,
|
||||||
|
OrgPermissionSubjects.Identity
|
||||||
|
);
|
||||||
|
|
||||||
|
const identityRolePermission = await getOrgRolePermissions(
|
||||||
|
identityMembershipOrg?.customRole?.slug ?? identityMembershipOrg.role,
|
||||||
|
identityMembershipOrg.organization.toString()
|
||||||
|
);
|
||||||
|
const hasRequiredPrivileges = isAtLeastAsPrivilegedOrg(permission, identityRolePermission);
|
||||||
|
if (!hasRequiredPrivileges) throw ForbiddenRequestError({
|
||||||
|
message: "Failed to update more privileged identity"
|
||||||
|
});
|
||||||
|
|
||||||
|
if (role) {
|
||||||
|
const rolePermission = await getOrgRolePermissions(role, identityMembershipOrg.organization.toString());
|
||||||
|
const hasRequiredPrivileges = isAtLeastAsPrivilegedOrg(permission, rolePermission);
|
||||||
|
|
||||||
|
if (!hasRequiredPrivileges) throw ForbiddenRequestError({
|
||||||
|
message: "Failed to update identity to a more privileged role"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let customRole;
|
||||||
|
if (role) {
|
||||||
|
const isCustomRole = ![ADMIN, MEMBER, NO_ACCESS].includes(role);
|
||||||
|
if (isCustomRole) {
|
||||||
|
customRole = await Role.findOne({
|
||||||
|
slug: role,
|
||||||
|
isOrgRole: true,
|
||||||
|
organization: identityMembershipOrg.organization
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!customRole) throw BadRequestError({ message: "Role not found" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const identity = await Identity.findByIdAndUpdate(
|
||||||
|
identityId,
|
||||||
|
{
|
||||||
|
name,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!identity) throw BadRequestError({
|
||||||
|
message: `Failed to update identity with id ${identityId}`
|
||||||
|
});
|
||||||
|
|
||||||
|
await IdentityMembershipOrg.findOneAndUpdate(
|
||||||
|
{
|
||||||
|
identity: identity._id
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: customRole ? CUSTOM : role,
|
||||||
|
...(customRole ? {
|
||||||
|
customRole
|
||||||
|
} : {}),
|
||||||
|
...(role && !customRole ? { // non-custom role
|
||||||
|
$unset: {
|
||||||
|
customRole: 1
|
||||||
|
}
|
||||||
|
} : {})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
await EEAuditLogService.createAuditLog(
|
||||||
|
req.authData,
|
||||||
|
{
|
||||||
|
type: EventType.UPDATE_IDENTITY,
|
||||||
|
metadata: {
|
||||||
|
identityId: identity._id.toString(),
|
||||||
|
name: identity.name,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
organizationId: identityMembershipOrg.organization
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
identity
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete identity with id [identityId]
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const deleteIdentity = async (req: Request, res: Response) => {
|
||||||
|
/*
|
||||||
|
#swagger.summary = 'Delete identity'
|
||||||
|
#swagger.description = 'Delete identity'
|
||||||
|
|
||||||
|
#swagger.security = [{
|
||||||
|
"bearerAuth": []
|
||||||
|
}]
|
||||||
|
|
||||||
|
#swagger.parameters['identityId'] = {
|
||||||
|
"description": "ID of identity",
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"in": "path"
|
||||||
|
}
|
||||||
|
|
||||||
|
#swagger.responses[200] = {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"identity": {
|
||||||
|
$ref: '#/definitions/Identity'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Details of the deleted identity"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const {
|
||||||
|
params: { identityId }
|
||||||
|
} = await validateRequest(reqValidator.DeleteIdentityV1, req);
|
||||||
|
|
||||||
|
const identityMembershipOrg = await IdentityMembershipOrg
|
||||||
|
.findOne({
|
||||||
|
identity: new Types.ObjectId(identityId)
|
||||||
|
})
|
||||||
|
.populate<{
|
||||||
|
identity: IIdentity,
|
||||||
|
customRole: IRole
|
||||||
|
}>("identity customRole");
|
||||||
|
|
||||||
|
if (!identityMembershipOrg) throw ResourceNotFoundError({
|
||||||
|
message: `Failed to find identity with id ${identityId}`
|
||||||
|
});
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: identityMembershipOrg.organization
|
||||||
|
});
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
OrgPermissionActions.Delete,
|
||||||
|
OrgPermissionSubjects.Identity
|
||||||
|
);
|
||||||
|
|
||||||
|
const identityRolePermission = await getOrgRolePermissions(
|
||||||
|
identityMembershipOrg?.customRole?.slug ?? identityMembershipOrg.role,
|
||||||
|
identityMembershipOrg.organization.toString()
|
||||||
|
);
|
||||||
|
const hasRequiredPrivileges = isAtLeastAsPrivilegedOrg(permission, identityRolePermission);
|
||||||
|
if (!hasRequiredPrivileges) throw ForbiddenRequestError({
|
||||||
|
message: "Failed to delete more privileged identity"
|
||||||
|
});
|
||||||
|
|
||||||
|
const identity = await Identity.findByIdAndDelete(identityMembershipOrg.identity);
|
||||||
|
if (!identity) throw ResourceNotFoundError({
|
||||||
|
message: `Identity with id ${identityId} not found`
|
||||||
|
});
|
||||||
|
|
||||||
|
await IdentityMembershipOrg.findByIdAndDelete(identityMembershipOrg._id);
|
||||||
|
|
||||||
|
await IdentityMembership.deleteMany({
|
||||||
|
identity: identityMembershipOrg.identity
|
||||||
|
});
|
||||||
|
|
||||||
|
await IdentityUniversalAuth.deleteMany({
|
||||||
|
identity: identityMembershipOrg.identity
|
||||||
|
});
|
||||||
|
|
||||||
|
await IdentityUniversalAuthClientSecret.deleteMany({
|
||||||
|
identity: identityMembershipOrg.identity
|
||||||
|
});
|
||||||
|
|
||||||
|
await IdentityAccessToken.deleteMany({
|
||||||
|
identity: identityMembershipOrg.identity
|
||||||
|
});
|
||||||
|
|
||||||
|
await EEAuditLogService.createAuditLog(
|
||||||
|
req.authData,
|
||||||
|
{
|
||||||
|
type: EventType.DELETE_IDENTITY,
|
||||||
|
metadata: {
|
||||||
|
identityId: identity._id.toString()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
organizationId: identityMembershipOrg.organization
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
identity
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,27 +1,31 @@
|
|||||||
|
import * as identitiesController from "./identitiesController";
|
||||||
import * as secretController from "./secretController";
|
import * as secretController from "./secretController";
|
||||||
import * as secretSnapshotController from "./secretSnapshotController";
|
import * as secretSnapshotController from "./secretSnapshotController";
|
||||||
import * as organizationsController from "./organizationsController";
|
import * as organizationsController from "./organizationsController";
|
||||||
import * as ssoController from "./ssoController";
|
import * as ssoController from "./ssoController";
|
||||||
import * as usersController from "./usersController";
|
import * as usersController from "./usersController";
|
||||||
import * as workspaceController from "./workspaceController";
|
import * as workspaceController from "./workspaceController";
|
||||||
import * as actionController from "./actionController";
|
|
||||||
import * as membershipController from "./membershipController";
|
import * as membershipController from "./membershipController";
|
||||||
import * as cloudProductsController from "./cloudProductsController";
|
import * as cloudProductsController from "./cloudProductsController";
|
||||||
import * as roleController from "./roleController";
|
import * as roleController from "./roleController";
|
||||||
import * as secretApprovalPolicyController from "./secretApprovalPolicyController";
|
import * as secretApprovalPolicyController from "./secretApprovalPolicyController";
|
||||||
import * as secretApprovalRequestController from "./secretApprovalRequestsController";
|
import * as secretApprovalRequestController from "./secretApprovalRequestsController";
|
||||||
|
import * as secretRotationProviderController from "./secretRotationProviderController";
|
||||||
|
import * as secretRotationController from "./secretRotationController";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
identitiesController,
|
||||||
secretController,
|
secretController,
|
||||||
secretSnapshotController,
|
secretSnapshotController,
|
||||||
organizationsController,
|
organizationsController,
|
||||||
ssoController,
|
ssoController,
|
||||||
usersController,
|
usersController,
|
||||||
workspaceController,
|
workspaceController,
|
||||||
actionController,
|
|
||||||
membershipController,
|
membershipController,
|
||||||
cloudProductsController,
|
cloudProductsController,
|
||||||
roleController,
|
roleController,
|
||||||
secretApprovalPolicyController,
|
secretApprovalPolicyController,
|
||||||
secretApprovalRequestController
|
secretApprovalRequestController,
|
||||||
|
secretRotationProviderController,
|
||||||
|
secretRotationController
|
||||||
};
|
};
|
@ -8,7 +8,7 @@ import * as reqValidator from "../../../validation/organization";
|
|||||||
import {
|
import {
|
||||||
OrgPermissionActions,
|
OrgPermissionActions,
|
||||||
OrgPermissionSubjects,
|
OrgPermissionSubjects,
|
||||||
getUserOrgPermissions
|
getAuthDataOrgPermissions,
|
||||||
} from "../../services/RoleService";
|
} from "../../services/RoleService";
|
||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
import { Organization } from "../../../models";
|
import { Organization } from "../../../models";
|
||||||
@ -20,7 +20,10 @@ export const getOrganizationPlansTable = async (req: Request, res: Response) =>
|
|||||||
params: { organizationId }
|
params: { organizationId }
|
||||||
} = await validateRequest(reqValidator.GetOrgPlansTablev1, req);
|
} = await validateRequest(reqValidator.GetOrgPlansTablev1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Read,
|
OrgPermissionActions.Read,
|
||||||
OrgPermissionSubjects.Billing
|
OrgPermissionSubjects.Billing
|
||||||
@ -42,7 +45,10 @@ export const getOrganizationPlan = async (req: Request, res: Response) => {
|
|||||||
params: { organizationId }
|
params: { organizationId }
|
||||||
} = await validateRequest(reqValidator.GetOrgPlanv1, req);
|
} = await validateRequest(reqValidator.GetOrgPlanv1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Read,
|
OrgPermissionActions.Read,
|
||||||
OrgPermissionSubjects.Billing
|
OrgPermissionSubjects.Billing
|
||||||
@ -70,7 +76,10 @@ export const startOrganizationTrial = async (req: Request, res: Response) => {
|
|||||||
body: { success_url }
|
body: { success_url }
|
||||||
} = await validateRequest(reqValidator.StartOrgTrailv1, req);
|
} = await validateRequest(reqValidator.StartOrgTrailv1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Create,
|
OrgPermissionActions.Create,
|
||||||
OrgPermissionSubjects.Billing
|
OrgPermissionSubjects.Billing
|
||||||
@ -116,7 +125,10 @@ export const getOrganizationPlanBillingInfo = async (req: Request, res: Response
|
|||||||
params: { organizationId }
|
params: { organizationId }
|
||||||
} = await validateRequest(reqValidator.GetOrgPlanBillingInfov1, req);
|
} = await validateRequest(reqValidator.GetOrgPlanBillingInfov1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Read,
|
OrgPermissionActions.Read,
|
||||||
OrgPermissionSubjects.Billing
|
OrgPermissionSubjects.Billing
|
||||||
@ -149,7 +161,10 @@ export const getOrganizationPlanTable = async (req: Request, res: Response) => {
|
|||||||
params: { organizationId }
|
params: { organizationId }
|
||||||
} = await validateRequest(reqValidator.GetOrgPlanTablev1, req);
|
} = await validateRequest(reqValidator.GetOrgPlanTablev1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Read,
|
OrgPermissionActions.Read,
|
||||||
OrgPermissionSubjects.Billing
|
OrgPermissionSubjects.Billing
|
||||||
@ -176,7 +191,10 @@ export const getOrganizationBillingDetails = async (req: Request, res: Response)
|
|||||||
params: { organizationId }
|
params: { organizationId }
|
||||||
} = await validateRequest(reqValidator.GetOrgBillingDetailsv1, req);
|
} = await validateRequest(reqValidator.GetOrgBillingDetailsv1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Read,
|
OrgPermissionActions.Read,
|
||||||
OrgPermissionSubjects.Billing
|
OrgPermissionSubjects.Billing
|
||||||
@ -204,7 +222,10 @@ export const updateOrganizationBillingDetails = async (req: Request, res: Respon
|
|||||||
body: { name, email }
|
body: { name, email }
|
||||||
} = await validateRequest(reqValidator.UpdateOrgBillingDetailsv1, req);
|
} = await validateRequest(reqValidator.UpdateOrgBillingDetailsv1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Edit,
|
OrgPermissionActions.Edit,
|
||||||
OrgPermissionSubjects.Billing
|
OrgPermissionSubjects.Billing
|
||||||
@ -238,7 +259,10 @@ export const getOrganizationPmtMethods = async (req: Request, res: Response) =>
|
|||||||
params: { organizationId }
|
params: { organizationId }
|
||||||
} = await validateRequest(reqValidator.GetOrgPmtMethodsv1, req);
|
} = await validateRequest(reqValidator.GetOrgPmtMethodsv1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Read,
|
OrgPermissionActions.Read,
|
||||||
OrgPermissionSubjects.Billing
|
OrgPermissionSubjects.Billing
|
||||||
@ -271,7 +295,10 @@ export const addOrganizationPmtMethod = async (req: Request, res: Response) => {
|
|||||||
body: { success_url, cancel_url }
|
body: { success_url, cancel_url }
|
||||||
} = await validateRequest(reqValidator.CreateOrgPmtMethodv1, req);
|
} = await validateRequest(reqValidator.CreateOrgPmtMethodv1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Create,
|
OrgPermissionActions.Create,
|
||||||
OrgPermissionSubjects.Billing
|
OrgPermissionSubjects.Billing
|
||||||
@ -312,7 +339,10 @@ export const deleteOrganizationPmtMethod = async (req: Request, res: Response) =
|
|||||||
params: { organizationId, pmtMethodId }
|
params: { organizationId, pmtMethodId }
|
||||||
} = await validateRequest(reqValidator.DelOrgPmtMethodv1, req);
|
} = await validateRequest(reqValidator.DelOrgPmtMethodv1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Delete,
|
OrgPermissionActions.Delete,
|
||||||
OrgPermissionSubjects.Billing
|
OrgPermissionSubjects.Billing
|
||||||
@ -342,7 +372,10 @@ export const getOrganizationTaxIds = async (req: Request, res: Response) => {
|
|||||||
params: { organizationId }
|
params: { organizationId }
|
||||||
} = await validateRequest(reqValidator.GetOrgTaxIdsv1, req);
|
} = await validateRequest(reqValidator.GetOrgTaxIdsv1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Read,
|
OrgPermissionActions.Read,
|
||||||
OrgPermissionSubjects.Billing
|
OrgPermissionSubjects.Billing
|
||||||
@ -375,7 +408,10 @@ export const addOrganizationTaxId = async (req: Request, res: Response) => {
|
|||||||
body: { type, value }
|
body: { type, value }
|
||||||
} = await validateRequest(reqValidator.CreateOrgTaxId, req);
|
} = await validateRequest(reqValidator.CreateOrgTaxId, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Create,
|
OrgPermissionActions.Create,
|
||||||
OrgPermissionSubjects.Billing
|
OrgPermissionSubjects.Billing
|
||||||
@ -412,7 +448,10 @@ export const deleteOrganizationTaxId = async (req: Request, res: Response) => {
|
|||||||
params: { organizationId, taxId }
|
params: { organizationId, taxId }
|
||||||
} = await validateRequest(reqValidator.DelOrgTaxIdv1, req);
|
} = await validateRequest(reqValidator.DelOrgTaxIdv1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Delete,
|
OrgPermissionActions.Delete,
|
||||||
OrgPermissionSubjects.Billing
|
OrgPermissionSubjects.Billing
|
||||||
@ -445,7 +484,10 @@ export const getOrganizationInvoices = async (req: Request, res: Response) => {
|
|||||||
params: { organizationId }
|
params: { organizationId }
|
||||||
} = await validateRequest(reqValidator.GetOrgInvoicesv1, req);
|
} = await validateRequest(reqValidator.GetOrgInvoicesv1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Read,
|
OrgPermissionActions.Read,
|
||||||
OrgPermissionSubjects.Billing
|
OrgPermissionSubjects.Billing
|
||||||
@ -480,7 +522,10 @@ export const getOrganizationLicenses = async (req: Request, res: Response) => {
|
|||||||
params: { organizationId }
|
params: { organizationId }
|
||||||
} = await validateRequest(reqValidator.GetOrgLicencesv1, req);
|
} = await validateRequest(reqValidator.GetOrgLicencesv1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Read,
|
OrgPermissionActions.Read,
|
||||||
OrgPermissionSubjects.Billing
|
OrgPermissionSubjects.Billing
|
@ -1,4 +1,6 @@
|
|||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
|
import { Types } from "mongoose";
|
||||||
|
import { Membership, User } from "../../../models";
|
||||||
import {
|
import {
|
||||||
CreateRoleSchema,
|
CreateRoleSchema,
|
||||||
DeleteRoleSchema,
|
DeleteRoleSchema,
|
||||||
@ -11,16 +13,19 @@ import {
|
|||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
ProjectPermissionSub,
|
ProjectPermissionSub,
|
||||||
adminProjectPermissions,
|
adminProjectPermissions,
|
||||||
getUserProjectPermissions,
|
getAuthDataProjectPermissions,
|
||||||
memberProjectPermissions,
|
memberProjectPermissions,
|
||||||
|
noAccessProjectPermissions,
|
||||||
viewerProjectPermission
|
viewerProjectPermission
|
||||||
} from "../../services/ProjectRoleService";
|
} from "../../services/ProjectRoleService";
|
||||||
import {
|
import {
|
||||||
OrgPermissionActions,
|
OrgPermissionActions,
|
||||||
OrgPermissionSubjects,
|
OrgPermissionSubjects,
|
||||||
adminPermissions,
|
adminPermissions,
|
||||||
|
getAuthDataOrgPermissions,
|
||||||
getUserOrgPermissions,
|
getUserOrgPermissions,
|
||||||
memberPermissions
|
memberPermissions,
|
||||||
|
noAccessPermissions
|
||||||
} from "../../services/RoleService";
|
} from "../../services/RoleService";
|
||||||
import { BadRequestError } from "../../../utils/errors";
|
import { BadRequestError } from "../../../utils/errors";
|
||||||
import { Role } from "../../models";
|
import { Role } from "../../models";
|
||||||
@ -34,12 +39,19 @@ export const createRole = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
const isOrgRole = !workspaceId; // if workspaceid is provided then its a workspace rule
|
const isOrgRole = !workspaceId; // if workspaceid is provided then its a workspace rule
|
||||||
if (isOrgRole) {
|
if (isOrgRole) {
|
||||||
const { permission } = await getUserOrgPermissions(req.user.id, orgId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(orgId)
|
||||||
|
});
|
||||||
|
|
||||||
if (permission.cannot(OrgPermissionActions.Create, OrgPermissionSubjects.Role)) {
|
if (permission.cannot(OrgPermissionActions.Create, OrgPermissionSubjects.Role)) {
|
||||||
throw BadRequestError({ message: "user doesn't have the permission." });
|
throw BadRequestError({ message: "user doesn't have the permission." });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const { permission } = await getUserProjectPermissions(req.user.id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
if (permission.cannot(ProjectPermissionActions.Create, ProjectPermissionSub.Role)) {
|
if (permission.cannot(ProjectPermissionActions.Create, ProjectPermissionSub.Role)) {
|
||||||
throw BadRequestError({ message: "User doesn't have the permission." });
|
throw BadRequestError({ message: "User doesn't have the permission." });
|
||||||
}
|
}
|
||||||
@ -77,12 +89,19 @@ export const updateRole = async (req: Request, res: Response) => {
|
|||||||
const isOrgRole = !workspaceId; // if workspaceid is provided then its a workspace rule
|
const isOrgRole = !workspaceId; // if workspaceid is provided then its a workspace rule
|
||||||
|
|
||||||
if (isOrgRole) {
|
if (isOrgRole) {
|
||||||
const { permission } = await getUserOrgPermissions(req.user.id, orgId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(orgId)
|
||||||
|
});
|
||||||
if (permission.cannot(OrgPermissionActions.Edit, OrgPermissionSubjects.Role)) {
|
if (permission.cannot(OrgPermissionActions.Edit, OrgPermissionSubjects.Role)) {
|
||||||
throw BadRequestError({ message: "User doesn't have the org permission." });
|
throw BadRequestError({ message: "User doesn't have the org permission." });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const { permission } = await getUserProjectPermissions(req.user.id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
if (permission.cannot(ProjectPermissionActions.Edit, ProjectPermissionSub.Role)) {
|
if (permission.cannot(ProjectPermissionActions.Edit, ProjectPermissionSub.Role)) {
|
||||||
throw BadRequestError({ message: "User doesn't have the workspace permission." });
|
throw BadRequestError({ message: "User doesn't have the workspace permission." });
|
||||||
}
|
}
|
||||||
@ -129,12 +148,19 @@ export const deleteRole = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
const isOrgRole = !role.workspace;
|
const isOrgRole = !role.workspace;
|
||||||
if (isOrgRole) {
|
if (isOrgRole) {
|
||||||
const { permission } = await getUserOrgPermissions(req.user.id, role.organization.toString());
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: role.organization
|
||||||
|
});
|
||||||
if (permission.cannot(OrgPermissionActions.Delete, OrgPermissionSubjects.Role)) {
|
if (permission.cannot(OrgPermissionActions.Delete, OrgPermissionSubjects.Role)) {
|
||||||
throw BadRequestError({ message: "User doesn't have the org permission." });
|
throw BadRequestError({ message: "User doesn't have the org permission." });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const { permission } = await getUserProjectPermissions(req.user.id, role.workspace.toString());
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: role.workspace
|
||||||
|
});
|
||||||
|
|
||||||
if (permission.cannot(ProjectPermissionActions.Delete, ProjectPermissionSub.Role)) {
|
if (permission.cannot(ProjectPermissionActions.Delete, ProjectPermissionSub.Role)) {
|
||||||
throw BadRequestError({ message: "User doesn't have the workspace permission." });
|
throw BadRequestError({ message: "User doesn't have the workspace permission." });
|
||||||
}
|
}
|
||||||
@ -157,12 +183,19 @@ export const getRoles = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
const isOrgRole = !workspaceId;
|
const isOrgRole = !workspaceId;
|
||||||
if (isOrgRole) {
|
if (isOrgRole) {
|
||||||
const { permission } = await getUserOrgPermissions(req.user.id, orgId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(orgId)
|
||||||
|
});
|
||||||
if (permission.cannot(OrgPermissionActions.Read, OrgPermissionSubjects.Role)) {
|
if (permission.cannot(OrgPermissionActions.Read, OrgPermissionSubjects.Role)) {
|
||||||
throw BadRequestError({ message: "User doesn't have the org permission." });
|
throw BadRequestError({ message: "User doesn't have the org permission." });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const { permission } = await getUserProjectPermissions(req.user.id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
if (permission.cannot(ProjectPermissionActions.Read, ProjectPermissionSub.Role)) {
|
if (permission.cannot(ProjectPermissionActions.Read, ProjectPermissionSub.Role)) {
|
||||||
throw BadRequestError({ message: "User doesn't have the workspace permission." });
|
throw BadRequestError({ message: "User doesn't have the workspace permission." });
|
||||||
}
|
}
|
||||||
@ -178,6 +211,13 @@ export const getRoles = async (req: Request, res: Response) => {
|
|||||||
description: "Complete administration access over the organization",
|
description: "Complete administration access over the organization",
|
||||||
permissions: isOrgRole ? adminPermissions.rules : adminProjectPermissions.rules
|
permissions: isOrgRole ? adminPermissions.rules : adminProjectPermissions.rules
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
_id: "no-access",
|
||||||
|
name: "No Access",
|
||||||
|
slug: "no-access",
|
||||||
|
description: "No access to any resources in the organization",
|
||||||
|
permissions: isOrgRole ? noAccessPermissions.rules : noAccessProjectPermissions.rules
|
||||||
|
},
|
||||||
{
|
{
|
||||||
_id: "member",
|
_id: "member",
|
||||||
name: isOrgRole ? "Member" : "Developer",
|
name: isOrgRole ? "Member" : "Developer",
|
||||||
@ -213,11 +253,12 @@ export const getUserPermissions = async (req: Request, res: Response) => {
|
|||||||
params: { orgId }
|
params: { orgId }
|
||||||
} = await validateRequest(GetUserPermission, req);
|
} = await validateRequest(GetUserPermission, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, orgId);
|
const { permission, membership } = await getUserOrgPermissions(req.user._id, orgId);
|
||||||
|
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
data: {
|
data: {
|
||||||
permissions: packRules(permission.rules)
|
permissions: packRules(permission.rules),
|
||||||
|
membership
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -226,11 +267,24 @@ export const getUserWorkspacePermissions = async (req: Request, res: Response) =
|
|||||||
const {
|
const {
|
||||||
params: { workspaceId }
|
params: { workspaceId }
|
||||||
} = await validateRequest(GetUserProjectPermission, req);
|
} = await validateRequest(GetUserProjectPermission, req);
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
let membership;
|
||||||
|
if (req.authData.authPayload instanceof User) {
|
||||||
|
membership = await Membership.findOne({
|
||||||
|
user: req.authData.authPayload._id,
|
||||||
|
workspace: new Types.ObjectId(workspaceId)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
data: {
|
data: {
|
||||||
permissions: packRules(permission.rules)
|
permissions: packRules(permission.rules),
|
||||||
|
membership
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
@ -1,10 +1,11 @@
|
|||||||
|
import { Types } from "mongoose";
|
||||||
import { ForbiddenError, subject } from "@casl/ability";
|
import { ForbiddenError, subject } from "@casl/ability";
|
||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import {
|
import {
|
||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
ProjectPermissionSub,
|
ProjectPermissionSub,
|
||||||
getUserProjectPermissions
|
getAuthDataProjectPermissions
|
||||||
} from "../../services/ProjectRoleService";
|
} from "../../services/ProjectRoleService";
|
||||||
import { validateRequest } from "../../../helpers/validation";
|
import { validateRequest } from "../../../helpers/validation";
|
||||||
import { SecretApprovalPolicy } from "../../models/secretApprovalPolicy";
|
import { SecretApprovalPolicy } from "../../models/secretApprovalPolicy";
|
||||||
@ -19,7 +20,11 @@ export const createSecretApprovalPolicy = async (req: Request, res: Response) =>
|
|||||||
body: { approvals, secretPath, approvers, environment, workspaceId, name }
|
body: { approvals, secretPath, approvers, environment, workspaceId, name }
|
||||||
} = await validateRequest(reqValidator.CreateSecretApprovalRule, req);
|
} = await validateRequest(reqValidator.CreateSecretApprovalRule, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Create,
|
ProjectPermissionActions.Create,
|
||||||
ProjectPermissionSub.SecretApproval
|
ProjectPermissionSub.SecretApproval
|
||||||
@ -49,10 +54,11 @@ export const updateSecretApprovalPolicy = async (req: Request, res: Response) =>
|
|||||||
const secretApproval = await SecretApprovalPolicy.findById(id);
|
const secretApproval = await SecretApprovalPolicy.findById(id);
|
||||||
if (!secretApproval) throw ERR_SECRET_APPROVAL_NOT_FOUND;
|
if (!secretApproval) throw ERR_SECRET_APPROVAL_NOT_FOUND;
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
req.user._id,
|
authData: req.authData,
|
||||||
secretApproval.workspace.toString()
|
workspaceId: secretApproval.workspace
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Edit,
|
ProjectPermissionActions.Edit,
|
||||||
ProjectPermissionSub.SecretApproval
|
ProjectPermissionSub.SecretApproval
|
||||||
@ -78,10 +84,11 @@ export const deleteSecretApprovalPolicy = async (req: Request, res: Response) =>
|
|||||||
const secretApproval = await SecretApprovalPolicy.findById(id);
|
const secretApproval = await SecretApprovalPolicy.findById(id);
|
||||||
if (!secretApproval) throw ERR_SECRET_APPROVAL_NOT_FOUND;
|
if (!secretApproval) throw ERR_SECRET_APPROVAL_NOT_FOUND;
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
req.user._id,
|
authData: req.authData,
|
||||||
secretApproval.workspace.toString()
|
workspaceId: secretApproval.workspace
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Delete,
|
ProjectPermissionActions.Delete,
|
||||||
ProjectPermissionSub.SecretApproval
|
ProjectPermissionSub.SecretApproval
|
||||||
@ -99,7 +106,11 @@ export const getSecretApprovalPolicy = async (req: Request, res: Response) => {
|
|||||||
query: { workspaceId }
|
query: { workspaceId }
|
||||||
} = await validateRequest(reqValidator.GetSecretApprovalRuleList, req);
|
} = await validateRequest(reqValidator.GetSecretApprovalRuleList, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.SecretApproval
|
ProjectPermissionSub.SecretApproval
|
||||||
@ -117,7 +128,11 @@ export const getSecretApprovalPolicyOfBoard = async (req: Request, res: Response
|
|||||||
query: { workspaceId, environment, secretPath }
|
query: { workspaceId, environment, secretPath }
|
||||||
} = await validateRequest(reqValidator.GetSecretApprovalPolicyOfABoard, req);
|
} = await validateRequest(reqValidator.GetSecretApprovalPolicyOfABoard, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
subject(ProjectPermissionSub.Secrets, { secretPath, environment })
|
subject(ProjectPermissionSub.Secrets, { secretPath, environment })
|
@ -1,7 +1,6 @@
|
|||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
import { getUserProjectPermissions } from "../../services/ProjectRoleService";
|
|
||||||
import { validateRequest } from "../../../helpers/validation";
|
import { validateRequest } from "../../../helpers/validation";
|
||||||
import { Folder } from "../../../models";
|
import { Folder, Membership, User } from "../../../models";
|
||||||
import { ApprovalStatus, SecretApprovalRequest } from "../../models/secretApprovalRequest";
|
import { ApprovalStatus, SecretApprovalRequest } from "../../models/secretApprovalRequest";
|
||||||
import * as reqValidator from "../../validation/secretApprovalRequest";
|
import * as reqValidator from "../../validation/secretApprovalRequest";
|
||||||
import { getFolderWithPathFromId } from "../../../services/FolderService";
|
import { getFolderWithPathFromId } from "../../../services/FolderService";
|
||||||
@ -17,7 +16,15 @@ export const getSecretApprovalRequestCount = async (req: Request, res: Response)
|
|||||||
query: { workspaceId }
|
query: { workspaceId }
|
||||||
} = await validateRequest(reqValidator.getSecretApprovalRequestCount, req);
|
} = await validateRequest(reqValidator.getSecretApprovalRequestCount, req);
|
||||||
|
|
||||||
const { membership } = await getUserProjectPermissions(req.user._id, workspaceId);
|
if (!(req.authData.authPayload instanceof User)) return;
|
||||||
|
|
||||||
|
const membership = await Membership.findOne({
|
||||||
|
user: req.authData.authPayload._id,
|
||||||
|
workspace: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!membership) throw UnauthorizedRequestError();
|
||||||
|
|
||||||
const approvalRequestCount = await SecretApprovalRequest.aggregate([
|
const approvalRequestCount = await SecretApprovalRequest.aggregate([
|
||||||
{
|
{
|
||||||
$match: {
|
$match: {
|
||||||
@ -65,7 +72,14 @@ export const getSecretApprovalRequests = async (req: Request, res: Response) =>
|
|||||||
query: { status, committer, workspaceId, environment, limit, offset }
|
query: { status, committer, workspaceId, environment, limit, offset }
|
||||||
} = await validateRequest(reqValidator.getSecretApprovalRequests, req);
|
} = await validateRequest(reqValidator.getSecretApprovalRequests, req);
|
||||||
|
|
||||||
const { membership } = await getUserProjectPermissions(req.user._id, workspaceId);
|
if (!(req.authData.authPayload instanceof User)) return;
|
||||||
|
|
||||||
|
const membership = await Membership.findOne({
|
||||||
|
user: req.authData.authPayload._id,
|
||||||
|
workspace: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!membership) throw UnauthorizedRequestError();
|
||||||
|
|
||||||
const query = {
|
const query = {
|
||||||
workspace: new Types.ObjectId(workspaceId),
|
workspace: new Types.ObjectId(workspaceId),
|
||||||
@ -148,14 +162,19 @@ export const getSecretApprovalRequestDetails = async (req: Request, res: Respons
|
|||||||
if (!secretApprovalRequest)
|
if (!secretApprovalRequest)
|
||||||
throw BadRequestError({ message: "Secret approval request not found" });
|
throw BadRequestError({ message: "Secret approval request not found" });
|
||||||
|
|
||||||
const { membership } = await getUserProjectPermissions(
|
if (!(req.authData.authPayload instanceof User)) return;
|
||||||
req.user._id,
|
|
||||||
secretApprovalRequest.workspace.toString()
|
const membership = await Membership.findOne({
|
||||||
);
|
user: req.authData.authPayload._id,
|
||||||
|
workspace: secretApprovalRequest.workspace
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!membership) throw UnauthorizedRequestError();
|
||||||
|
|
||||||
// allow to fetch only if its admin or is the committer or approver
|
// allow to fetch only if its admin or is the committer or approver
|
||||||
if (
|
if (
|
||||||
membership.role !== "admin" &&
|
membership.role !== "admin" &&
|
||||||
secretApprovalRequest.committer !== membership.id &&
|
!secretApprovalRequest.committer.equals(membership.id) &&
|
||||||
!secretApprovalRequest.policy.approvers.find(
|
!secretApprovalRequest.policy.approvers.find(
|
||||||
(approverId) => approverId.toString() === membership._id.toString()
|
(approverId) => approverId.toString() === membership._id.toString()
|
||||||
)
|
)
|
||||||
@ -190,10 +209,15 @@ export const updateSecretApprovalReviewStatus = async (req: Request, res: Respon
|
|||||||
if (!secretApprovalRequest)
|
if (!secretApprovalRequest)
|
||||||
throw BadRequestError({ message: "Secret approval request not found" });
|
throw BadRequestError({ message: "Secret approval request not found" });
|
||||||
|
|
||||||
const { membership } = await getUserProjectPermissions(
|
if (!(req.authData.authPayload instanceof User)) return;
|
||||||
req.user._id,
|
|
||||||
secretApprovalRequest.workspace.toString()
|
const membership = await Membership.findOne({
|
||||||
);
|
user: req.authData.authPayload._id,
|
||||||
|
workspace: secretApprovalRequest.workspace
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!membership) throw UnauthorizedRequestError();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
membership.role !== "admin" &&
|
membership.role !== "admin" &&
|
||||||
secretApprovalRequest.committer !== membership.id &&
|
secretApprovalRequest.committer !== membership.id &&
|
||||||
@ -227,10 +251,15 @@ export const mergeSecretApprovalRequest = async (req: Request, res: Response) =>
|
|||||||
if (!secretApprovalRequest)
|
if (!secretApprovalRequest)
|
||||||
throw BadRequestError({ message: "Secret approval request not found" });
|
throw BadRequestError({ message: "Secret approval request not found" });
|
||||||
|
|
||||||
const { membership } = await getUserProjectPermissions(
|
if (!(req.authData.authPayload instanceof User)) return;
|
||||||
req.user._id,
|
|
||||||
secretApprovalRequest.workspace.toString()
|
const membership = await Membership.findOne({
|
||||||
);
|
user: req.authData.authPayload._id,
|
||||||
|
workspace: secretApprovalRequest.workspace
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!membership) throw UnauthorizedRequestError();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
membership.role !== "admin" &&
|
membership.role !== "admin" &&
|
||||||
secretApprovalRequest.committer !== membership.id &&
|
secretApprovalRequest.committer !== membership.id &&
|
||||||
@ -272,10 +301,14 @@ export const updateSecretApprovalRequestStatus = async (req: Request, res: Respo
|
|||||||
if (!secretApprovalRequest)
|
if (!secretApprovalRequest)
|
||||||
throw BadRequestError({ message: "Secret approval request not found" });
|
throw BadRequestError({ message: "Secret approval request not found" });
|
||||||
|
|
||||||
const { membership } = await getUserProjectPermissions(
|
if (!(req.authData.authPayload instanceof User)) return;
|
||||||
req.user._id,
|
|
||||||
secretApprovalRequest.workspace.toString()
|
const membership = await Membership.findOne({
|
||||||
);
|
user: req.authData.authPayload._id,
|
||||||
|
workspace: secretApprovalRequest.workspace
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!membership) throw UnauthorizedRequestError();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
membership.role !== "admin" &&
|
membership.role !== "admin" &&
|
@ -5,7 +5,7 @@ import { Folder, Secret } from "../../../models";
|
|||||||
import {
|
import {
|
||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
ProjectPermissionSub,
|
ProjectPermissionSub,
|
||||||
getUserProjectPermissions
|
getAuthDataProjectPermissions
|
||||||
} from "../../services/ProjectRoleService";
|
} from "../../services/ProjectRoleService";
|
||||||
import { BadRequestError } from "../../../utils/errors";
|
import { BadRequestError } from "../../../utils/errors";
|
||||||
import * as reqValidator from "../../../validation";
|
import * as reqValidator from "../../../validation";
|
||||||
@ -74,7 +74,11 @@ export const getSecretVersions = async (req: Request, res: Response) => {
|
|||||||
throw BadRequestError({ message: "Failed to find secret" });
|
throw BadRequestError({ message: "Failed to find secret" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, secret.workspace.toString());
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: secret.workspace
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.SecretRollback
|
ProjectPermissionSub.SecretRollback
|
||||||
@ -157,10 +161,12 @@ export const rollbackSecretVersion = async (req: Request, res: Response) => {
|
|||||||
if (!toBeUpdatedSec) {
|
if (!toBeUpdatedSec) {
|
||||||
throw BadRequestError({ message: "Failed to find secret" });
|
throw BadRequestError({ message: "Failed to find secret" });
|
||||||
}
|
}
|
||||||
const { permission } = await getUserProjectPermissions(
|
|
||||||
req.user._id,
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
toBeUpdatedSec.workspace.toString()
|
authData: req.authData,
|
||||||
);
|
workspaceId: toBeUpdatedSec.workspace
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Create,
|
ProjectPermissionActions.Create,
|
||||||
ProjectPermissionSub.SecretRollback
|
ProjectPermissionSub.SecretRollback
|
110
backend-mongo/src/ee/controllers/v1/secretRotationController.ts
Normal file
110
backend-mongo/src/ee/controllers/v1/secretRotationController.ts
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
import { Request, Response } from "express";
|
||||||
|
import { Types } from "mongoose";
|
||||||
|
import { validateRequest } from "../../../helpers/validation";
|
||||||
|
import * as reqValidator from "../../validation/secretRotation";
|
||||||
|
import * as secretRotationService from "../../secretRotation/service";
|
||||||
|
import {
|
||||||
|
ProjectPermissionActions,
|
||||||
|
ProjectPermissionSub,
|
||||||
|
getAuthDataProjectPermissions
|
||||||
|
} from "../../services/ProjectRoleService";
|
||||||
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
|
export const createSecretRotation = async (req: Request, res: Response) => {
|
||||||
|
const {
|
||||||
|
body: {
|
||||||
|
provider,
|
||||||
|
customProvider,
|
||||||
|
interval,
|
||||||
|
outputs,
|
||||||
|
secretPath,
|
||||||
|
environment,
|
||||||
|
workspaceId,
|
||||||
|
inputs
|
||||||
|
}
|
||||||
|
} = await validateRequest(reqValidator.createSecretRotationV1, req);
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionSub.SecretRotation
|
||||||
|
);
|
||||||
|
|
||||||
|
const secretRotation = await secretRotationService.createSecretRotation({
|
||||||
|
workspaceId,
|
||||||
|
inputs,
|
||||||
|
environment,
|
||||||
|
secretPath,
|
||||||
|
outputs,
|
||||||
|
interval,
|
||||||
|
customProvider,
|
||||||
|
provider
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.send({ secretRotation });
|
||||||
|
};
|
||||||
|
|
||||||
|
export const restartSecretRotations = async (req: Request, res: Response) => {
|
||||||
|
const {
|
||||||
|
body: { id }
|
||||||
|
} = await validateRequest(reqValidator.restartSecretRotationV1, req);
|
||||||
|
|
||||||
|
const doc = await secretRotationService.getSecretRotationById({ id });
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: doc.workspace
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionSub.SecretRotation
|
||||||
|
);
|
||||||
|
|
||||||
|
const secretRotation = await secretRotationService.restartSecretRotation({ id });
|
||||||
|
return res.send({ secretRotation });
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteSecretRotations = async (req: Request, res: Response) => {
|
||||||
|
const {
|
||||||
|
params: { id }
|
||||||
|
} = await validateRequest(reqValidator.removeSecretRotationV1, req);
|
||||||
|
|
||||||
|
const doc = await secretRotationService.getSecretRotationById({ id });
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: doc.workspace
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Delete,
|
||||||
|
ProjectPermissionSub.SecretRotation
|
||||||
|
);
|
||||||
|
|
||||||
|
const secretRotations = await secretRotationService.deleteSecretRotation({ id });
|
||||||
|
return res.send({ secretRotations });
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getSecretRotations = async (req: Request, res: Response) => {
|
||||||
|
const {
|
||||||
|
query: { workspaceId }
|
||||||
|
} = await validateRequest(reqValidator.getSecretRotationV1, req);
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Read,
|
||||||
|
ProjectPermissionSub.SecretRotation
|
||||||
|
);
|
||||||
|
|
||||||
|
const secretRotations = await secretRotationService.getSecretRotationOfWorkspace(workspaceId);
|
||||||
|
return res.send({ secretRotations });
|
||||||
|
};
|
@ -0,0 +1,33 @@
|
|||||||
|
import { Request, Response } from "express";
|
||||||
|
import { Types } from "mongoose";
|
||||||
|
import { validateRequest } from "../../../helpers/validation";
|
||||||
|
import * as reqValidator from "../../validation/secretRotationProvider";
|
||||||
|
import * as secretRotationProviderService from "../../secretRotation/service";
|
||||||
|
import {
|
||||||
|
ProjectPermissionActions,
|
||||||
|
ProjectPermissionSub,
|
||||||
|
getAuthDataProjectPermissions
|
||||||
|
} from "../../services/ProjectRoleService";
|
||||||
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
|
export const getProviderTemplates = async (req: Request, res: Response) => {
|
||||||
|
const {
|
||||||
|
params: { workspaceId }
|
||||||
|
} = await validateRequest(reqValidator.getSecretRotationProvidersV1, req);
|
||||||
|
|
||||||
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Read,
|
||||||
|
ProjectPermissionSub.SecretRotation
|
||||||
|
);
|
||||||
|
|
||||||
|
const rotationProviderList = await secretRotationProviderService.getProviderTemplate({
|
||||||
|
workspaceId
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.send(rotationProviderList);
|
||||||
|
};
|
@ -4,7 +4,7 @@ import { validateRequest } from "../../../helpers/validation";
|
|||||||
import {
|
import {
|
||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
ProjectPermissionSub,
|
ProjectPermissionSub,
|
||||||
getUserProjectPermissions
|
getAuthDataProjectPermissions
|
||||||
} from "../../services/ProjectRoleService";
|
} from "../../services/ProjectRoleService";
|
||||||
import * as reqValidator from "../../../validation/secretSnapshot";
|
import * as reqValidator from "../../../validation/secretSnapshot";
|
||||||
import { ISecretVersion, SecretSnapshot, TFolderRootVersionSchema } from "../../models";
|
import { ISecretVersion, SecretSnapshot, TFolderRootVersionSchema } from "../../models";
|
||||||
@ -33,10 +33,11 @@ export const getSecretSnapshot = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
if (!secretSnapshot) throw new Error("Failed to find secret snapshot");
|
if (!secretSnapshot) throw new Error("Failed to find secret snapshot");
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
req.user._id,
|
authData: req.authData,
|
||||||
secretSnapshot.workspace.toString()
|
workspaceId: secretSnapshot.workspace
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.SecretRollback
|
ProjectPermissionSub.SecretRollback
|
@ -13,7 +13,7 @@ import { validateRequest } from "../../../helpers/validation";
|
|||||||
import {
|
import {
|
||||||
OrgPermissionActions,
|
OrgPermissionActions,
|
||||||
OrgPermissionSubjects,
|
OrgPermissionSubjects,
|
||||||
getUserOrgPermissions
|
getAuthDataOrgPermissions
|
||||||
} from "../../services/RoleService";
|
} from "../../services/RoleService";
|
||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
@ -47,7 +47,10 @@ export const getSSOConfig = async (req: Request, res: Response) => {
|
|||||||
query: { organizationId }
|
query: { organizationId }
|
||||||
} = await validateRequest(reqValidator.GetSsoConfigv1, req);
|
} = await validateRequest(reqValidator.GetSsoConfigv1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Read,
|
OrgPermissionActions.Read,
|
||||||
OrgPermissionSubjects.Sso
|
OrgPermissionSubjects.Sso
|
||||||
@ -71,7 +74,10 @@ export const updateSSOConfig = async (req: Request, res: Response) => {
|
|||||||
body: { organizationId, authProvider, isActive, entryPoint, issuer, cert }
|
body: { organizationId, authProvider, isActive, entryPoint, issuer, cert }
|
||||||
} = await validateRequest(reqValidator.UpdateSsoConfigv1, req);
|
} = await validateRequest(reqValidator.UpdateSsoConfigv1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Edit,
|
OrgPermissionActions.Edit,
|
||||||
OrgPermissionSubjects.Sso
|
OrgPermissionSubjects.Sso
|
||||||
@ -206,7 +212,10 @@ export const createSSOConfig = async (req: Request, res: Response) => {
|
|||||||
body: { organizationId, authProvider, isActive, entryPoint, issuer, cert }
|
body: { organizationId, authProvider, isActive, entryPoint, issuer, cert }
|
||||||
} = await validateRequest(reqValidator.CreateSsoConfigv1, req);
|
} = await validateRequest(reqValidator.CreateSsoConfigv1, req);
|
||||||
|
|
||||||
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Create,
|
OrgPermissionActions.Create,
|
||||||
OrgPermissionSubjects.Sso
|
OrgPermissionSubjects.Sso
|
@ -2,10 +2,11 @@ import { Request, Response } from "express";
|
|||||||
import { PipelineStage, Types } from "mongoose";
|
import { PipelineStage, Types } from "mongoose";
|
||||||
import {
|
import {
|
||||||
Folder,
|
Folder,
|
||||||
|
Identity,
|
||||||
|
IdentityMembership,
|
||||||
Membership,
|
Membership,
|
||||||
Secret,
|
Secret,
|
||||||
ServiceTokenData,
|
ServiceTokenData,
|
||||||
ServiceTokenDataV3,
|
|
||||||
TFolderSchema,
|
TFolderSchema,
|
||||||
User,
|
User,
|
||||||
Workspace
|
Workspace
|
||||||
@ -17,18 +18,16 @@ import {
|
|||||||
FolderVersion,
|
FolderVersion,
|
||||||
IPType,
|
IPType,
|
||||||
ISecretVersion,
|
ISecretVersion,
|
||||||
Log,
|
IdentityActor,
|
||||||
SecretSnapshot,
|
SecretSnapshot,
|
||||||
SecretVersion,
|
SecretVersion,
|
||||||
ServiceActor,
|
ServiceActor,
|
||||||
ServiceActorV3,
|
|
||||||
TFolderRootVersionSchema,
|
TFolderRootVersionSchema,
|
||||||
TrustedIP,
|
TrustedIP,
|
||||||
UserActor
|
UserActor
|
||||||
} from "../../models";
|
} from "../../models";
|
||||||
import { EESecretService } from "../../services";
|
import { EESecretService } from "../../services";
|
||||||
import { getLatestSecretVersionIds } from "../../helpers/secretVersion";
|
import { getLatestSecretVersionIds } from "../../helpers/secretVersion";
|
||||||
// import Folder, { TFolderSchema } from "../../../models/folder";
|
|
||||||
import { getFolderByPath, searchByFolderId } from "../../../services/FolderService";
|
import { getFolderByPath, searchByFolderId } from "../../../services/FolderService";
|
||||||
import { EEAuditLogService, EELicenseService } from "../../services";
|
import { EEAuditLogService, EELicenseService } from "../../services";
|
||||||
import { extractIPDetails, isValidIpOrCidr } from "../../../utils/ip";
|
import { extractIPDetails, isValidIpOrCidr } from "../../../utils/ip";
|
||||||
@ -38,7 +37,6 @@ import {
|
|||||||
DeleteWorkspaceTrustedIpV1,
|
DeleteWorkspaceTrustedIpV1,
|
||||||
GetWorkspaceAuditLogActorFilterOptsV1,
|
GetWorkspaceAuditLogActorFilterOptsV1,
|
||||||
GetWorkspaceAuditLogsV1,
|
GetWorkspaceAuditLogsV1,
|
||||||
GetWorkspaceLogsV1,
|
|
||||||
GetWorkspaceSecretSnapshotsCountV1,
|
GetWorkspaceSecretSnapshotsCountV1,
|
||||||
GetWorkspaceSecretSnapshotsV1,
|
GetWorkspaceSecretSnapshotsV1,
|
||||||
GetWorkspaceTrustedIpsV1,
|
GetWorkspaceTrustedIpsV1,
|
||||||
@ -48,7 +46,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
ProjectPermissionSub,
|
ProjectPermissionSub,
|
||||||
getUserProjectPermissions
|
getAuthDataProjectPermissions
|
||||||
} from "../../services/ProjectRoleService";
|
} from "../../services/ProjectRoleService";
|
||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
import { BadRequestError } from "../../../utils/errors";
|
import { BadRequestError } from "../../../utils/errors";
|
||||||
@ -64,15 +62,30 @@ export const getWorkspaceSecretSnapshots = async (req: Request, res: Response) =
|
|||||||
#swagger.description = 'Return project secret snapshots ids'
|
#swagger.description = 'Return project secret snapshots ids'
|
||||||
|
|
||||||
#swagger.security = [{
|
#swagger.security = [{
|
||||||
"apiKeyAuth": []
|
"apiKeyAuth": [],
|
||||||
|
"bearerAuth": []
|
||||||
}]
|
}]
|
||||||
|
|
||||||
#swagger.parameters['workspaceId'] = {
|
#swagger.parameters['workspaceId'] = {
|
||||||
"description": "ID of project",
|
"description": "ID of project where to get secret snapshots for",
|
||||||
"required": true,
|
"required": true,
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#swagger.parameters['environment'] = {
|
||||||
|
"description": "Slug of environment where to get secret snapshots for",
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"in": "query"
|
||||||
|
}
|
||||||
|
|
||||||
|
#swagger.parameters['directory'] = {
|
||||||
|
"description": "Path where to get secret snapshots for like / or /foo/bar. Default is /",
|
||||||
|
"required": false,
|
||||||
|
"type": "string",
|
||||||
|
"in": "query"
|
||||||
|
}
|
||||||
|
|
||||||
#swagger.parameters['offset'] = {
|
#swagger.parameters['offset'] = {
|
||||||
"description": "Number of secret snapshots to skip",
|
"description": "Number of secret snapshots to skip",
|
||||||
"required": false,
|
"required": false,
|
||||||
@ -109,7 +122,11 @@ export const getWorkspaceSecretSnapshots = async (req: Request, res: Response) =
|
|||||||
query: { environment, directory, offset, limit }
|
query: { environment, directory, offset, limit }
|
||||||
} = await validateRequest(GetWorkspaceSecretSnapshotsV1, req);
|
} = await validateRequest(GetWorkspaceSecretSnapshotsV1, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.SecretRollback
|
ProjectPermissionSub.SecretRollback
|
||||||
@ -150,7 +167,11 @@ export const getWorkspaceSecretSnapshotsCount = async (req: Request, res: Respon
|
|||||||
query: { environment, directory }
|
query: { environment, directory }
|
||||||
} = await validateRequest(GetWorkspaceSecretSnapshotsCountV1, req);
|
} = await validateRequest(GetWorkspaceSecretSnapshotsCountV1, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.SecretRollback
|
ProjectPermissionSub.SecretRollback
|
||||||
@ -189,11 +210,12 @@ export const rollbackWorkspaceSecretSnapshot = async (req: Request, res: Respons
|
|||||||
#swagger.description = 'Roll back project secrets to those captured in a secret snapshot version.'
|
#swagger.description = 'Roll back project secrets to those captured in a secret snapshot version.'
|
||||||
|
|
||||||
#swagger.security = [{
|
#swagger.security = [{
|
||||||
"apiKeyAuth": []
|
"apiKeyAuth": [],
|
||||||
|
"bearerAuth": []
|
||||||
}]
|
}]
|
||||||
|
|
||||||
#swagger.parameters['workspaceId'] = {
|
#swagger.parameters['workspaceId'] = {
|
||||||
"description": "ID of project",
|
"description": "ID of project where to roll back",
|
||||||
"required": true,
|
"required": true,
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
@ -205,6 +227,14 @@ export const rollbackWorkspaceSecretSnapshot = async (req: Request, res: Respons
|
|||||||
"schema": {
|
"schema": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"environment": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Slug of environment where to roll back"
|
||||||
|
},
|
||||||
|
"directory": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Path where to roll back for like / or /foo/bar. Default is /"
|
||||||
|
},
|
||||||
"version": {
|
"version": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "Version of secret snapshot to roll back to",
|
"description": "Version of secret snapshot to roll back to",
|
||||||
@ -240,7 +270,11 @@ export const rollbackWorkspaceSecretSnapshot = async (req: Request, res: Respons
|
|||||||
body: { directory, environment, version }
|
body: { directory, environment, version }
|
||||||
} = await validateRequest(RollbackWorkspaceSecretSnapshotV1, req);
|
} = await validateRequest(RollbackWorkspaceSecretSnapshotV1, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Create,
|
ProjectPermissionActions.Create,
|
||||||
ProjectPermissionSub.SecretRollback
|
ProjectPermissionSub.SecretRollback
|
||||||
@ -564,55 +598,64 @@ export const rollbackWorkspaceSecretSnapshot = async (req: Request, res: Respons
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return (audit) logs for workspace with id [workspaceId]
|
* Return audit logs for workspace with id [workspaceId]
|
||||||
* @param req
|
* @param req
|
||||||
* @param res
|
* @param res
|
||||||
* @returns
|
|
||||||
*/
|
*/
|
||||||
export const getWorkspaceLogs = async (req: Request, res: Response) => {
|
export const getWorkspaceAuditLogs = async (req: Request, res: Response) => {
|
||||||
/*
|
/*
|
||||||
#swagger.summary = 'Return project (audit) logs'
|
#swagger.summary = 'Return audit logs'
|
||||||
#swagger.description = 'Return project (audit) logs'
|
#swagger.description = 'Return audit logs'
|
||||||
|
|
||||||
#swagger.security = [{
|
#swagger.security = [{
|
||||||
"apiKeyAuth": []
|
"apiKeyAuth": []
|
||||||
}]
|
}]
|
||||||
|
|
||||||
#swagger.parameters['workspaceId'] = {
|
#swagger.parameters['workspaceId'] = {
|
||||||
"description": "ID of project",
|
"description": "ID of the workspace where to get folders from",
|
||||||
"required": true,
|
"required": true,
|
||||||
"type": "string"
|
"type": "string",
|
||||||
}
|
"in": "path"
|
||||||
|
|
||||||
#swagger.parameters['userId'] = {
|
|
||||||
"description": "ID of project member",
|
|
||||||
"required": false,
|
|
||||||
"type": "string"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#swagger.parameters['offset'] = {
|
#swagger.parameters['offset'] = {
|
||||||
"description": "Number of logs to skip",
|
"description": "Number of logs to skip before starting to return logs for pagination",
|
||||||
"required": false,
|
"required": false,
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
|
|
||||||
#swagger.parameters['limit'] = {
|
#swagger.parameters['limit'] = {
|
||||||
"description": "Maximum number of logs to return",
|
"description": "Maximum number of logs to return for pagination",
|
||||||
"required": false,
|
"required": false,
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
|
|
||||||
#swagger.parameters['sortBy'] = {
|
#swagger.parameters['startDate'] = {
|
||||||
"description": "Order to sort the logs by",
|
"description": "Filter logs from this date in ISO-8601 format",
|
||||||
"schema": {
|
"required": false,
|
||||||
"type": "string",
|
"type": "string"
|
||||||
"@enum": ["oldest", "recent"]
|
|
||||||
},
|
|
||||||
"required": false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#swagger.parameters['actionNames'] = {
|
#swagger.parameters['endDate'] = {
|
||||||
"description": "Names of log actions (comma-separated)",
|
"description": "Filter logs till this date in ISO-8601 format",
|
||||||
|
"required": false,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
|
||||||
|
#swagger.parameters['eventType'] = {
|
||||||
|
"description": "Filter by type of event such as get-secrets, get-secret, create-secret, update-secret, delete-secret, etc.",
|
||||||
|
"required": false,
|
||||||
|
"type": "string",
|
||||||
|
}
|
||||||
|
|
||||||
|
#swagger.parameters['userAgentType'] = {
|
||||||
|
"description": "Filter by type of user agent such as web, cli, k8-operator, or other",
|
||||||
|
"required": false,
|
||||||
|
"type": "string",
|
||||||
|
}
|
||||||
|
|
||||||
|
#swagger.parameters['actor'] = {
|
||||||
|
"description": "Filter by actor such as user or service",
|
||||||
"required": false,
|
"required": false,
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
@ -623,69 +666,49 @@ export const getWorkspaceLogs = async (req: Request, res: Response) => {
|
|||||||
schema: {
|
schema: {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"logs": {
|
"auditLogs": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
$ref: "#/components/schemas/Log"
|
$ref: "#/components/schemas/AuditLog",
|
||||||
|
},
|
||||||
|
"description": "List of audit log"
|
||||||
},
|
},
|
||||||
"description": "Project logs"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
const {
|
|
||||||
query: { limit, offset, userId, sortBy, actionNames },
|
|
||||||
params: { workspaceId }
|
|
||||||
} = await validateRequest(GetWorkspaceLogsV1, req);
|
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
ProjectPermissionActions.Read,
|
|
||||||
ProjectPermissionSub.AuditLogs
|
|
||||||
);
|
|
||||||
|
|
||||||
const logs = await Log.find({
|
|
||||||
workspace: workspaceId,
|
|
||||||
...(userId ? { user: userId } : {}),
|
|
||||||
...(actionNames
|
|
||||||
? {
|
|
||||||
actionNames: {
|
|
||||||
$in: actionNames.split(",")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
: {})
|
|
||||||
})
|
|
||||||
.sort({ createdAt: sortBy === "recent" ? -1 : 1 })
|
|
||||||
.skip(offset)
|
|
||||||
.limit(limit)
|
|
||||||
.populate("actions")
|
|
||||||
.populate("user serviceAccount serviceTokenData");
|
|
||||||
|
|
||||||
return res.status(200).send({
|
|
||||||
logs
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return audit logs for workspace with id [workspaceId]
|
|
||||||
* @param req
|
|
||||||
* @param res
|
|
||||||
*/
|
|
||||||
export const getWorkspaceAuditLogs = async (req: Request, res: Response) => {
|
|
||||||
const {
|
const {
|
||||||
query: { limit, offset, endDate, eventType, startDate, userAgentType, actor },
|
query: { limit, offset, endDate, eventType, startDate, userAgentType, actor },
|
||||||
params: { workspaceId }
|
params: { workspaceId }
|
||||||
} = await validateRequest(GetWorkspaceAuditLogsV1, req);
|
} = await validateRequest(GetWorkspaceAuditLogsV1, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.AuditLogs
|
ProjectPermissionSub.AuditLogs
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let actorMetadataQuery = "";
|
||||||
|
if (actor) {
|
||||||
|
switch (actor?.split("-", 2)[0]) {
|
||||||
|
case ActorType.USER:
|
||||||
|
actorMetadataQuery = "actor.metadata.userId";
|
||||||
|
break;
|
||||||
|
case ActorType.SERVICE:
|
||||||
|
actorMetadataQuery = "actor.metadata.serviceId";
|
||||||
|
break;
|
||||||
|
case ActorType.IDENTITY:
|
||||||
|
actorMetadataQuery = "actor.metadata.identityId";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const query = {
|
const query = {
|
||||||
workspace: new Types.ObjectId(workspaceId),
|
workspace: new Types.ObjectId(workspaceId),
|
||||||
...(eventType
|
...(eventType
|
||||||
@ -701,12 +724,8 @@ export const getWorkspaceAuditLogs = async (req: Request, res: Response) => {
|
|||||||
...(actor
|
...(actor
|
||||||
? {
|
? {
|
||||||
"actor.type": actor.substring(0, actor.lastIndexOf("-")),
|
"actor.type": actor.substring(0, actor.lastIndexOf("-")),
|
||||||
...(actor.split("-", 2)[0] === ActorType.USER
|
...({
|
||||||
? {
|
[actorMetadataQuery]: actor.substring(actor.lastIndexOf("-") + 1)
|
||||||
"actor.metadata.userId": actor.substring(actor.lastIndexOf("-") + 1)
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
"actor.metadata.serviceId": actor.substring(actor.lastIndexOf("-") + 1)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
@ -722,11 +741,8 @@ export const getWorkspaceAuditLogs = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
const auditLogs = await AuditLog.find(query).sort({ createdAt: -1 }).skip(offset).limit(limit);
|
const auditLogs = await AuditLog.find(query).sort({ createdAt: -1 }).skip(offset).limit(limit);
|
||||||
|
|
||||||
const totalCount = await AuditLog.countDocuments(query);
|
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
auditLogs,
|
auditLogs
|
||||||
totalCount
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -740,7 +756,11 @@ export const getWorkspaceAuditLogActorFilterOpts = async (req: Request, res: Res
|
|||||||
params: { workspaceId }
|
params: { workspaceId }
|
||||||
} = await validateRequest(GetWorkspaceAuditLogActorFilterOptsV1, req);
|
} = await validateRequest(GetWorkspaceAuditLogActorFilterOptsV1, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.AuditLogs
|
ProjectPermissionSub.AuditLogs
|
||||||
@ -749,6 +769,7 @@ export const getWorkspaceAuditLogActorFilterOpts = async (req: Request, res: Res
|
|||||||
const userIds = await Membership.distinct("user", {
|
const userIds = await Membership.distinct("user", {
|
||||||
workspace: new Types.ObjectId(workspaceId)
|
workspace: new Types.ObjectId(workspaceId)
|
||||||
});
|
});
|
||||||
|
|
||||||
const userActors: UserActor[] = (
|
const userActors: UserActor[] = (
|
||||||
await User.find({
|
await User.find({
|
||||||
_id: {
|
_id: {
|
||||||
@ -775,23 +796,25 @@ export const getWorkspaceAuditLogActorFilterOpts = async (req: Request, res: Res
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const serviceV3Actors: ServiceActorV3[] = (
|
const identityIds = await IdentityMembership.distinct("identity", {
|
||||||
await ServiceTokenDataV3.find({
|
|
||||||
workspace: new Types.ObjectId(workspaceId)
|
workspace: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
|
const identityActors: IdentityActor[] = (
|
||||||
|
await Identity.find({
|
||||||
|
_id: {
|
||||||
|
$in: identityIds
|
||||||
|
}
|
||||||
})
|
})
|
||||||
).map((serviceTokenData) => ({
|
).map((identity) => ({
|
||||||
type: ActorType.SERVICE_V3,
|
type: ActorType.IDENTITY,
|
||||||
metadata: {
|
metadata: {
|
||||||
serviceId: serviceTokenData._id.toString(),
|
identityId: identity._id.toString(),
|
||||||
name: serviceTokenData.name
|
name: identity.name
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const actors = [
|
const actors = [...userActors, ...serviceActors, ...identityActors];
|
||||||
...userActors,
|
|
||||||
...serviceActors,
|
|
||||||
...serviceV3Actors
|
|
||||||
];
|
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
actors
|
actors
|
||||||
@ -808,7 +831,11 @@ export const getWorkspaceTrustedIps = async (req: Request, res: Response) => {
|
|||||||
params: { workspaceId }
|
params: { workspaceId }
|
||||||
} = await validateRequest(GetWorkspaceTrustedIpsV1, req);
|
} = await validateRequest(GetWorkspaceTrustedIpsV1, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
ProjectPermissionSub.IpAllowList
|
ProjectPermissionSub.IpAllowList
|
||||||
@ -834,7 +861,11 @@ export const addWorkspaceTrustedIp = async (req: Request, res: Response) => {
|
|||||||
body: { comment, isActive, ipAddress: ip }
|
body: { comment, isActive, ipAddress: ip }
|
||||||
} = await validateRequest(AddWorkspaceTrustedIpV1, req);
|
} = await validateRequest(AddWorkspaceTrustedIpV1, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Create,
|
ProjectPermissionActions.Create,
|
||||||
ProjectPermissionSub.IpAllowList
|
ProjectPermissionSub.IpAllowList
|
||||||
@ -900,7 +931,11 @@ export const updateWorkspaceTrustedIp = async (req: Request, res: Response) => {
|
|||||||
body: { ipAddress: ip, comment }
|
body: { ipAddress: ip, comment }
|
||||||
} = await validateRequest(UpdateWorkspaceTrustedIpV1, req);
|
} = await validateRequest(UpdateWorkspaceTrustedIpV1, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Edit,
|
ProjectPermissionActions.Edit,
|
||||||
ProjectPermissionSub.IpAllowList
|
ProjectPermissionSub.IpAllowList
|
||||||
@ -992,7 +1027,11 @@ export const deleteWorkspaceTrustedIp = async (req: Request, res: Response) => {
|
|||||||
params: { workspaceId, trustedIpId }
|
params: { workspaceId, trustedIpId }
|
||||||
} = await validateRequest(DeleteWorkspaceTrustedIpV1, req);
|
} = await validateRequest(DeleteWorkspaceTrustedIpV1, req);
|
||||||
|
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getAuthDataProjectPermissions({
|
||||||
|
authData: req.authData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Delete,
|
ProjectPermissionActions.Delete,
|
||||||
ProjectPermissionSub.IpAllowList
|
ProjectPermissionSub.IpAllowList
|
101
backend-mongo/src/ee/controllers/v3/apiKeyDataController.ts
Normal file
101
backend-mongo/src/ee/controllers/v3/apiKeyDataController.ts
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import { Request, Response } from "express";
|
||||||
|
import { Types } from "mongoose";
|
||||||
|
import { APIKeyDataV2 } from "../../../models/apiKeyDataV2";
|
||||||
|
import { validateRequest } from "../../../helpers/validation";
|
||||||
|
import { BadRequestError } from "../../../utils/errors";
|
||||||
|
import * as reqValidator from "../../../validation";
|
||||||
|
import { createToken } from "../../../helpers";
|
||||||
|
import { AuthTokenType } from "../../../variables";
|
||||||
|
import { getAuthSecret } from "../../../config";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create API key data v2
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
*/
|
||||||
|
export const createAPIKeyData = async (req: Request, res: Response) => {
|
||||||
|
const {
|
||||||
|
body: {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
} = await validateRequest(reqValidator.CreateAPIKeyV3, req);
|
||||||
|
|
||||||
|
const apiKeyData = await new APIKeyDataV2({
|
||||||
|
name,
|
||||||
|
user: req.user._id,
|
||||||
|
usageCount: 0,
|
||||||
|
}).save();
|
||||||
|
|
||||||
|
const apiKey = createToken({
|
||||||
|
payload: {
|
||||||
|
authTokenType: AuthTokenType.API_KEY,
|
||||||
|
apiKeyDataId: apiKeyData._id.toString(),
|
||||||
|
userId: req.user._id.toString()
|
||||||
|
},
|
||||||
|
secret: await getAuthSecret()
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
apiKeyData,
|
||||||
|
apiKey
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update API key data v2 with id [apiKeyDataId]
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
*/
|
||||||
|
export const updateAPIKeyData = async (req: Request, res: Response) => {
|
||||||
|
const {
|
||||||
|
params: { apiKeyDataId },
|
||||||
|
body: {
|
||||||
|
name,
|
||||||
|
}
|
||||||
|
} = await validateRequest(reqValidator.UpdateAPIKeyV3, req);
|
||||||
|
|
||||||
|
const apiKeyData = await APIKeyDataV2.findOneAndUpdate(
|
||||||
|
{
|
||||||
|
_id: new Types.ObjectId(apiKeyDataId),
|
||||||
|
user: req.user._id
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!apiKeyData) throw BadRequestError({
|
||||||
|
message: "Failed to update API key"
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
apiKeyData
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete API key data v2 with id [apiKeyDataId]
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
*/
|
||||||
|
export const deleteAPIKeyData = async (req: Request, res: Response) => {
|
||||||
|
const {
|
||||||
|
params: { apiKeyDataId }
|
||||||
|
} = await validateRequest(reqValidator.DeleteAPIKeyV3, req);
|
||||||
|
|
||||||
|
const apiKeyData = await APIKeyDataV2.findOneAndDelete({
|
||||||
|
_id: new Types.ObjectId(apiKeyDataId),
|
||||||
|
user: req.user._id
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!apiKeyData) throw BadRequestError({
|
||||||
|
message: "Failed to delete API key"
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
apiKeyData
|
||||||
|
});
|
||||||
|
}
|
5
backend-mongo/src/ee/controllers/v3/index.ts
Normal file
5
backend-mongo/src/ee/controllers/v3/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import * as apiKeyDataController from "./apiKeyDataController";
|
||||||
|
|
||||||
|
export {
|
||||||
|
apiKeyDataController
|
||||||
|
}
|
70
backend-mongo/src/ee/models/auditLog/auditLog.ts
Normal file
70
backend-mongo/src/ee/models/auditLog/auditLog.ts
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
import { ActorType, EventType, UserAgentType } from "./enums";
|
||||||
|
import { Actor, Event } from "./types";
|
||||||
|
|
||||||
|
export interface IAuditLog {
|
||||||
|
actor: Actor;
|
||||||
|
organization: Types.ObjectId;
|
||||||
|
workspace: Types.ObjectId;
|
||||||
|
ipAddress: string;
|
||||||
|
event: Event;
|
||||||
|
userAgent: string;
|
||||||
|
userAgentType: UserAgentType;
|
||||||
|
expiresAt?: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auditLogSchema = new Schema<IAuditLog>(
|
||||||
|
{
|
||||||
|
actor: {
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
enum: ActorType,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
type: Schema.Types.Mixed
|
||||||
|
}
|
||||||
|
},
|
||||||
|
organization: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
required: false,
|
||||||
|
index: true
|
||||||
|
},
|
||||||
|
ipAddress: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
event: {
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
enum: EventType,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
type: Schema.Types.Mixed
|
||||||
|
}
|
||||||
|
},
|
||||||
|
userAgent: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
userAgentType: {
|
||||||
|
type: String,
|
||||||
|
enum: UserAgentType,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
expiresAt: {
|
||||||
|
type: Date,
|
||||||
|
expires: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const AuditLog = model<IAuditLog>("AuditLog", auditLogSchema);
|
@ -1,14 +1,17 @@
|
|||||||
export enum ActorType {
|
export enum ActorType { // would extend to AWS, Azure, ...
|
||||||
USER = "user",
|
USER = "user", // userIdentity
|
||||||
SERVICE = "service",
|
SERVICE = "service",
|
||||||
SERVICE_V3 = "service-v3"
|
IDENTITY = "identity"
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum UserAgentType {
|
export enum UserAgentType {
|
||||||
WEB = "web",
|
WEB = "web",
|
||||||
CLI = "cli",
|
CLI = "cli",
|
||||||
K8_OPERATOR = "k8-operator",
|
K8_OPERATOR = "k8-operator",
|
||||||
OTHER = "other"
|
TERRAFORM = "terraform",
|
||||||
|
OTHER = "other",
|
||||||
|
PYTHON_SDK = "InfisicalPythonSDK",
|
||||||
|
NODE_SDK = "InfisicalNodeSDK"
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum EventType {
|
export enum EventType {
|
||||||
@ -31,13 +34,21 @@ export enum EventType {
|
|||||||
DELETE_TRUSTED_IP = "delete-trusted-ip",
|
DELETE_TRUSTED_IP = "delete-trusted-ip",
|
||||||
CREATE_SERVICE_TOKEN = "create-service-token", // v2
|
CREATE_SERVICE_TOKEN = "create-service-token", // v2
|
||||||
DELETE_SERVICE_TOKEN = "delete-service-token", // v2
|
DELETE_SERVICE_TOKEN = "delete-service-token", // v2
|
||||||
CREATE_SERVICE_TOKEN_V3 = "create-service-token-v3", // v3
|
CREATE_IDENTITY = "create-identity",
|
||||||
UPDATE_SERVICE_TOKEN_V3 = "update-service-token-v3", // v3
|
UPDATE_IDENTITY = "update-identity",
|
||||||
DELETE_SERVICE_TOKEN_V3 = "delete-service-token-v3", // v3
|
DELETE_IDENTITY = "delete-identity",
|
||||||
|
LOGIN_IDENTITY_UNIVERSAL_AUTH = "login-identity-universal-auth",
|
||||||
|
ADD_IDENTITY_UNIVERSAL_AUTH = "add-identity-universal-auth",
|
||||||
|
UPDATE_IDENTITY_UNIVERSAL_AUTH = "update-identity-universal-auth",
|
||||||
|
GET_IDENTITY_UNIVERSAL_AUTH = "get-identity-universal-auth",
|
||||||
|
CREATE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "create-identity-universal-auth-client-secret",
|
||||||
|
REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "revoke-identity-universal-auth-client-secret",
|
||||||
|
GET_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRETS = "get-identity-universal-auth-client-secret",
|
||||||
CREATE_ENVIRONMENT = "create-environment",
|
CREATE_ENVIRONMENT = "create-environment",
|
||||||
UPDATE_ENVIRONMENT = "update-environment",
|
UPDATE_ENVIRONMENT = "update-environment",
|
||||||
DELETE_ENVIRONMENT = "delete-environment",
|
DELETE_ENVIRONMENT = "delete-environment",
|
||||||
ADD_WORKSPACE_MEMBER = "add-workspace-member",
|
ADD_WORKSPACE_MEMBER = "add-workspace-member",
|
||||||
|
ADD_BATCH_WORKSPACE_MEMBER = "add-workspace-members",
|
||||||
REMOVE_WORKSPACE_MEMBER = "remove-workspace-member",
|
REMOVE_WORKSPACE_MEMBER = "remove-workspace-member",
|
||||||
CREATE_FOLDER = "create-folder",
|
CREATE_FOLDER = "create-folder",
|
||||||
UPDATE_FOLDER = "update-folder",
|
UPDATE_FOLDER = "update-folder",
|
@ -1,11 +1,5 @@
|
|||||||
import {
|
import { ActorType, EventType } from "./enums";
|
||||||
ActorType,
|
import { IIdentityTrustedIp } from "../../../models";
|
||||||
EventType
|
|
||||||
} from "./enums";
|
|
||||||
import {
|
|
||||||
IServiceTokenV3Scope,
|
|
||||||
IServiceTokenV3TrustedIp
|
|
||||||
} from "../../../models/serviceTokenDataV3";
|
|
||||||
|
|
||||||
interface UserActorMetadata {
|
interface UserActorMetadata {
|
||||||
userId: string;
|
userId: string;
|
||||||
@ -17,6 +11,11 @@ interface ServiceActorMetadata {
|
|||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IdentityActorMetadata {
|
||||||
|
identityId: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface UserActor {
|
export interface UserActor {
|
||||||
type: ActorType.USER;
|
type: ActorType.USER;
|
||||||
metadata: UserActorMetadata;
|
metadata: UserActorMetadata;
|
||||||
@ -27,15 +26,12 @@ export interface ServiceActor {
|
|||||||
metadata: ServiceActorMetadata;
|
metadata: ServiceActorMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ServiceActorV3 {
|
export interface IdentityActor {
|
||||||
type: ActorType.SERVICE_V3;
|
type: ActorType.IDENTITY;
|
||||||
metadata: ServiceActorMetadata;
|
metadata: IdentityActorMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Actor =
|
export type Actor = UserActor | ServiceActor | IdentityActor;
|
||||||
| UserActor
|
|
||||||
| ServiceActor
|
|
||||||
| ServiceActorV3;
|
|
||||||
|
|
||||||
interface GetSecretsEvent {
|
interface GetSecretsEvent {
|
||||||
type: EventType.GET_SECRETS;
|
type: EventType.GET_SECRETS;
|
||||||
@ -225,37 +221,92 @@ interface DeleteServiceTokenEvent {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CreateServiceTokenV3Event {
|
interface CreateIdentityEvent { // note: currently not logging org-role
|
||||||
type: EventType.CREATE_SERVICE_TOKEN_V3;
|
type: EventType.CREATE_IDENTITY;
|
||||||
metadata: {
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
name: string;
|
name: string;
|
||||||
isActive: boolean;
|
};
|
||||||
scopes: Array<IServiceTokenV3Scope>;
|
|
||||||
trustedIps: Array<IServiceTokenV3TrustedIp>;
|
|
||||||
expiresAt?: Date;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface UpdateServiceTokenV3Event {
|
interface UpdateIdentityEvent {
|
||||||
type: EventType.UPDATE_SERVICE_TOKEN_V3;
|
type: EventType.UPDATE_IDENTITY;
|
||||||
metadata: {
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
isActive?: boolean;
|
};
|
||||||
scopes?: Array<IServiceTokenV3Scope>;
|
|
||||||
trustedIps?: Array<IServiceTokenV3TrustedIp>;
|
|
||||||
expiresAt?: Date;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DeleteServiceTokenV3Event {
|
interface DeleteIdentityEvent {
|
||||||
type: EventType.DELETE_SERVICE_TOKEN_V3;
|
type: EventType.DELETE_IDENTITY;
|
||||||
metadata: {
|
metadata: {
|
||||||
name: string;
|
identityId: string;
|
||||||
isActive: boolean;
|
};
|
||||||
scopes: Array<IServiceTokenV3Scope>;
|
|
||||||
expiresAt?: Date;
|
|
||||||
trustedIps: Array<IServiceTokenV3TrustedIp>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface LoginIdentityUniversalAuthEvent {
|
||||||
|
type: EventType.LOGIN_IDENTITY_UNIVERSAL_AUTH ;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
identityUniversalAuthId: string;
|
||||||
|
clientSecretId: string;
|
||||||
|
identityAccessTokenId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AddIdentityUniversalAuthEvent {
|
||||||
|
type: EventType.ADD_IDENTITY_UNIVERSAL_AUTH;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
clientSecretTrustedIps: Array<IIdentityTrustedIp>;
|
||||||
|
accessTokenTTL: number;
|
||||||
|
accessTokenMaxTTL: number;
|
||||||
|
accessTokenNumUsesLimit: number;
|
||||||
|
accessTokenTrustedIps: Array<IIdentityTrustedIp>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateIdentityUniversalAuthEvent {
|
||||||
|
type: EventType.UPDATE_IDENTITY_UNIVERSAL_AUTH;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
clientSecretTrustedIps?: Array<IIdentityTrustedIp>;
|
||||||
|
accessTokenTTL?: number;
|
||||||
|
accessTokenMaxTTL?: number;
|
||||||
|
accessTokenNumUsesLimit?: number;
|
||||||
|
accessTokenTrustedIps?: Array<IIdentityTrustedIp>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetIdentityUniversalAuthEvent {
|
||||||
|
type: EventType.GET_IDENTITY_UNIVERSAL_AUTH;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateIdentityUniversalAuthClientSecretEvent {
|
||||||
|
type: EventType.CREATE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET ;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
clientSecretId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetIdentityUniversalAuthClientSecretsEvent {
|
||||||
|
type: EventType.GET_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRETS;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface RevokeIdentityUniversalAuthClientSecretEvent {
|
||||||
|
type: EventType.REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET ;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
clientSecretId: string;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CreateEnvironmentEvent {
|
interface CreateEnvironmentEvent {
|
||||||
@ -292,6 +343,14 @@ interface AddWorkspaceMemberEvent {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface AddBatchWorkspaceMemberEvent {
|
||||||
|
type: EventType.ADD_BATCH_WORKSPACE_MEMBER;
|
||||||
|
metadata: Array<{
|
||||||
|
userId: string;
|
||||||
|
email: string;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
interface RemoveWorkspaceMemberEvent {
|
interface RemoveWorkspaceMemberEvent {
|
||||||
type: EventType.REMOVE_WORKSPACE_MEMBER;
|
type: EventType.REMOVE_WORKSPACE_MEMBER;
|
||||||
metadata: {
|
metadata: {
|
||||||
@ -427,15 +486,15 @@ interface UpdateUserRole {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface UpdateUserDeniedPermissions {
|
interface UpdateUserDeniedPermissions {
|
||||||
type: EventType.UPDATE_USER_WORKSPACE_DENIED_PERMISSIONS,
|
type: EventType.UPDATE_USER_WORKSPACE_DENIED_PERMISSIONS;
|
||||||
metadata: {
|
metadata: {
|
||||||
userId: string;
|
userId: string;
|
||||||
email: string;
|
email: string;
|
||||||
deniedPermissions: {
|
deniedPermissions: {
|
||||||
environmentSlug: string;
|
environmentSlug: string;
|
||||||
ability: string;
|
ability: string;
|
||||||
}[]
|
}[];
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
interface SecretApprovalMerge {
|
interface SecretApprovalMerge {
|
||||||
type: EventType.SECRET_APPROVAL_MERGED;
|
type: EventType.SECRET_APPROVAL_MERGED;
|
||||||
@ -492,13 +551,21 @@ export type Event =
|
|||||||
| DeleteTrustedIPEvent
|
| DeleteTrustedIPEvent
|
||||||
| CreateServiceTokenEvent
|
| CreateServiceTokenEvent
|
||||||
| DeleteServiceTokenEvent
|
| DeleteServiceTokenEvent
|
||||||
| CreateServiceTokenV3Event
|
| CreateIdentityEvent
|
||||||
| UpdateServiceTokenV3Event
|
| UpdateIdentityEvent
|
||||||
| DeleteServiceTokenV3Event
|
| DeleteIdentityEvent
|
||||||
|
| LoginIdentityUniversalAuthEvent
|
||||||
|
| AddIdentityUniversalAuthEvent
|
||||||
|
| UpdateIdentityUniversalAuthEvent
|
||||||
|
| GetIdentityUniversalAuthEvent
|
||||||
|
| CreateIdentityUniversalAuthClientSecretEvent
|
||||||
|
| GetIdentityUniversalAuthClientSecretsEvent
|
||||||
|
| RevokeIdentityUniversalAuthClientSecretEvent
|
||||||
| CreateEnvironmentEvent
|
| CreateEnvironmentEvent
|
||||||
| UpdateEnvironmentEvent
|
| UpdateEnvironmentEvent
|
||||||
| DeleteEnvironmentEvent
|
| DeleteEnvironmentEvent
|
||||||
| AddWorkspaceMemberEvent
|
| AddWorkspaceMemberEvent
|
||||||
|
| AddBatchWorkspaceMemberEvent
|
||||||
| RemoveWorkspaceMemberEvent
|
| RemoveWorkspaceMemberEvent
|
||||||
| CreateFolderEvent
|
| CreateFolderEvent
|
||||||
| UpdateFolderEvent
|
| UpdateFolderEvent
|
@ -1,9 +1,7 @@
|
|||||||
export * from "./secretSnapshot";
|
export * from "./secretSnapshot";
|
||||||
export * from "./secretVersion";
|
export * from "./secretVersion";
|
||||||
export * from "./folderVersion";
|
export * from "./folderVersion";
|
||||||
export * from "./log";
|
|
||||||
export * from "./role";
|
export * from "./role";
|
||||||
export * from "./action";
|
|
||||||
export * from "./ssoConfig";
|
export * from "./ssoConfig";
|
||||||
export * from "./trustedIp";
|
export * from "./trustedIp";
|
||||||
export * from "./auditLog";
|
export * from "./auditLog";
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user