Merge remote-tracking branch 'origin' into groups-phase-2b

This commit is contained in:
Tuan Dang
2024-04-22 10:37:53 -07:00
53 changed files with 1112 additions and 450 deletions
@@ -5,6 +5,7 @@ on:
types: [opened, synchronize] types: [opened, synchronize]
paths: paths:
- "backend/src/server/routes/**" - "backend/src/server/routes/**"
- "backend/src/ee/routes/**"
jobs: jobs:
check-be-api-changes: check-be-api-changes:
+262 -182
View File
@@ -47,10 +47,11 @@
"libsodium-wrappers": "^0.7.13", "libsodium-wrappers": "^0.7.13",
"lodash.isequal": "^4.5.0", "lodash.isequal": "^4.5.0",
"ms": "^2.1.3", "ms": "^2.1.3",
"mysql2": "^3.9.1", "mysql2": "^3.9.4",
"nanoid": "^5.0.4", "nanoid": "^5.0.4",
"nodemailer": "^6.9.9", "nodemailer": "^6.9.9",
"ora": "^7.0.1", "ora": "^7.0.1",
"oracledb": "^6.4.0",
"passport-github": "^1.1.0", "passport-github": "^1.1.0",
"passport-gitlab2": "^5.0.0", "passport-gitlab2": "^5.0.0",
"passport-google-oauth20": "^2.0.0", "passport-google-oauth20": "^2.0.0",
@@ -1708,6 +1709,22 @@
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/@esbuild/aix-ppc64": {
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz",
"integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm": { "node_modules/@esbuild/android-arm": {
"version": "0.18.20", "version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz",
@@ -3162,9 +3179,9 @@
} }
}, },
"node_modules/@rollup/rollup-android-arm-eabi": { "node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.8.0", "version": "4.14.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.8.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.3.tgz",
"integrity": "sha512-zdTObFRoNENrdPpnTNnhOljYIcOX7aI7+7wyrSpPFFIOf/nRdedE6IYsjaBE7tjukphh1tMTojgJ7p3lKY8x6Q==", "integrity": "sha512-X9alQ3XM6I9IlSlmC8ddAvMSyG1WuHk5oUnXGw+yUBs3BFoTizmG1La/Gr8fVJvDWAq+zlYTZ9DBgrlKRVY06g==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -3175,9 +3192,9 @@
] ]
}, },
"node_modules/@rollup/rollup-android-arm64": { "node_modules/@rollup/rollup-android-arm64": {
"version": "4.8.0", "version": "4.14.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.8.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.3.tgz",
"integrity": "sha512-aiItwP48BiGpMFS9Znjo/xCNQVwTQVcRKkFKsO81m8exrGjHkCBDvm9PHay2kpa8RPnZzzKcD1iQ9KaLY4fPQQ==", "integrity": "sha512-eQK5JIi+POhFpzk+LnjKIy4Ks+pwJ+NXmPxOCSvOKSNRPONzKuUvWE+P9JxGZVxrtzm6BAYMaL50FFuPe0oWMQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -3188,9 +3205,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-arm64": { "node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.8.0", "version": "4.14.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.8.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.3.tgz",
"integrity": "sha512-zhNIS+L4ZYkYQUjIQUR6Zl0RXhbbA0huvNIWjmPc2SL0cB1h5Djkcy+RZ3/Bwszfb6vgwUvcVJYD6e6Zkpsi8g==", "integrity": "sha512-Od4vE6f6CTT53yM1jgcLqNfItTsLt5zE46fdPaEmeFHvPs5SjZYlLpHrSiHEKR1+HdRfxuzXHjDOIxQyC3ptBA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -3201,9 +3218,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-x64": { "node_modules/@rollup/rollup-darwin-x64": {
"version": "4.8.0", "version": "4.14.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.8.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.3.tgz",
"integrity": "sha512-A/FAHFRNQYrELrb/JHncRWzTTXB2ticiRFztP4ggIUAfa9Up1qfW8aG2w/mN9jNiZ+HB0t0u0jpJgFXG6BfRTA==", "integrity": "sha512-0IMAO21axJeNIrvS9lSe/PGthc8ZUS+zC53O0VhF5gMxfmcKAP4ESkKOCwEi6u2asUrt4mQv2rjY8QseIEb1aw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -3214,9 +3231,22 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-gnueabihf": { "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.8.0", "version": "4.14.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.8.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.3.tgz",
"integrity": "sha512-JsidBnh3p2IJJA4/2xOF2puAYqbaczB3elZDT0qHxn362EIoIkq7hrR43Xa8RisgI6/WPfvb2umbGsuvf7E37A==", "integrity": "sha512-ge2DC7tHRHa3caVEoSbPRJpq7azhG+xYsd6u2MEnJ6XzPSzQsTKyXvh6iWjXRf7Rt9ykIUWHtl0Uz3T6yXPpKw==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.14.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.14.3.tgz",
"integrity": "sha512-ljcuiDI4V3ySuc7eSk4lQ9wU8J8r8KrOUvB2U+TtK0TiW6OFDmJ+DdIjjwZHIw9CNxzbmXY39wwpzYuFDwNXuw==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -3227,9 +3257,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-gnu": { "node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.8.0", "version": "4.14.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.8.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.3.tgz",
"integrity": "sha512-hBNCnqw3EVCkaPB0Oqd24bv8SklETptQWcJz06kb9OtiShn9jK1VuTgi7o4zPSt6rNGWQOTDEAccbk0OqJmS+g==", "integrity": "sha512-Eci2us9VTHm1eSyn5/eEpaC7eP/mp5n46gTRB3Aar3BgSvDQGJZuicyq6TsH4HngNBgVqC5sDYxOzTExSU+NjA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -3240,9 +3270,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-musl": { "node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.8.0", "version": "4.14.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.8.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.3.tgz",
"integrity": "sha512-Fw9ChYfJPdltvi9ALJ9wzdCdxGw4wtq4t1qY028b2O7GwB5qLNSGtqMsAel1lfWTZvf4b6/+4HKp0GlSYg0ahA==", "integrity": "sha512-UrBoMLCq4E92/LCqlh+blpqMz5h1tJttPIniwUgOFJyjWI1qrtrDhhpHPuFxULlUmjFHfloWdixtDhSxJt5iKw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -3252,10 +3282,23 @@
"linux" "linux"
] ]
}, },
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.14.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.3.tgz",
"integrity": "sha512-5aRjvsS8q1nWN8AoRfrq5+9IflC3P1leMoy4r2WjXyFqf3qcqsxRCfxtZIV58tCxd+Yv7WELPcO9mY9aeQyAmw==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": { "node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.8.0", "version": "4.14.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.8.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.3.tgz",
"integrity": "sha512-BH5xIh7tOzS9yBi8dFrCTG8Z6iNIGWGltd3IpTSKp6+pNWWO6qy8eKoRxOtwFbMrid5NZaidLYN6rHh9aB8bEw==", "integrity": "sha512-sk/Qh1j2/RJSX7FhEpJn8n0ndxy/uf0kI/9Zc4b1ELhqULVdTfN6HL31CDaTChiBAOgLcsJ1sgVZjWv8XNEsAQ==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@@ -3265,10 +3308,23 @@
"linux" "linux"
] ]
}, },
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.14.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.3.tgz",
"integrity": "sha512-jOO/PEaDitOmY9TgkxF/TQIjXySQe5KVYB57H/8LRP/ux0ZoO8cSHCX17asMSv3ruwslXW/TLBcxyaUzGRHcqg==",
"cpu": [
"s390x"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": { "node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.8.0", "version": "4.14.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.8.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.3.tgz",
"integrity": "sha512-PmvAj8k6EuWiyLbkNpd6BLv5XeYFpqWuRvRNRl80xVfpGXK/z6KYXmAgbI4ogz7uFiJxCnYcqyvZVD0dgFog7Q==", "integrity": "sha512-8ybV4Xjy59xLMyWo3GCfEGqtKV5M5gCSrZlxkPGvEPCGDLNla7v48S662HSGwRd6/2cSneMQWiv+QzcttLrrOA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -3279,9 +3335,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-musl": { "node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.8.0", "version": "4.14.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.8.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.3.tgz",
"integrity": "sha512-mdxnlW2QUzXwY+95TuxZ+CurrhgrPAMveDWI97EQlA9bfhR8tw3Pt7SUlc/eSlCNxlWktpmT//EAA8UfCHOyXg==", "integrity": "sha512-s+xf1I46trOY10OqAtZ5Rm6lzHre/UiLA1J2uOhCFXWkbZrJRkYBPO6FhvGfHmdtQ3Bx793MNa7LvoWFAm93bg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -3292,9 +3348,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-arm64-msvc": { "node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.8.0", "version": "4.14.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.8.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.3.tgz",
"integrity": "sha512-ge7saUz38aesM4MA7Cad8CHo0Fyd1+qTaqoIo+Jtk+ipBi4ATSrHWov9/S4u5pbEQmLjgUjB7BJt+MiKG2kzmA==", "integrity": "sha512-+4h2WrGOYsOumDQ5S2sYNyhVfrue+9tc9XcLWLh+Kw3UOxAvrfOrSMFon60KspcDdytkNDh7K2Vs6eMaYImAZg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -3305,9 +3361,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-ia32-msvc": { "node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.8.0", "version": "4.14.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.8.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.3.tgz",
"integrity": "sha512-p9E3PZlzurhlsN5h9g7zIP1DnqKXJe8ZUkFwAazqSvHuWfihlIISPxG9hCHCoA+dOOspL/c7ty1eeEVFTE0UTw==", "integrity": "sha512-T1l7y/bCeL/kUwh9OD4PQT4aM7Bq43vX05htPJJ46RTI4r5KNt6qJRzAfNfM+OYMNEVBWQzR2Gyk+FXLZfogGw==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@@ -3318,9 +3374,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-x64-msvc": { "node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.8.0", "version": "4.14.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.8.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.3.tgz",
"integrity": "sha512-kb4/auKXkYKqlUYTE8s40FcJIj5soOyRLHKd4ugR0dCq0G2EfcF54eYcfQiGkHzjidZ40daB4ulsFdtqNKZtBg==", "integrity": "sha512-/BypzV0H1y1HzgYpxqRaXGBRqfodgoBBCcsrujT6QRcakDQdfU+Lq9PENPh5jB4I44YWq+0C2eHsHya+nZY1sA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -5916,12 +5972,12 @@
} }
}, },
"node_modules/body-parser": { "node_modules/body-parser": {
"version": "1.20.1", "version": "1.20.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
"integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
"dependencies": { "dependencies": {
"bytes": "3.1.2", "bytes": "3.1.2",
"content-type": "~1.0.4", "content-type": "~1.0.5",
"debug": "2.6.9", "debug": "2.6.9",
"depd": "2.0.0", "depd": "2.0.0",
"destroy": "1.2.0", "destroy": "1.2.0",
@@ -5929,7 +5985,7 @@
"iconv-lite": "0.4.24", "iconv-lite": "0.4.24",
"on-finished": "2.4.1", "on-finished": "2.4.1",
"qs": "6.11.0", "qs": "6.11.0",
"raw-body": "2.5.1", "raw-body": "2.5.2",
"type-is": "~1.6.18", "type-is": "~1.6.18",
"unpipe": "1.0.0" "unpipe": "1.0.0"
}, },
@@ -7379,16 +7435,16 @@
} }
}, },
"node_modules/express": { "node_modules/express": {
"version": "4.18.2", "version": "4.19.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
"integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
"dependencies": { "dependencies": {
"accepts": "~1.3.8", "accepts": "~1.3.8",
"array-flatten": "1.1.1", "array-flatten": "1.1.1",
"body-parser": "1.20.1", "body-parser": "1.20.2",
"content-disposition": "0.5.4", "content-disposition": "0.5.4",
"content-type": "~1.0.4", "content-type": "~1.0.4",
"cookie": "0.5.0", "cookie": "0.6.0",
"cookie-signature": "1.0.6", "cookie-signature": "1.0.6",
"debug": "2.6.9", "debug": "2.6.9",
"depd": "2.0.0", "depd": "2.0.0",
@@ -7419,6 +7475,14 @@
"node": ">= 0.10.0" "node": ">= 0.10.0"
} }
}, },
"node_modules/express/node_modules/cookie": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/express/node_modules/cookie-signature": { "node_modules/express/node_modules/cookie-signature": {
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
@@ -7749,9 +7813,9 @@
"dev": true "dev": true
}, },
"node_modules/follow-redirects": { "node_modules/follow-redirects": {
"version": "1.15.4", "version": "1.15.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
"funding": [ "funding": [
{ {
"type": "individual", "type": "individual",
@@ -9759,9 +9823,9 @@
} }
}, },
"node_modules/mysql2": { "node_modules/mysql2": {
"version": "3.9.1", "version": "3.9.4",
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.9.1.tgz", "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.9.4.tgz",
"integrity": "sha512-3njoWAAhGBYy0tWBabqUQcLtczZUxrmmtc2vszQUekg3kTJyZ5/IeLC3Fo04u6y6Iy5Sba7pIIa2P/gs8D3ZeQ==", "integrity": "sha512-OEESQuwxMza803knC1YSt7NMuc1BrK9j7gZhCSs2WAyxr1vfiI7QLaLOKTh5c9SWGz98qVyQUbK8/WckevNQhg==",
"dependencies": { "dependencies": {
"denque": "^2.1.0", "denque": "^2.1.0",
"generate-function": "^2.3.1", "generate-function": "^2.3.1",
@@ -10231,6 +10295,15 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/oracledb": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/oracledb/-/oracledb-6.4.0.tgz",
"integrity": "sha512-TJI08qzQlf/l7T49VojP9BoQpjEr14NXZmpSzzcLrbNs7qSl0QA/Mc9gGiEdkg5WmwH0wqUjtMC7jlf1WamlYA==",
"hasInstallScript": true,
"engines": {
"node": ">=14.6"
}
},
"node_modules/p-limit": { "node_modules/p-limit": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@@ -10818,9 +10891,9 @@
} }
}, },
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.4.32", "version": "8.4.38",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
"integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@@ -10839,7 +10912,7 @@
"dependencies": { "dependencies": {
"nanoid": "^3.3.7", "nanoid": "^3.3.7",
"picocolors": "^1.0.0", "picocolors": "^1.0.0",
"source-map-js": "^1.0.2" "source-map-js": "^1.2.0"
}, },
"engines": { "engines": {
"node": "^10 || ^12 || >=14" "node": "^10 || ^12 || >=14"
@@ -11234,9 +11307,9 @@
} }
}, },
"node_modules/raw-body": { "node_modules/raw-body": {
"version": "2.5.1", "version": "2.5.2",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
"dependencies": { "dependencies": {
"bytes": "3.1.2", "bytes": "3.1.2",
"http-errors": "2.0.0", "http-errors": "2.0.0",
@@ -11511,10 +11584,13 @@
} }
}, },
"node_modules/rollup": { "node_modules/rollup": {
"version": "4.8.0", "version": "4.14.3",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.8.0.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.3.tgz",
"integrity": "sha512-NpsklK2fach5CdI+PScmlE5R4Ao/FSWtF7LkoIrHDxPACY/xshNasPsbpG0VVHxUTbf74tJbVT4PrP8JsJ6ZDA==", "integrity": "sha512-ag5tTQKYsj1bhrFC9+OEWqb5O6VYgtQDO9hPDBMmIbePwhfSr+ExlcU741t8Dhw5DkPCQf6noz0jb36D6W9/hw==",
"dev": true, "dev": true,
"dependencies": {
"@types/estree": "1.0.5"
},
"bin": { "bin": {
"rollup": "dist/bin/rollup" "rollup": "dist/bin/rollup"
}, },
@@ -11523,19 +11599,22 @@
"npm": ">=8.0.0" "npm": ">=8.0.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.8.0", "@rollup/rollup-android-arm-eabi": "4.14.3",
"@rollup/rollup-android-arm64": "4.8.0", "@rollup/rollup-android-arm64": "4.14.3",
"@rollup/rollup-darwin-arm64": "4.8.0", "@rollup/rollup-darwin-arm64": "4.14.3",
"@rollup/rollup-darwin-x64": "4.8.0", "@rollup/rollup-darwin-x64": "4.14.3",
"@rollup/rollup-linux-arm-gnueabihf": "4.8.0", "@rollup/rollup-linux-arm-gnueabihf": "4.14.3",
"@rollup/rollup-linux-arm64-gnu": "4.8.0", "@rollup/rollup-linux-arm-musleabihf": "4.14.3",
"@rollup/rollup-linux-arm64-musl": "4.8.0", "@rollup/rollup-linux-arm64-gnu": "4.14.3",
"@rollup/rollup-linux-riscv64-gnu": "4.8.0", "@rollup/rollup-linux-arm64-musl": "4.14.3",
"@rollup/rollup-linux-x64-gnu": "4.8.0", "@rollup/rollup-linux-powerpc64le-gnu": "4.14.3",
"@rollup/rollup-linux-x64-musl": "4.8.0", "@rollup/rollup-linux-riscv64-gnu": "4.14.3",
"@rollup/rollup-win32-arm64-msvc": "4.8.0", "@rollup/rollup-linux-s390x-gnu": "4.14.3",
"@rollup/rollup-win32-ia32-msvc": "4.8.0", "@rollup/rollup-linux-x64-gnu": "4.14.3",
"@rollup/rollup-win32-x64-msvc": "4.8.0", "@rollup/rollup-linux-x64-musl": "4.14.3",
"@rollup/rollup-win32-arm64-msvc": "4.14.3",
"@rollup/rollup-win32-ia32-msvc": "4.14.3",
"@rollup/rollup-win32-x64-msvc": "4.14.3",
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },
@@ -11887,9 +11966,9 @@
} }
}, },
"node_modules/source-map-js": { "node_modules/source-map-js": {
"version": "1.0.2", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
@@ -12249,9 +12328,9 @@
} }
}, },
"node_modules/tar": { "node_modules/tar": {
"version": "6.2.0", "version": "6.2.1",
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
"integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
"dependencies": { "dependencies": {
"chownr": "^2.0.0", "chownr": "^2.0.0",
"fs-minipass": "^2.0.0", "fs-minipass": "^2.0.0",
@@ -13447,14 +13526,14 @@
} }
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "5.0.12", "version": "5.2.9",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.0.12.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.9.tgz",
"integrity": "sha512-4hsnEkG3q0N4Tzf1+t6NdN9dg/L3BM+q8SWgbSPnJvrgH2kgdyzfVJwbR1ic69/4uMJJ/3dqDZZE5/WwqW8U1w==", "integrity": "sha512-uOQWfuZBlc6Y3W/DTuQ1Sr+oIXWvqljLvS881SVmAj00d5RdgShLcuXWxseWPd4HXwiYBFW/vXHfKFeqj9uQnw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"esbuild": "^0.19.3", "esbuild": "^0.20.1",
"postcss": "^8.4.32", "postcss": "^8.4.38",
"rollup": "^4.2.0" "rollup": "^4.13.0"
}, },
"bin": { "bin": {
"vite": "bin/vite.js" "vite": "bin/vite.js"
@@ -13589,9 +13668,9 @@
"dev": true "dev": true
}, },
"node_modules/vite/node_modules/@esbuild/android-arm": { "node_modules/vite/node_modules/@esbuild/android-arm": {
"version": "0.19.9", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz",
"integrity": "sha512-jkYjjq7SdsWuNI6b5quymW0oC83NN5FdRPuCbs9HZ02mfVdAP8B8eeqLSYU3gb6OJEaY5CQabtTFbqBf26H3GA==", "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -13605,9 +13684,9 @@
} }
}, },
"node_modules/vite/node_modules/@esbuild/android-arm64": { "node_modules/vite/node_modules/@esbuild/android-arm64": {
"version": "0.19.9", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz",
"integrity": "sha512-q4cR+6ZD0938R19MyEW3jEsMzbb/1rulLXiNAJQADD/XYp7pT+rOS5JGxvpRW8dFDEfjW4wLgC/3FXIw4zYglQ==", "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -13621,9 +13700,9 @@
} }
}, },
"node_modules/vite/node_modules/@esbuild/android-x64": { "node_modules/vite/node_modules/@esbuild/android-x64": {
"version": "0.19.9", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz",
"integrity": "sha512-KOqoPntWAH6ZxDwx1D6mRntIgZh9KodzgNOy5Ebt9ghzffOk9X2c1sPwtM9P+0eXbefnDhqYfkh5PLP5ULtWFA==", "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -13637,9 +13716,9 @@
} }
}, },
"node_modules/vite/node_modules/@esbuild/darwin-arm64": { "node_modules/vite/node_modules/@esbuild/darwin-arm64": {
"version": "0.19.9", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz",
"integrity": "sha512-KBJ9S0AFyLVx2E5D8W0vExqRW01WqRtczUZ8NRu+Pi+87opZn5tL4Y0xT0mA4FtHctd0ZgwNoN639fUUGlNIWw==", "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -13653,9 +13732,9 @@
} }
}, },
"node_modules/vite/node_modules/@esbuild/darwin-x64": { "node_modules/vite/node_modules/@esbuild/darwin-x64": {
"version": "0.19.9", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz",
"integrity": "sha512-vE0VotmNTQaTdX0Q9dOHmMTao6ObjyPm58CHZr1UK7qpNleQyxlFlNCaHsHx6Uqv86VgPmR4o2wdNq3dP1qyDQ==", "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -13669,9 +13748,9 @@
} }
}, },
"node_modules/vite/node_modules/@esbuild/freebsd-arm64": { "node_modules/vite/node_modules/@esbuild/freebsd-arm64": {
"version": "0.19.9", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz",
"integrity": "sha512-uFQyd/o1IjiEk3rUHSwUKkqZwqdvuD8GevWF065eqgYfexcVkxh+IJgwTaGZVu59XczZGcN/YMh9uF1fWD8j1g==", "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -13685,9 +13764,9 @@
} }
}, },
"node_modules/vite/node_modules/@esbuild/freebsd-x64": { "node_modules/vite/node_modules/@esbuild/freebsd-x64": {
"version": "0.19.9", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz",
"integrity": "sha512-WMLgWAtkdTbTu1AWacY7uoj/YtHthgqrqhf1OaEWnZb7PQgpt8eaA/F3LkV0E6K/Lc0cUr/uaVP/49iE4M4asA==", "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -13701,9 +13780,9 @@
} }
}, },
"node_modules/vite/node_modules/@esbuild/linux-arm": { "node_modules/vite/node_modules/@esbuild/linux-arm": {
"version": "0.19.9", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz",
"integrity": "sha512-C/ChPohUYoyUaqn1h17m/6yt6OB14hbXvT8EgM1ZWaiiTYz7nWZR0SYmMnB5BzQA4GXl3BgBO1l8MYqL/He3qw==", "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -13717,9 +13796,9 @@
} }
}, },
"node_modules/vite/node_modules/@esbuild/linux-arm64": { "node_modules/vite/node_modules/@esbuild/linux-arm64": {
"version": "0.19.9", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz",
"integrity": "sha512-PiPblfe1BjK7WDAKR1Cr9O7VVPqVNpwFcPWgfn4xu0eMemzRp442hXyzF/fSwgrufI66FpHOEJk0yYdPInsmyQ==", "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -13733,9 +13812,9 @@
} }
}, },
"node_modules/vite/node_modules/@esbuild/linux-ia32": { "node_modules/vite/node_modules/@esbuild/linux-ia32": {
"version": "0.19.9", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz",
"integrity": "sha512-f37i/0zE0MjDxijkPSQw1CO/7C27Eojqb+r3BbHVxMLkj8GCa78TrBZzvPyA/FNLUMzP3eyHCVkAopkKVja+6Q==", "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@@ -13749,9 +13828,9 @@
} }
}, },
"node_modules/vite/node_modules/@esbuild/linux-loong64": { "node_modules/vite/node_modules/@esbuild/linux-loong64": {
"version": "0.19.9", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz",
"integrity": "sha512-t6mN147pUIf3t6wUt3FeumoOTPfmv9Cc6DQlsVBpB7eCpLOqQDyWBP1ymXn1lDw4fNUSb/gBcKAmvTP49oIkaA==", "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==",
"cpu": [ "cpu": [
"loong64" "loong64"
], ],
@@ -13765,9 +13844,9 @@
} }
}, },
"node_modules/vite/node_modules/@esbuild/linux-mips64el": { "node_modules/vite/node_modules/@esbuild/linux-mips64el": {
"version": "0.19.9", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz",
"integrity": "sha512-jg9fujJTNTQBuDXdmAg1eeJUL4Jds7BklOTkkH80ZgQIoCTdQrDaHYgbFZyeTq8zbY+axgptncko3v9p5hLZtw==", "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==",
"cpu": [ "cpu": [
"mips64el" "mips64el"
], ],
@@ -13781,9 +13860,9 @@
} }
}, },
"node_modules/vite/node_modules/@esbuild/linux-ppc64": { "node_modules/vite/node_modules/@esbuild/linux-ppc64": {
"version": "0.19.9", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz",
"integrity": "sha512-tkV0xUX0pUUgY4ha7z5BbDS85uI7ABw3V1d0RNTii7E9lbmV8Z37Pup2tsLV46SQWzjOeyDi1Q7Wx2+QM8WaCQ==", "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@@ -13797,9 +13876,9 @@
} }
}, },
"node_modules/vite/node_modules/@esbuild/linux-riscv64": { "node_modules/vite/node_modules/@esbuild/linux-riscv64": {
"version": "0.19.9", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz",
"integrity": "sha512-DfLp8dj91cufgPZDXr9p3FoR++m3ZJ6uIXsXrIvJdOjXVREtXuQCjfMfvmc3LScAVmLjcfloyVtpn43D56JFHg==", "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@@ -13813,9 +13892,9 @@
} }
}, },
"node_modules/vite/node_modules/@esbuild/linux-s390x": { "node_modules/vite/node_modules/@esbuild/linux-s390x": {
"version": "0.19.9", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz",
"integrity": "sha512-zHbglfEdC88KMgCWpOl/zc6dDYJvWGLiUtmPRsr1OgCViu3z5GncvNVdf+6/56O2Ca8jUU+t1BW261V6kp8qdw==", "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@@ -13829,9 +13908,9 @@
} }
}, },
"node_modules/vite/node_modules/@esbuild/linux-x64": { "node_modules/vite/node_modules/@esbuild/linux-x64": {
"version": "0.19.9", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz",
"integrity": "sha512-JUjpystGFFmNrEHQnIVG8hKwvA2DN5o7RqiO1CVX8EN/F/gkCjkUMgVn6hzScpwnJtl2mPR6I9XV1oW8k9O+0A==", "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -13845,9 +13924,9 @@
} }
}, },
"node_modules/vite/node_modules/@esbuild/netbsd-x64": { "node_modules/vite/node_modules/@esbuild/netbsd-x64": {
"version": "0.19.9", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz",
"integrity": "sha512-GThgZPAwOBOsheA2RUlW5UeroRfESwMq/guy8uEe3wJlAOjpOXuSevLRd70NZ37ZrpO6RHGHgEHvPg1h3S1Jug==", "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -13861,9 +13940,9 @@
} }
}, },
"node_modules/vite/node_modules/@esbuild/openbsd-x64": { "node_modules/vite/node_modules/@esbuild/openbsd-x64": {
"version": "0.19.9", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz",
"integrity": "sha512-Ki6PlzppaFVbLnD8PtlVQfsYw4S9n3eQl87cqgeIw+O3sRr9IghpfSKY62mggdt1yCSZ8QWvTZ9jo9fjDSg9uw==", "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -13877,9 +13956,9 @@
} }
}, },
"node_modules/vite/node_modules/@esbuild/sunos-x64": { "node_modules/vite/node_modules/@esbuild/sunos-x64": {
"version": "0.19.9", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz",
"integrity": "sha512-MLHj7k9hWh4y1ddkBpvRj2b9NCBhfgBt3VpWbHQnXRedVun/hC7sIyTGDGTfsGuXo4ebik2+3ShjcPbhtFwWDw==", "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -13893,9 +13972,9 @@
} }
}, },
"node_modules/vite/node_modules/@esbuild/win32-arm64": { "node_modules/vite/node_modules/@esbuild/win32-arm64": {
"version": "0.19.9", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz",
"integrity": "sha512-GQoa6OrQ8G08guMFgeXPH7yE/8Dt0IfOGWJSfSH4uafwdC7rWwrfE6P9N8AtPGIjUzdo2+7bN8Xo3qC578olhg==", "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -13909,9 +13988,9 @@
} }
}, },
"node_modules/vite/node_modules/@esbuild/win32-ia32": { "node_modules/vite/node_modules/@esbuild/win32-ia32": {
"version": "0.19.9", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz",
"integrity": "sha512-UOozV7Ntykvr5tSOlGCrqU3NBr3d8JqPes0QWN2WOXfvkWVGRajC+Ym0/Wj88fUgecUCLDdJPDF0Nna2UK3Qtg==", "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@@ -13925,9 +14004,9 @@
} }
}, },
"node_modules/vite/node_modules/@esbuild/win32-x64": { "node_modules/vite/node_modules/@esbuild/win32-x64": {
"version": "0.19.9", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz",
"integrity": "sha512-oxoQgglOP7RH6iasDrhY+R/3cHrfwIDvRlT4CGChflq6twk8iENeVvMJjmvBb94Ik1Z+93iGO27err7w6l54GQ==", "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -13941,9 +14020,9 @@
} }
}, },
"node_modules/vite/node_modules/esbuild": { "node_modules/vite/node_modules/esbuild": {
"version": "0.19.9", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.9.tgz", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz",
"integrity": "sha512-U9CHtKSy+EpPsEBa+/A2gMs/h3ylBC0H0KSqIg7tpztHerLi6nrrcoUJAkNCEPumx8yJ+Byic4BVwHgRbN0TBg==", "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==",
"dev": true, "dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"bin": { "bin": {
@@ -13953,28 +14032,29 @@
"node": ">=12" "node": ">=12"
}, },
"optionalDependencies": { "optionalDependencies": {
"@esbuild/android-arm": "0.19.9", "@esbuild/aix-ppc64": "0.20.2",
"@esbuild/android-arm64": "0.19.9", "@esbuild/android-arm": "0.20.2",
"@esbuild/android-x64": "0.19.9", "@esbuild/android-arm64": "0.20.2",
"@esbuild/darwin-arm64": "0.19.9", "@esbuild/android-x64": "0.20.2",
"@esbuild/darwin-x64": "0.19.9", "@esbuild/darwin-arm64": "0.20.2",
"@esbuild/freebsd-arm64": "0.19.9", "@esbuild/darwin-x64": "0.20.2",
"@esbuild/freebsd-x64": "0.19.9", "@esbuild/freebsd-arm64": "0.20.2",
"@esbuild/linux-arm": "0.19.9", "@esbuild/freebsd-x64": "0.20.2",
"@esbuild/linux-arm64": "0.19.9", "@esbuild/linux-arm": "0.20.2",
"@esbuild/linux-ia32": "0.19.9", "@esbuild/linux-arm64": "0.20.2",
"@esbuild/linux-loong64": "0.19.9", "@esbuild/linux-ia32": "0.20.2",
"@esbuild/linux-mips64el": "0.19.9", "@esbuild/linux-loong64": "0.20.2",
"@esbuild/linux-ppc64": "0.19.9", "@esbuild/linux-mips64el": "0.20.2",
"@esbuild/linux-riscv64": "0.19.9", "@esbuild/linux-ppc64": "0.20.2",
"@esbuild/linux-s390x": "0.19.9", "@esbuild/linux-riscv64": "0.20.2",
"@esbuild/linux-x64": "0.19.9", "@esbuild/linux-s390x": "0.20.2",
"@esbuild/netbsd-x64": "0.19.9", "@esbuild/linux-x64": "0.20.2",
"@esbuild/openbsd-x64": "0.19.9", "@esbuild/netbsd-x64": "0.20.2",
"@esbuild/sunos-x64": "0.19.9", "@esbuild/openbsd-x64": "0.20.2",
"@esbuild/win32-arm64": "0.19.9", "@esbuild/sunos-x64": "0.20.2",
"@esbuild/win32-ia32": "0.19.9", "@esbuild/win32-arm64": "0.20.2",
"@esbuild/win32-x64": "0.19.9" "@esbuild/win32-ia32": "0.20.2",
"@esbuild/win32-x64": "0.20.2"
} }
}, },
"node_modules/vitest": { "node_modules/vitest": {
+1
View File
@@ -112,6 +112,7 @@
"nanoid": "^5.0.4", "nanoid": "^5.0.4",
"nodemailer": "^6.9.9", "nodemailer": "^6.9.9",
"ora": "^7.0.1", "ora": "^7.0.1",
"oracledb": "^6.4.0",
"passport-github": "^1.1.0", "passport-github": "^1.1.0",
"passport-gitlab2": "^5.0.0", "passport-gitlab2": "^5.0.0",
"passport-google-oauth20": "^2.0.0", "passport-google-oauth20": "^2.0.0",
+1 -3
View File
@@ -19,7 +19,6 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
description: "Return project secret snapshots ids", description: "Return project secret snapshots ids",
security: [ security: [
{ {
apiKeyAuth: [],
bearerAuth: [] bearerAuth: []
} }
], ],
@@ -97,8 +96,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
description: "Return audit logs", description: "Return audit logs",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
params: z.object({ params: z.object({
@@ -69,7 +69,6 @@ export const registerSnapshotRouter = async (server: FastifyZodProvider) => {
description: "Roll back project secrets to those captured in a secret snapshot version.", description: "Roll back project secrets to those captured in a secret snapshot version.",
security: [ security: [
{ {
apiKeyAuth: [],
bearerAuth: [] bearerAuth: []
} }
], ],
@@ -2,7 +2,8 @@ import { z } from "zod";
export enum SqlProviders { export enum SqlProviders {
Postgres = "postgres", Postgres = "postgres",
MySQL = "mysql2" MySQL = "mysql2",
Oracle = "oracledb"
} }
export const DynamicSecretSqlDBSchema = z.object({ export const DynamicSecretSqlDBSchema = z.object({
@@ -8,15 +8,25 @@ import { BadRequestError } from "@app/lib/errors";
import { getDbConnectionHost } from "@app/lib/knex"; import { getDbConnectionHost } from "@app/lib/knex";
import { alphaNumericNanoId } from "@app/lib/nanoid"; import { alphaNumericNanoId } from "@app/lib/nanoid";
import { DynamicSecretSqlDBSchema, TDynamicProviderFns } from "./models"; import { DynamicSecretSqlDBSchema, SqlProviders, TDynamicProviderFns } from "./models";
const EXTERNAL_REQUEST_TIMEOUT = 10 * 1000; const EXTERNAL_REQUEST_TIMEOUT = 10 * 1000;
const generatePassword = (size?: number) => { const generatePassword = (provider: SqlProviders) => {
// oracle has limit of 48 password length
const size = provider === SqlProviders.Oracle ? 30 : 48;
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~!*$#"; const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~!*$#";
return customAlphabet(charset, 48)(size); return customAlphabet(charset, 48)(size);
}; };
const generateUsername = (provider: SqlProviders) => {
// For oracle, the client assumes everything is upper case when not using quotes around the password
if (provider === SqlProviders.Oracle) return alphaNumericNanoId(32).toUpperCase();
return alphaNumericNanoId(32);
};
export const SqlDatabaseProvider = (): TDynamicProviderFns => { export const SqlDatabaseProvider = (): TDynamicProviderFns => {
const validateProviderInputs = async (inputs: unknown) => { const validateProviderInputs = async (inputs: unknown) => {
const appCfg = getConfig(); const appCfg = getConfig();
@@ -59,10 +69,10 @@ export const SqlDatabaseProvider = (): TDynamicProviderFns => {
const validateConnection = async (inputs: unknown) => { const validateConnection = async (inputs: unknown) => {
const providerInputs = await validateProviderInputs(inputs); const providerInputs = await validateProviderInputs(inputs);
const db = await getClient(providerInputs); const db = await getClient(providerInputs);
const isConnected = await db // oracle needs from keyword
.raw("SELECT NOW()") const testStatement = providerInputs.client === SqlProviders.Oracle ? "SELECT 1 FROM DUAL" : "SELECT 1";
.then(() => true)
.catch(() => false); const isConnected = await db.raw(testStatement).then(() => true);
await db.destroy(); await db.destroy();
return isConnected; return isConnected;
}; };
@@ -71,8 +81,8 @@ export const SqlDatabaseProvider = (): TDynamicProviderFns => {
const providerInputs = await validateProviderInputs(inputs); const providerInputs = await validateProviderInputs(inputs);
const db = await getClient(providerInputs); const db = await getClient(providerInputs);
const username = alphaNumericNanoId(32); const username = generateUsername(providerInputs.client);
const password = generatePassword(); const password = generatePassword(providerInputs.client);
const { database } = providerInputs; const { database } = providerInputs;
const expiration = new Date(expireAt).toISOString(); const expiration = new Date(expireAt).toISOString();
@@ -1,4 +1,4 @@
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError, subject } from "@casl/ability";
import { TableName, TSecretTagJunctionInsert } from "@app/db/schemas"; import { TableName, TSecretTagJunctionInsert } from "@app/db/schemas";
import { BadRequestError, InternalServerError } from "@app/lib/errors"; import { BadRequestError, InternalServerError } from "@app/lib/errors";
@@ -23,6 +23,7 @@ import {
import { TSnapshotDALFactory } from "./snapshot-dal"; import { TSnapshotDALFactory } from "./snapshot-dal";
import { TSnapshotFolderDALFactory } from "./snapshot-folder-dal"; import { TSnapshotFolderDALFactory } from "./snapshot-folder-dal";
import { TSnapshotSecretDALFactory } from "./snapshot-secret-dal"; import { TSnapshotSecretDALFactory } from "./snapshot-secret-dal";
import { getFullFolderPath } from "./snapshot-service-fns";
type TSecretSnapshotServiceFactoryDep = { type TSecretSnapshotServiceFactoryDep = {
snapshotDAL: TSnapshotDALFactory; snapshotDAL: TSnapshotDALFactory;
@@ -33,7 +34,7 @@ type TSecretSnapshotServiceFactoryDep = {
secretDAL: Pick<TSecretDALFactory, "delete" | "insertMany">; secretDAL: Pick<TSecretDALFactory, "delete" | "insertMany">;
secretTagDAL: Pick<TSecretTagDALFactory, "saveTagsToSecret">; secretTagDAL: Pick<TSecretTagDALFactory, "saveTagsToSecret">;
secretVersionTagDAL: Pick<TSecretVersionTagDALFactory, "insertMany">; secretVersionTagDAL: Pick<TSecretVersionTagDALFactory, "insertMany">;
folderDAL: Pick<TSecretFolderDALFactory, "findById" | "findBySecretPath" | "delete" | "insertMany">; folderDAL: Pick<TSecretFolderDALFactory, "findById" | "findBySecretPath" | "delete" | "insertMany" | "find">;
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">; permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
licenseService: Pick<TLicenseServiceFactory, "isValidLicense">; licenseService: Pick<TLicenseServiceFactory, "isValidLicense">;
}; };
@@ -71,6 +72,12 @@ export const secretSnapshotServiceFactory = ({
); );
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
// We need to check if the user has access to the secrets in the folder. If we don't do this, a user could theoretically access snapshot secret values even if they don't have read access to the secrets in the folder.
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
);
const folder = await folderDAL.findBySecretPath(projectId, environment, path); const folder = await folderDAL.findBySecretPath(projectId, environment, path);
if (!folder) throw new BadRequestError({ message: "Folder not found" }); if (!folder) throw new BadRequestError({ message: "Folder not found" });
@@ -98,6 +105,12 @@ export const secretSnapshotServiceFactory = ({
); );
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
// We need to check if the user has access to the secrets in the folder. If we don't do this, a user could theoretically access snapshot secret values even if they don't have read access to the secrets in the folder.
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
);
const folder = await folderDAL.findBySecretPath(projectId, environment, path); const folder = await folderDAL.findBySecretPath(projectId, environment, path);
if (!folder) throw new BadRequestError({ message: "Folder not found" }); if (!folder) throw new BadRequestError({ message: "Folder not found" });
@@ -116,6 +129,19 @@ export const secretSnapshotServiceFactory = ({
actorOrgId actorOrgId
); );
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
const fullFolderPath = await getFullFolderPath({
folderDAL,
folderId: snapshot.folderId,
envId: snapshot.environment.id
});
// We need to check if the user has access to the secrets in the folder. If we don't do this, a user could theoretically access snapshot secret values even if they don't have read access to the secrets in the folder.
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment: snapshot.environment.slug, secretPath: fullFolderPath })
);
return snapshot; return snapshot;
}; };
@@ -101,6 +101,7 @@ export const snapshotDALFactory = (db: TDbClient) => {
key: "snapshotId", key: "snapshotId",
parentMapper: ({ parentMapper: ({
snapshotId: id, snapshotId: id,
folderId,
projectId, projectId,
envId, envId,
envSlug, envSlug,
@@ -109,6 +110,7 @@ export const snapshotDALFactory = (db: TDbClient) => {
snapshotUpdatedAt: updatedAt snapshotUpdatedAt: updatedAt
}) => ({ }) => ({
id, id,
folderId,
projectId, projectId,
createdAt, createdAt,
updatedAt, updatedAt,
@@ -0,0 +1,28 @@
import { TSecretFolderDALFactory } from "@app/services/secret-folder/secret-folder-dal";
type GetFullFolderPath = {
folderDAL: Pick<TSecretFolderDALFactory, "findById" | "find">; // Added findAllInEnv
folderId: string;
envId: string;
};
export const getFullFolderPath = async ({ folderDAL, folderId, envId }: GetFullFolderPath): Promise<string> => {
// Helper function to remove duplicate slashes
const removeDuplicateSlashes = (path: string) => path.replace(/\/{2,}/g, "/");
// Fetch all folders at once based on environment ID to avoid multiple queries
const folders = await folderDAL.find({ envId });
const folderMap = new Map(folders.map((folder) => [folder.id, folder]));
const buildPath = (currFolderId: string): string => {
const folder = folderMap.get(currFolderId);
if (!folder) return "";
const folderPathSegment = !folder.parentId && folder.name === "root" ? "/" : `/${folder.name}`;
if (folder.parentId) {
return removeDuplicateSlashes(`${buildPath(folder.parentId)}${folderPathSegment}`);
}
return removeDuplicateSlashes(folderPathSegment);
};
return buildPath(folderId);
};
+2 -1
View File
@@ -589,7 +589,8 @@ export const INTEGRATION = {
secretSuffix: "The suffix for the saved secret. Used by GCP", secretSuffix: "The suffix for the saved secret. Used by GCP",
initialSyncBehavoir: "Type of syncing behavoir with the integration", initialSyncBehavoir: "Type of syncing behavoir with the integration",
shouldAutoRedeploy: "Used by Render to trigger auto deploy", shouldAutoRedeploy: "Used by Render to trigger auto deploy",
secretGCPLabel: "The label for the GCP secrets" secretGCPLabel: "The label for the GCP secrets",
secretAWSTag: "The tag for the AWS secrets"
} }
}, },
UPDATE: { UPDATE: {
-6
View File
@@ -30,12 +30,6 @@ export const fastifySwagger = fp(async (fastify) => {
scheme: "bearer", scheme: "bearer",
bearerFormat: "JWT", bearerFormat: "JWT",
description: "An access token in Infisical" description: "An access token in Infisical"
},
apiKeyAuth: {
type: "apiKey",
in: "header",
name: "X-API-Key",
description: "An API Key in Infisical"
} }
} }
} }
@@ -56,7 +56,14 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => {
labelValue: z.string() labelValue: z.string()
}) })
.optional() .optional()
.describe(INTEGRATION.CREATE.metadata.secretGCPLabel) .describe(INTEGRATION.CREATE.metadata.secretGCPLabel),
secretAWSTag: z
.object({
key: z.string(),
value: z.string()
})
.optional()
.describe(INTEGRATION.CREATE.metadata.secretAWSTag)
}) })
.optional() .optional()
}), }),
@@ -18,8 +18,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
description: "Create environment", description: "Create environment",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
params: z.object({ params: z.object({
@@ -77,8 +76,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
description: "Update environment", description: "Update environment",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
params: z.object({ params: z.object({
@@ -144,8 +142,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
description: "Delete environment", description: "Delete environment",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
params: z.object({ params: z.object({
@@ -26,8 +26,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
description: "Return project user memberships", description: "Return project user memberships",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
params: z.object({ params: z.object({
@@ -139,8 +138,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
description: "Update project user membership", description: "Update project user membership",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
params: z.object({ params: z.object({
@@ -213,8 +211,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
description: "Delete project user membership", description: "Delete project user membership",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
params: z.object({ params: z.object({
@@ -138,6 +138,12 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
rateLimit: readLimit rateLimit: readLimit
}, },
schema: { schema: {
description: "Get project",
security: [
{
bearerAuth: []
}
],
params: z.object({ params: z.object({
workspaceId: z.string().trim().describe(PROJECTS.GET.workspaceId) workspaceId: z.string().trim().describe(PROJECTS.GET.workspaceId)
}), }),
@@ -170,6 +176,12 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
rateLimit: writeLimit rateLimit: writeLimit
}, },
schema: { schema: {
description: "Delete project",
security: [
{
bearerAuth: []
}
],
params: z.object({ params: z.object({
workspaceId: z.string().trim().describe(PROJECTS.DELETE.workspaceId) workspaceId: z.string().trim().describe(PROJECTS.DELETE.workspaceId)
}), }),
@@ -239,6 +251,12 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
rateLimit: writeLimit rateLimit: writeLimit
}, },
schema: { schema: {
description: "Update project",
security: [
{
bearerAuth: []
}
],
params: z.object({ params: z.object({
workspaceId: z.string().trim().describe(PROJECTS.UPDATE.workspaceId) workspaceId: z.string().trim().describe(PROJECTS.UPDATE.workspaceId)
}), }),
@@ -19,8 +19,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
description: "Create folders", description: "Create folders",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
body: z.object({ body: z.object({
@@ -76,8 +75,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
description: "Update folder", description: "Update folder",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
params: z.object({ params: z.object({
@@ -140,8 +138,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
description: "Delete a folder", description: "Delete a folder",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
params: z.object({ params: z.object({
@@ -200,8 +197,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
description: "Get folders", description: "Get folders",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
querystring: z.object({ querystring: z.object({
@@ -19,8 +19,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
description: "Create secret imports", description: "Create secret imports",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
body: z.object({ body: z.object({
@@ -84,8 +83,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
description: "Update secret imports", description: "Update secret imports",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
params: z.object({ params: z.object({
@@ -159,8 +157,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
description: "Delete secret imports", description: "Delete secret imports",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
params: z.object({ params: z.object({
@@ -223,8 +220,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
description: "Get secret imports", description: "Get secret imports",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
querystring: z.object({ querystring: z.object({
@@ -18,8 +18,7 @@ export const registerIdentityOrgRouter = async (server: FastifyZodProvider) => {
description: "Return organization identity memberships", description: "Return organization identity memberships",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
params: z.object({ params: z.object({
@@ -17,8 +17,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
description: "Return organization user memberships", description: "Return organization user memberships",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
params: z.object({ params: z.object({
@@ -65,8 +64,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
description: "Return projects in organization that user is part of", description: "Return projects in organization that user is part of",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
params: z.object({ params: z.object({
@@ -114,8 +112,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
description: "Update organization user memberships", description: "Update organization user memberships",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
params: z.object({ params: z.object({
@@ -157,8 +154,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
description: "Delete organization user memberships", description: "Delete organization user memberships",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
params: z.object({ params: z.object({
@@ -15,6 +15,12 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
rateLimit: writeLimit rateLimit: writeLimit
}, },
schema: { schema: {
description: "Invite members to project",
security: [
{
bearerAuth: []
}
],
params: z.object({ params: z.object({
projectId: z.string().describe(PROJECTS.INVITE_MEMBER.projectId) projectId: z.string().describe(PROJECTS.INVITE_MEMBER.projectId)
}), }),
@@ -64,10 +70,15 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
rateLimit: writeLimit rateLimit: writeLimit
}, },
schema: { schema: {
description: "Remove members from project",
security: [
{
bearerAuth: []
}
],
params: z.object({ params: z.object({
projectId: z.string().describe(PROJECTS.REMOVE_MEMBER.projectId) projectId: z.string().describe(PROJECTS.REMOVE_MEMBER.projectId)
}), }),
body: z.object({ body: z.object({
emails: z.string().email().array().default([]).describe(PROJECTS.REMOVE_MEMBER.emails), emails: z.string().email().array().default([]).describe(PROJECTS.REMOVE_MEMBER.emails),
usernames: z.string().array().default([]).describe(PROJECTS.REMOVE_MEMBER.usernames) usernames: z.string().array().default([]).describe(PROJECTS.REMOVE_MEMBER.usernames)
+12 -5
View File
@@ -36,11 +36,6 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
}, },
schema: { schema: {
description: "Return encrypted project key", description: "Return encrypted project key",
security: [
{
apiKeyAuth: []
}
],
params: z.object({ params: z.object({
workspaceId: z.string().trim().describe(PROJECTS.GET_KEY.workspaceId) workspaceId: z.string().trim().describe(PROJECTS.GET_KEY.workspaceId)
}), }),
@@ -149,6 +144,12 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
rateLimit: creationLimit rateLimit: creationLimit
}, },
schema: { schema: {
description: "Create a new project",
security: [
{
bearerAuth: []
}
],
body: z.object({ body: z.object({
projectName: z.string().trim().describe(PROJECTS.CREATE.projectName), projectName: z.string().trim().describe(PROJECTS.CREATE.projectName),
slug: z slug: z
@@ -200,6 +201,12 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
rateLimit: writeLimit rateLimit: writeLimit
}, },
schema: { schema: {
description: "Delete project",
security: [
{
bearerAuth: []
}
],
params: z.object({ params: z.object({
slug: slugSchema.describe("The slug of the project to delete.") slug: slugSchema.describe("The slug of the project to delete.")
}), }),
@@ -85,11 +85,6 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
}, },
schema: { schema: {
description: "Return organizations that current user is part of", description: "Return organizations that current user is part of",
security: [
{
apiKeyAuth: []
}
],
response: { response: {
200: z.object({ 200: z.object({
organizations: OrganizationsSchema.array() organizations: OrganizationsSchema.array()
@@ -217,11 +212,6 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
}, },
schema: { schema: {
description: "Retrieve the current user on the request", description: "Retrieve the current user on the request",
security: [
{
apiKeyAuth: []
}
],
response: { response: {
200: z.object({ 200: z.object({
user: UsersSchema.merge(UserEncryptionKeysSchema.omit({ verifier: true })) user: UsersSchema.merge(UserEncryptionKeysSchema.omit({ verifier: true }))
+5 -10
View File
@@ -158,8 +158,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
description: "List secrets", description: "List secrets",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
querystring: z.object({ querystring: z.object({
@@ -280,8 +279,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
description: "Get a secret by name", description: "Get a secret by name",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
params: z.object({ params: z.object({
@@ -375,8 +373,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
description: "Create secret", description: "Create secret",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
params: z.object({ params: z.object({
@@ -464,8 +461,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
description: "Update secret", description: "Update secret",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
params: z.object({ params: z.object({
@@ -550,8 +546,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
description: "Delete secret", description: "Delete secret",
security: [ security: [
{ {
bearerAuth: [], bearerAuth: []
apiKeyAuth: []
} }
], ],
params: z.object({ params: z.object({
@@ -129,26 +129,55 @@ const getAppsHeroku = async ({ accessToken }: { accessToken: string }) => {
* Return list of names of apps for Vercel integration * Return list of names of apps for Vercel integration
*/ */
const getAppsVercel = async ({ accessToken, teamId }: { teamId?: string | null; accessToken: string }) => { const getAppsVercel = async ({ accessToken, teamId }: { teamId?: string | null; accessToken: string }) => {
const res = ( const apps: Array<{ name: string; appId: string }> = [];
await request.get<{ projects: { name: string; id: string }[] }>(`${IntegrationUrls.VERCEL_API_URL}/v9/projects`, {
const limit = "20";
let hasMorePages = true;
let next: number | null = null;
interface Response {
projects: { name: string; id: string }[];
pagination: {
count: number;
next: number | null;
prev: number;
};
}
while (hasMorePages) {
const params: { [key: string]: string } = {
limit
};
if (teamId) {
params.teamId = teamId;
}
if (next) {
params.until = String(next);
}
const { data } = await request.get<Response>(`${IntegrationUrls.VERCEL_API_URL}/v9/projects`, {
params: new URLSearchParams(params),
headers: { headers: {
Authorization: `Bearer ${accessToken}`, Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json" "Accept-Encoding": "application/json"
}, }
...(teamId });
? {
params: {
teamId
}
}
: {})
})
).data;
const apps = res.projects.map((a) => ({ data.projects.forEach((a) => {
name: a.name, apps.push({
appId: a.id name: a.name,
})); appId: a.id
});
});
next = data.pagination.next;
if (data.pagination.next === null) {
hasMorePages = false;
}
}
return apps; return apps;
}; };
@@ -457,6 +457,8 @@ const syncSecretsAWSParameterStore = async ({
}); });
ssm.config.update(config); ssm.config.update(config);
const metadata = z.record(z.any()).parse(integration.metadata);
const params = { const params = {
Path: integration.path as string, Path: integration.path as string,
Recursive: false, Recursive: false,
@@ -486,7 +488,8 @@ const syncSecretsAWSParameterStore = async ({
Name: `${integration.path}${key}`, Name: `${integration.path}${key}`,
Type: "SecureString", Type: "SecureString",
Value: secrets[key].value, Value: secrets[key].value,
Overwrite: true // Overwrite: true,
Tags: metadata.secretAWSTag ? [{ Key: metadata.secretAWSTag.key, Value: metadata.secretAWSTag.value }] : []
}) })
.promise(); .promise();
// case: secret exists in AWS parameter store // case: secret exists in AWS parameter store
@@ -499,6 +502,7 @@ const syncSecretsAWSParameterStore = async ({
Type: "SecureString", Type: "SecureString",
Value: secrets[key].value, Value: secrets[key].value,
Overwrite: true Overwrite: true
// Tags: metadata.secretAWSTag ? [{ Key: metadata.secretAWSTag.key, Value: metadata.secretAWSTag.value }] : []
}) })
.promise(); .promise();
} }
@@ -537,6 +541,7 @@ const syncSecretsAWSSecretManager = async ({
}) => { }) => {
let secretsManager; let secretsManager;
const secKeyVal = getSecretKeyValuePair(secrets); const secKeyVal = getSecretKeyValuePair(secrets);
const metadata = z.record(z.any()).parse(integration.metadata);
try { try {
if (!accessId) return; if (!accessId) return;
@@ -573,7 +578,8 @@ const syncSecretsAWSSecretManager = async ({
await secretsManager.send( await secretsManager.send(
new CreateSecretCommand({ new CreateSecretCommand({
Name: integration.app as string, Name: integration.app as string,
SecretString: JSON.stringify(secKeyVal) SecretString: JSON.stringify(secKeyVal),
Tags: metadata.secretAWSTag ? [{ Key: metadata.secretAWSTag.key, Value: metadata.secretAWSTag.value }] : []
}) })
); );
} }
@@ -22,6 +22,10 @@ export type TCreateIntegrationDTO = {
labelName: string; labelName: string;
labelValue: string; labelValue: string;
}; };
secretAWSTag?: {
key: string;
value: string;
};
}; };
} & Omit<TProjectPermission, "projectId">; } & Omit<TProjectPermission, "projectId">;
@@ -134,8 +134,7 @@ export const projectMembershipServiceFactory = ({
const projectMemberships = await projectMembershipDAL.insertMany( const projectMemberships = await projectMembershipDAL.insertMany(
orgMembers.map(({ userId }) => ({ orgMembers.map(({ userId }) => ({
projectId, projectId,
userId: userId as string, userId: userId as string
role: ProjectMembershipRole.Member
})), })),
tx tx
); );
@@ -267,8 +266,7 @@ export const projectMembershipServiceFactory = ({
const projectMemberships = await projectMembershipDAL.insertMany( const projectMemberships = await projectMembershipDAL.insertMany(
orgMembers.map(({ user }) => ({ orgMembers.map(({ user }) => ({
projectId, projectId,
userId: user.id, userId: user.id
role: ProjectMembershipRole.Member
})), })),
tx tx
); );
+6
View File
@@ -381,6 +381,12 @@ func ProcessTemplate(templateId int, templatePath string, data interface{}, acce
funcs := template.FuncMap{ funcs := template.FuncMap{
"secret": secretFunction, "secret": secretFunction,
"dynamic_secret": dynamicSecretFunction, "dynamic_secret": dynamicSecretFunction,
"minus": func(a, b int) int {
return a - b
},
"add": func(a, b int) int {
return a + b
},
} }
templateName := path.Base(templatePath) templateName := path.Base(templatePath)
+32
View File
@@ -7,6 +7,7 @@ import (
"encoding/csv" "encoding/csv"
"encoding/json" "encoding/json"
"fmt" "fmt"
"os"
"strings" "strings"
"github.com/Infisical/infisical-merge/packages/models" "github.com/Infisical/infisical-merge/packages/models"
@@ -59,6 +60,11 @@ var exportCmd = &cobra.Command{
util.HandleError(err) util.HandleError(err)
} }
templatePath, err := cmd.Flags().GetString("template")
if err != nil {
util.HandleError(err)
}
secretOverriding, err := cmd.Flags().GetBool("secret-overriding") secretOverriding, err := cmd.Flags().GetBool("secret-overriding")
if err != nil { if err != nil {
util.HandleError(err, "Unable to parse flag") util.HandleError(err, "Unable to parse flag")
@@ -93,6 +99,31 @@ var exportCmd = &cobra.Command{
request.UniversalAuthAccessToken = token.Token request.UniversalAuthAccessToken = token.Token
} }
if templatePath != "" {
sigChan := make(chan os.Signal, 1)
dynamicSecretLeases := NewDynamicSecretLeaseManager(sigChan)
newEtag := ""
accessToken := ""
if token != nil {
accessToken = token.Token
} else {
log.Debug().Msg("GetAllEnvironmentVariables: Trying to fetch secrets using logged in details")
loggedInUserDetails, err := util.GetCurrentLoggedInUserDetails()
if err != nil {
util.HandleError(err)
}
accessToken = loggedInUserDetails.UserCredentials.JTWToken
}
processedTemplate, err := ProcessTemplate(1, templatePath, nil, accessToken, "", &newEtag, dynamicSecretLeases)
if err != nil {
util.HandleError(err)
}
fmt.Print(processedTemplate.String())
return
}
secrets, err := util.GetAllEnvironmentVariables(request, "") secrets, err := util.GetAllEnvironmentVariables(request, "")
if err != nil { if err != nil {
util.HandleError(err, "Unable to fetch secrets") util.HandleError(err, "Unable to fetch secrets")
@@ -140,6 +171,7 @@ func init() {
exportCmd.Flags().StringP("tags", "t", "", "filter secrets by tag slugs") exportCmd.Flags().StringP("tags", "t", "", "filter secrets by tag slugs")
exportCmd.Flags().String("projectId", "", "manually set the projectId to fetch secrets from") exportCmd.Flags().String("projectId", "", "manually set the projectId to fetch secrets from")
exportCmd.Flags().String("path", "/", "get secrets within a folder path") exportCmd.Flags().String("path", "/", "get secrets within a folder path")
exportCmd.Flags().String("template", "", "The path to the template file used to render secrets")
} }
// Format according to the format flag // Format according to the format flag
+23
View File
@@ -33,6 +33,9 @@ Export environment variables from the platform into a file format.
# Export variables to a YAML file # Export variables to a YAML file
infisical export --format=yaml > secrets.yaml infisical export --format=yaml > secrets.yaml
# Render secrets using a custom template file
infisical export --template=<path to template>
``` ```
### Environment variables ### Environment variables
@@ -57,6 +60,26 @@ Export environment variables from the platform into a file format.
</Accordion> </Accordion>
### flags ### flags
<Accordion title="--template">
The `--template` flag specifies the path to the template file used for rendering secrets. When using templates, you can omit the other format flags.
```text my-template-file
{{$secrets := secret "<infisical-project-id>" "<environment-slug>" "<folder-path>"}}
{{$length := len $secrets}}
{{- "{"}}
{{- with $secrets }}
{{- range $index, $secret := . }}
"{{ $secret.Key }}": "{{ $secret.Value }}"{{if lt $index (minus $length 1)}},{{end}}
{{- end }}
{{- end }}
{{ "}" -}}
```
```bash
# Example
infisical export --template="/path/to/template/file"
```
</Accordion>
<Accordion title="--env"> <Accordion title="--env">
Used to set the environment that secrets are pulled from. Used to set the environment that secrets are pulled from.
@@ -0,0 +1,115 @@
---
title: "MySQL"
description: "Learn how to dynamically generate MySQL Database user passwords."
---
The Infisical MySQL dynamic secret allows you to generate MySQL Database credentials on demand based on configured role.
## Prerequisite
Create a user with the required permission in your SQL instance. This user will be used to create new accounts on-demand.
## Set up Dynamic Secrets with MySQL
<Steps>
<Step title="Open Secret Overview Dashboard">
Open the Secret Overview dashboard and select the environment in which you would like to add a dynamic secret.
</Step>
<Step title="Click on the 'Add Dynamic Secret' button">
![Add Dynamic Secret Button](../../../images/platform/dynamic-secrets/add-dynamic-secret-button.png)
</Step>
<Step title="Select 'SQL Database'">
![Dynamic Secret Modal](../../../images/platform/dynamic-secrets/dynamic-secret-modal.png)
</Step>
<Step title="Provide the inputs for dynamic secret parameters">
<ParamField path="Secret Name" type="string" required>
Name by which you want the secret to be referenced
</ParamField>
<ParamField path="Default TTL" type="string" required>
Default time-to-live for a generated secret (it is possible to modify this value when a secret is generate)
</ParamField>
<ParamField path="Max TTL" type="string" required>
Maximum time-to-live for a generated secret
</ParamField>
<ParamField path="Service" type="string" required>
Choose the service you want to generate dynamic secrets for. This must be selected as **MySQL**.
</ParamField>
<ParamField path="Host" type="string" required>
Database host
</ParamField>
<ParamField path="Port" type="number" required>
Database port
</ParamField>
<ParamField path="User" type="string" required>
Username that will be used to create dynamic secrets
</ParamField>
<ParamField path="Password" type="string" required>
Password that will be used to create dynamic secrets
</ParamField>
<ParamField path="Database Name" type="string" required>
Name of the database for which you want to create dynamic secrets
</ParamField>
<ParamField path="CA(SSL)" type="string">
A CA may be required if your DB requires it for incoming connections. AWS RDS instances with default settings will requires a CA which can be downloaded [here](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL.html#UsingWithRDS.SSL.CertificatesAllRegions).
</ParamField>
</Step>
<Step title="(Optional) Modify SQL Statements">
If you want to provide specific privileges for the generated dynamic credentials, you can modify the SQL statement to your needs. This is useful if you want to only give access to a specific table(s).
![Modify SQL Statements Modal](/images/platform/dynamic-secrets/modify-sql-statement-mysql.png)
</Step>
<Step title="Click `Submit`">
After submitting the form, you will see a dynamic secret created in the dashboard.
<Note>
If this step fails, you may have to add the CA certificate.
</Note>
![Dynamic Secret](/images/platform/dynamic-secrets/dynamic-secret.png)
</Step>
<Step title="Generate dynamic secrets">
Once you've successfully configured the dynamic secret, you're ready to generate on-demand credentials.
To do this, simply click on the 'Generate' button which appears when hovering over the dynamic secret item.
Alternatively, you can initiate the creation of a new lease by selecting 'New Lease' from the dynamic secret lease list section.
![Dynamic Secret](/images/platform/dynamic-secrets/dynamic-secret-generate.png)
![Dynamic Secret](/images/platform/dynamic-secrets/dynamic-secret-lease-empty.png)
When generating these secrets, it's important to specify a Time-to-Live (TTL) duration. This will dictate how long the credentials are valid for.
![Provision Lease](/images/platform/dynamic-secrets/provision-lease.png)
<Tip>
Ensure that the TTL for the lease fall within the maximum TTL defined when configuring the dynamic secret.
</Tip>
Once you click the `Submit` button, a new secret lease will be generated and the credentials from it will be shown to you.
![Provision Lease](/images/platform/dynamic-secrets/lease-values.png)
</Step>
</Steps>
## Audit or Revoke Leases
Once you have created one or more leases, you will be able to access them by clicking on the respective dynamic secret item on the dashboard.
This will allow you see the expiration time of the lease or delete a lease before it's set time to live.
![Provision Lease](/images/platform/dynamic-secrets/lease-data.png)
## Renew Leases
To extend the life of the generated dynamic secret leases past its initial time to live, simply click on the **Renew** as illustrated below.
![Provision Lease](/images/platform/dynamic-secrets/dynamic-secret-lease-renew.png)
<Warning>
Lease renewals cannot exceed the maximum TTL set when configuring the dynamic secret
</Warning>
@@ -0,0 +1,115 @@
---
title: "Oracle"
description: "Learn how to dynamically generate Oracle Database user passwords."
---
The Infisical Oracle dynamic secret allows you to generate Oracle Database credentials on demand based on configured role.
## Prerequisite
Create a user with the required permission in your SQL instance. This user will be used to create new accounts on-demand.
## Set up Dynamic Secrets with Oracle
<Steps>
<Step title="Open Secret Overview Dashboard">
Open the Secret Overview dashboard and select the environment in which you would like to add a dynamic secret.
</Step>
<Step title="Click on the 'Add Dynamic Secret' button">
![Add Dynamic Secret Button](../../../images/platform/dynamic-secrets/add-dynamic-secret-button.png)
</Step>
<Step title="Select `SQL Database`">
![Dynamic Secret Modal](../../../images/platform/dynamic-secrets/dynamic-secret-modal.png)
</Step>
<Step title="Provide the inputs for dynamic secret parameters">
<ParamField path="Secret Name" type="string" required>
Name by which you want the secret to be referenced
</ParamField>
<ParamField path="Default TTL" type="string" required>
Default time-to-live for a generated secret (it is possible to modify this value when a secret is generate)
</ParamField>
<ParamField path="Max TTL" type="string" required>
Maximum time-to-live for a generated secret
</ParamField>
<ParamField path="Service" type="string" required>
Choose the service you want to generate dynamic secrets for. This must be selected as **Oracle**.
</ParamField>
<ParamField path="Host" type="string" required>
Database host
</ParamField>
<ParamField path="Port" type="number" required>
Database port
</ParamField>
<ParamField path="User" type="string" required>
Username that will be used to create dynamic secrets
</ParamField>
<ParamField path="Password" type="string" required>
Password that will be used to create dynamic secrets
</ParamField>
<ParamField path="Database Name" type="string" required>
Name of the database for which you want to create dynamic secrets
</ParamField>
<ParamField path="CA(SSL)" type="string">
A CA may be required if your DB requires it for incoming connections. AWS RDS instances with default settings will requires a CA which can be downloaded [here](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL.html#UsingWithRDS.SSL.CertificatesAllRegions).
</ParamField>
![Dynamic Secret Setup Modal](../../../images/platform/dynamic-secrets/dynamic-secret-modal-oracle.png)
</Step>
<Step title="(Optional) Modify SQL Statements">
If you want to provide specific privileges for the generated dynamic credentials, you can modify the SQL statement to your needs. This is useful if you want to only give access to a specific table(s).
</Step>
<Step title="Click 'Submit'">
After submitting the form, you will see a dynamic secret created in the dashboard.
<Note>
If this step fails, you may have to add the CA certficate.
</Note>
![Dynamic Secret](../../../images/platform/dynamic-secrets/dynamic-secret.png)
</Step>
<Step title="Generate dynamic secrets">
Once you've successfully configured the dynamic secret, you're ready to generate on-demand credentials.
To do this, simply click on the 'Generate' button which appears when hovering over the dynamic secret item.
Alternatively, you can initiate the creation of a new lease by selecting 'New Lease' from the dynamic secret lease list section.
![Dynamic Secret](/images/platform/dynamic-secrets/dynamic-secret-generate.png)
![Dynamic Secret](/images/platform/dynamic-secrets/dynamic-secret-lease-empty.png)
When generating these secrets, it's important to specify a Time-to-Live (TTL) duration. This will dictate how long the credentials are valid for.
![Provision Lease](/images/platform/dynamic-secrets/provision-lease.png)
<Tip>
Ensure that the TTL for the lease fall within the maximum TTL defined when configuring the dynamic secret.
</Tip>
Once you click the `Submit` button, a new secret lease will be generated and the credentials for it will be shown to you.
![Provision Lease](/images/platform/dynamic-secrets/lease-values.png)
</Step>
</Steps>
## Audit or Revoke Leases
Once you have created one or more leases, you will be able to access them by clicking on the respective dynamic secret item on the dashboard.
This will allow you see the expiration time of the lease or delete a lease before it's set time to live.
![Provision Lease](/images/platform/dynamic-secrets/lease-data.png)
## Renew Leases
To extend the life of the generated dynamic secret leases past its initial time to live, simply click on the **Renew** as illustrated below.
![Provision Lease](/images/platform/dynamic-secrets/dynamic-secret-lease-renew.png)
<Warning>
Lease renewals cannot exceed the maximum TTL set when configuring the dynamic secret
</Warning>
@@ -1,14 +1,13 @@
--- ---
title: "PostgreSQL" title: "PostgreSQL"
description: "Learn how to dynamically generate PostgreSQL Database user passwords." description: "How to dynamically generate PostgreSQL database users"
--- ---
The Infisical PostgreSQL secret rotation allows you to automatically rotate your PostgreSQL database user's password at a predefined interval. The Infisical PostgreSQL dynamic secret allows you to generate PostgreSQL database credentials on demand based on configured role.
## Prerequisite ## Prerequisite
1. Create a user with the required permission in your SQL instance. Create a user with the required permission in your SQL instance. This user will be used to create new accounts on-demand.
## Set up Dynamic Secrets with PostgreSQL ## Set up Dynamic Secrets with PostgreSQL
@@ -17,7 +16,7 @@ The Infisical PostgreSQL secret rotation allows you to automatically rotate your
<Step title="Open Secret Overview Dashboard"> <Step title="Open Secret Overview Dashboard">
Open the Secret Overview dashboard and select the environment in which you would like to add a dynamic secret. Open the Secret Overview dashboard and select the environment in which you would like to add a dynamic secret.
</Step> </Step>
<Step title="Click on the `Add Dynamic Secret` button"> <Step title="Click on the 'Add Dynamic Secret' button">
![Add Dynamic Secret Button](../../../images/platform/dynamic-secrets/add-dynamic-secret-button.png) ![Add Dynamic Secret Button](../../../images/platform/dynamic-secrets/add-dynamic-secret-button.png)
</Step> </Step>
<Step title="Select `SQL Database`"> <Step title="Select `SQL Database`">
@@ -37,7 +36,7 @@ The Infisical PostgreSQL secret rotation allows you to automatically rotate your
</ParamField> </ParamField>
<ParamField path="Service" type="string" required> <ParamField path="Service" type="string" required>
Choose the service you want to generate dynamic secrets for Choose the service you want to generate dynamic secrets for. This must be selected as **PostgreSQL**.
</ParamField> </ParamField>
<ParamField path="Host" type="string" required> <ParamField path="Host" type="string" required>
@@ -68,31 +67,52 @@ The Infisical PostgreSQL secret rotation allows you to automatically rotate your
</Step> </Step>
<Step title="(Optional) Modify SQL Statements"> <Step title="(Optional) Modify SQL Statements">
If you want to provide specific privileges for the future generated dynamic secrets, you are able to specify them as SQL statements. If you want to provide specific privileges for the generated dynamic credentials, you can modify the SQL statement to your needs. This is useful if you want to only give access to a specific table(s).
![Modify SQL Statements Modal](../../../images/platform/dynamic-secrets/modify-sql-statements.png) ![Modify SQL Statements Modal](../../../images/platform/dynamic-secrets/modify-sql-statements.png)
</Step> </Step>
<Step title="Click `Submit`"> <Step title="Click 'Submit'">
After submitting the form, you will see a dynamic secret creates in the dashboard. After submitting the form, you will see a dynamic secret created in the dashboard.
<Note> <Note>
If this step fails, you might have to add the CA certficate. If this step fails, you may have to add the CA certficate.
</Note> </Note>
![Dynamic Secret](../../../images/platform/dynamic-secrets/dynamic-secret.png) ![Dynamic Secret](../../../images/platform/dynamic-secrets/dynamic-secret.png)
</Step> </Step>
<Step title="Generate dynamic secrets"> <Step title="Generate dynamic secrets">
Now that the dynamic secret is created, you can start generating unique secret values by specifying the Time-to-live within the predefined range. Once you've successfully configured the dynamic secret, you're ready to generate on-demand credentials.
To do this, simply click on the 'Generate' button which appears when hovering over the dynamic secret item.
Alternatively, you can initiate the creation of a new lease by selecting 'New Lease' from the dynamic secret lease list section.
![Provision Lease](../../../images/platform/dynamic-secrets/provision-lease.png) ![Dynamic Secret](/images/platform/dynamic-secrets/dynamic-secret-generate.png)
![Dynamic Secret](/images/platform/dynamic-secrets/dynamic-secret-lease-empty.png)
After you click the `Submit` button, a new secret lease will be generated and the Database User and Database Password will be shown. When generating these secrets, it's important to specify a Time-to-Live (TTL) duration. This will dictate how long the credentials are valid for.
![Provision Lease](../../../images/platform/dynamic-secrets/lease-values.png) ![Provision Lease](/images/platform/dynamic-secrets/provision-lease.png)
</Step>
<Step title="Audit or Revoke Leases">
As soon as you have generated a few secret leases, you will be able to access them by clicking `Generate` on the dynamic secret row. In this modal, you are able to see the expiration time or delete a secret preemptively.
![Provision Lease](../../../images/platform/dynamic-secrets/lease-data.png) <Tip>
Ensure that the TTL for the lease fall within the maximum TTL defined when configuring the dynamic secret.
</Tip>
Once you click the `Submit` button, a new secret lease will be generated and the credentials for it will be shown to you.
![Provision Lease](/images/platform/dynamic-secrets/lease-values.png)
</Step> </Step>
</Steps> </Steps>
## Audit or Revoke Leases
Once you have created one or more leases, you will be able to access them by clicking on the respective dynamic secret item on the dashboard.
This will allow you see the expiration time of the lease or delete the lease before it's set time to live.
![Provision Lease](/images/platform/dynamic-secrets/lease-data.png)
## Renew Leases
To extend the life of the generated dynamic secret leases past its initial time to live, simply click on the **Renew** as illustrated below.
![Provision Lease](/images/platform/dynamic-secrets/dynamic-secret-lease-renew.png)
<Warning>
Lease renewals cannot exceed the maximum TTL set when configuring the dynamic secret
</Warning>
Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

@@ -29,7 +29,8 @@ Prerequisites:
"ssm:PutParameter", "ssm:PutParameter",
"ssm:DeleteParameter", "ssm:DeleteParameter",
"ssm:GetParametersByPath", "ssm:GetParametersByPath",
"ssm:DeleteParameters" "ssm:DeleteParameters",
"ssm:AddTagsToResource"
], ],
"Resource": "*" "Resource": "*"
} }
@@ -28,7 +28,8 @@ Prerequisites:
"Action": [ "Action": [
"secretsmanager:GetSecretValue", "secretsmanager:GetSecretValue",
"secretsmanager:CreateSecret", "secretsmanager:CreateSecret",
"secretsmanager:UpdateSecret" "secretsmanager:UpdateSecret",
"secretsmanager:TagResource"
], ],
"Resource": "*" "Resource": "*"
} }
+11 -34
View File
@@ -32,10 +32,7 @@
"thumbsRating": true "thumbsRating": true
}, },
"api": { "api": {
"baseUrl": [ "baseUrl": ["https://app.infisical.com", "http://localhost:8080"]
"https://app.infisical.com",
"http://localhost:8080"
]
}, },
"topbarLinks": [ "topbarLinks": [
{ {
@@ -142,7 +139,9 @@
"group": "Dynamic Secrets", "group": "Dynamic Secrets",
"pages": [ "pages": [
"documentation/platform/dynamic-secrets/overview", "documentation/platform/dynamic-secrets/overview",
"documentation/platform/dynamic-secrets/postgresql" "documentation/platform/dynamic-secrets/postgresql",
"documentation/platform/dynamic-secrets/mysql",
"documentation/platform/dynamic-secrets/oracle"
] ]
}, },
"documentation/platform/groups" "documentation/platform/groups"
@@ -370,15 +369,11 @@
}, },
{ {
"group": "Build Tool Integrations", "group": "Build Tool Integrations",
"pages": [ "pages": ["integrations/build-tools/gradle"]
"integrations/build-tools/gradle"
]
}, },
{ {
"group": "", "group": "",
"pages": [ "pages": ["sdks/overview"]
"sdks/overview"
]
}, },
{ {
"group": "SDK's", "group": "SDK's",
@@ -396,22 +391,13 @@
"api-reference/overview/authentication", "api-reference/overview/authentication",
{ {
"group": "Examples", "group": "Examples",
"pages": [ "pages": ["api-reference/overview/examples/integration"]
"api-reference/overview/examples/integration"
]
} }
] ]
}, },
{ {
"group": "Endpoints", "group": "Endpoints",
"pages": [ "pages": [
{
"group": "Users",
"pages": [
"api-reference/endpoints/users/me",
"api-reference/endpoints/users/my-organizations"
]
},
{ {
"group": "Identities", "group": "Identities",
"pages": [ "pages": [
@@ -457,7 +443,6 @@
"api-reference/endpoints/workspaces/list-identity-memberships", "api-reference/endpoints/workspaces/list-identity-memberships",
"api-reference/endpoints/workspaces/update-identity-membership", "api-reference/endpoints/workspaces/update-identity-membership",
"api-reference/endpoints/workspaces/delete-identity-membership", "api-reference/endpoints/workspaces/delete-identity-membership",
"api-reference/endpoints/workspaces/workspace-key",
"api-reference/endpoints/workspaces/secret-snapshots", "api-reference/endpoints/workspaces/secret-snapshots",
"api-reference/endpoints/workspaces/rollback-snapshot" "api-reference/endpoints/workspaces/rollback-snapshot"
] ]
@@ -535,15 +520,11 @@
}, },
{ {
"group": "Service Tokens", "group": "Service Tokens",
"pages": [ "pages": ["api-reference/endpoints/service-tokens/get"]
"api-reference/endpoints/service-tokens/get"
]
}, },
{ {
"group": "Audit Logs", "group": "Audit Logs",
"pages": [ "pages": ["api-reference/endpoints/audit-logs/export-audit-log"]
"api-reference/endpoints/audit-logs/export-audit-log"
]
} }
] ]
}, },
@@ -559,9 +540,7 @@
}, },
{ {
"group": "", "group": "",
"pages": [ "pages": ["changelog/overview"]
"changelog/overview"
]
}, },
{ {
"group": "Contributing", "group": "Contributing",
@@ -585,9 +564,7 @@
}, },
{ {
"group": "Contributing to SDK", "group": "Contributing to SDK",
"pages": [ "pages": ["contributing/sdk/developing"]
"contributing/sdk/developing"
]
} }
] ]
} }
+2 -2
View File
@@ -143,8 +143,8 @@ Without email configuration, Infisical's core functions like sign-up/login and s
SMTP_HOST=email-smtp.ap-northeast-1.amazonaws.com # SMTP endpoint obtained from SMTP settings SMTP_HOST=email-smtp.ap-northeast-1.amazonaws.com # SMTP endpoint obtained from SMTP settings
SMTP_USERNAME=xxx # your SMTP username SMTP_USERNAME=xxx # your SMTP username
SMTP_PASSWORD=xxx # your SMTP password SMTP_PASSWORD=xxx # your SMTP password
SMTP_PORT=587 SMTP_PORT=465
SMTP_SECURE=false SMTP_SECURE=true
[email protected] # your email address being used to send out emails [email protected] # your email address being used to send out emails
SMTP_FROM_NAME=Infisical SMTP_FROM_NAME=Infisical
``` ```
@@ -21,7 +21,8 @@ export enum DynamicSecretProviders {
export enum SqlProviders { export enum SqlProviders {
Postgres = "postgres", Postgres = "postgres",
MySql = "mysql2" MySql = "mysql2",
Oracle = "oracledb"
} }
export type TDynamicSecretProvider = { export type TDynamicSecretProvider = {
@@ -63,6 +63,10 @@ export const useCreateIntegration = () => {
secretSuffix?: string; secretSuffix?: string;
initialSyncBehavior?: string; initialSyncBehavior?: string;
shouldAutoRedeploy?: boolean; shouldAutoRedeploy?: boolean;
secretAWSTag?: {
key: string;
value: string;
};
}; };
}) => { }) => {
const { const {
@@ -10,6 +10,7 @@ import {
faCircleInfo faCircleInfo
} from "@fortawesome/free-solid-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { motion } from "framer-motion";
import queryString from "query-string"; import queryString from "query-string";
import { useCreateIntegration } from "@app/hooks/api"; import { useCreateIntegration } from "@app/hooks/api";
@@ -21,11 +22,21 @@ import {
FormControl, FormControl,
Input, Input,
Select, Select,
SelectItem SelectItem,
Switch,
Tab,
TabList,
TabPanel,
Tabs
} from "../../../components/v2"; } from "../../../components/v2";
import { useGetIntegrationAuthById } from "../../../hooks/api/integrationAuth"; import { useGetIntegrationAuthById } from "../../../hooks/api/integrationAuth";
import { useGetWorkspaceById } from "../../../hooks/api/workspace"; import { useGetWorkspaceById } from "../../../hooks/api/workspace";
enum TabSections {
Connection = "connection",
Options = "options"
}
const awsRegions = [ const awsRegions = [
{ name: "US East (Ohio)", slug: "us-east-2" }, { name: "US East (Ohio)", slug: "us-east-2" },
{ name: "US East (N. Virginia)", slug: "us-east-1" }, { name: "US East (N. Virginia)", slug: "us-east-1" },
@@ -76,6 +87,9 @@ export default function AWSParameterStoreCreateIntegrationPage() {
const [pathErrorText, setPathErrorText] = useState(""); const [pathErrorText, setPathErrorText] = useState("");
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [shouldTag, setShouldTag] = useState(false);
const [tagKey, setTagKey] = useState("");
const [tagValue, setTagValue] = useState("");
useEffect(() => { useEffect(() => {
if (workspace) { if (workspace) {
@@ -110,7 +124,17 @@ export default function AWSParameterStoreCreateIntegrationPage() {
sourceEnvironment: selectedSourceEnvironment, sourceEnvironment: selectedSourceEnvironment,
path, path,
region: selectedAWSRegion, region: selectedAWSRegion,
secretPath secretPath,
metadata: {
...(shouldTag
? {
secretAWSTag: {
key: tagKey,
value: tagValue
}
}
: {})
}
}); });
setIsLoading(false); setIsLoading(false);
@@ -157,56 +181,114 @@ export default function AWSParameterStoreCreateIntegrationPage() {
</Link> </Link>
</div> </div>
</CardTitle> </CardTitle>
<FormControl label="Project Environment" className="px-6"> <Tabs defaultValue={TabSections.Connection} className="px-6">
<Select <TabList>
value={selectedSourceEnvironment} <div className="flex w-full flex-row border-b border-mineshaft-600">
onValueChange={(val) => setSelectedSourceEnvironment(val)} <Tab value={TabSections.Connection}>Connection</Tab>
className="w-full border border-mineshaft-500" <Tab value={TabSections.Options}>Options</Tab>
> </div>
{workspace?.environments.map((sourceEnvironment) => ( </TabList>
<SelectItem <TabPanel value={TabSections.Connection}>
value={sourceEnvironment.slug} <motion.div
key={`flyio-environment-${sourceEnvironment.slug}`} key="panel-1"
transition={{ duration: 0.15 }}
initial={{ opacity: 0, translateX: 30 }}
animate={{ opacity: 1, translateX: 0 }}
exit={{ opacity: 0, translateX: 30 }}
>
<FormControl label="Project Environment">
<Select
value={selectedSourceEnvironment}
onValueChange={(val) => setSelectedSourceEnvironment(val)}
className="w-full border border-mineshaft-500"
>
{workspace?.environments.map((sourceEnvironment) => (
<SelectItem
value={sourceEnvironment.slug}
key={`flyio-environment-${sourceEnvironment.slug}`}
>
{sourceEnvironment.name}
</SelectItem>
))}
</Select>
</FormControl>
<FormControl label="Secrets Path">
<Input
value={secretPath}
onChange={(evt) => setSecretPath(evt.target.value)}
placeholder="Provide a path, default is /"
/>
</FormControl>
<FormControl label="AWS Region">
<Select
value={selectedAWSRegion}
onValueChange={(val) => setSelectedAWSRegion(val)}
className="w-full border border-mineshaft-500"
>
{awsRegions.map((awsRegion) => (
<SelectItem value={awsRegion.slug} key={`flyio-environment-${awsRegion.slug}`}>
{awsRegion.name}
</SelectItem>
))}
</Select>
</FormControl>
<FormControl
label="Path"
errorText={pathErrorText}
isError={pathErrorText !== "" ?? false}
> >
{sourceEnvironment.name} <Input
</SelectItem> placeholder={`/${workspace.name
))} .toLowerCase()
</Select> .replace(/ /g, "-")}/${selectedSourceEnvironment}/`}
</FormControl> value={path}
<FormControl label="Secrets Path" className="px-6"> onChange={(e) => setPath(e.target.value)}
<Input />
value={secretPath} </FormControl>
onChange={(evt) => setSecretPath(evt.target.value)} </motion.div>
placeholder="Provide a path, default is /" </TabPanel>
/> <TabPanel value={TabSections.Options}>
</FormControl> <motion.div
<FormControl label="AWS Region" className="px-6"> key="panel-1"
<Select transition={{ duration: 0.15 }}
value={selectedAWSRegion} initial={{ opacity: 0, translateX: -30 }}
onValueChange={(val) => setSelectedAWSRegion(val)} animate={{ opacity: 1, translateX: 0 }}
className="w-full border border-mineshaft-500" exit={{ opacity: 0, translateX: 30 }}
> >
{awsRegions.map((awsRegion) => ( <div className="mt-2 ml-1">
<SelectItem value={awsRegion.slug} key={`flyio-environment-${awsRegion.slug}`}> <Switch
{awsRegion.name} id="tag-aws"
</SelectItem> onCheckedChange={() => setShouldTag(!shouldTag)}
))} isChecked={shouldTag}
</Select> >
</FormControl> Tag in AWS Parameter Store
<FormControl </Switch>
label="Path" </div>
errorText={pathErrorText} {shouldTag && (
isError={pathErrorText !== "" ?? false} <div className="mt-4">
className="px-6" <FormControl
> label="Tag Key"
<Input >
placeholder={`/${workspace.name <Input
.toLowerCase() placeholder="managed-by"
.replace(/ /g, "-")}/${selectedSourceEnvironment}/`} value={tagKey}
value={path} onChange={(e) => setTagKey(e.target.value)}
onChange={(e) => setPath(e.target.value)} />
/> </FormControl>
</FormControl> <FormControl
label="Tag Value"
>
<Input
placeholder="managed-by"
value={tagValue}
onChange={(e) => setTagValue(e.target.value)}
/>
</FormControl>
</div>
)}
</motion.div>
</TabPanel>
</Tabs>
<Button <Button
onClick={handleButtonClick} onClick={handleButtonClick}
color="mineshaft" color="mineshaft"
@@ -10,6 +10,7 @@ import {
faCircleInfo faCircleInfo
} from "@fortawesome/free-solid-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { motion } from "framer-motion";
import queryString from "query-string"; import queryString from "query-string";
import { useCreateIntegration } from "@app/hooks/api"; import { useCreateIntegration } from "@app/hooks/api";
@@ -21,11 +22,21 @@ import {
FormControl, FormControl,
Input, Input,
Select, Select,
SelectItem SelectItem,
Switch,
Tab,
TabList,
TabPanel,
Tabs
} from "../../../components/v2"; } from "../../../components/v2";
import { useGetIntegrationAuthById } from "../../../hooks/api/integrationAuth"; import { useGetIntegrationAuthById } from "../../../hooks/api/integrationAuth";
import { useGetWorkspaceById } from "../../../hooks/api/workspace"; import { useGetWorkspaceById } from "../../../hooks/api/workspace";
enum TabSections {
Connection = "connection",
Options = "options"
}
const awsRegions = [ const awsRegions = [
{ name: "US East (Ohio)", slug: "us-east-2" }, { name: "US East (Ohio)", slug: "us-east-2" },
{ name: "US East (N. Virginia)", slug: "us-east-1" }, { name: "US East (N. Virginia)", slug: "us-east-1" },
@@ -74,11 +85,14 @@ export default function AWSSecretManagerCreateIntegrationPage() {
const [selectedAWSRegion, setSelectedAWSRegion] = useState(""); const [selectedAWSRegion, setSelectedAWSRegion] = useState("");
const [targetSecretName, setTargetSecretName] = useState(""); const [targetSecretName, setTargetSecretName] = useState("");
const [targetSecretNameErrorText, setTargetSecretNameErrorText] = useState(""); const [targetSecretNameErrorText, setTargetSecretNameErrorText] = useState("");
const [tagKey, setTagKey] = useState("");
const [tagValue, setTagValue] = useState("");
// const [path, setPath] = useState(''); // const [path, setPath] = useState('');
// const [pathErrorText, setPathErrorText] = useState(''); // const [pathErrorText, setPathErrorText] = useState('');
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [shouldTag, setShouldTag] = useState(false);
useEffect(() => { useEffect(() => {
if (workspace) { if (workspace) {
@@ -109,7 +123,17 @@ export default function AWSSecretManagerCreateIntegrationPage() {
app: targetSecretName.trim(), app: targetSecretName.trim(),
sourceEnvironment: selectedSourceEnvironment, sourceEnvironment: selectedSourceEnvironment,
region: selectedAWSRegion, region: selectedAWSRegion,
secretPath secretPath,
metadata: {
...(shouldTag
? {
secretAWSTag: {
key: tagKey,
value: tagValue
}
}
: {})
}
}); });
setIsLoading(false); setIsLoading(false);
@@ -156,56 +180,114 @@ export default function AWSSecretManagerCreateIntegrationPage() {
</Link> </Link>
</div> </div>
</CardTitle> </CardTitle>
<FormControl label="Project Environment" className="px-6"> <Tabs defaultValue={TabSections.Connection} className="px-6">
<Select <TabList>
value={selectedSourceEnvironment} <div className="flex w-full flex-row border-b border-mineshaft-600">
onValueChange={(val) => setSelectedSourceEnvironment(val)} <Tab value={TabSections.Connection}>Connection</Tab>
className="w-full border border-mineshaft-500" <Tab value={TabSections.Options}>Options</Tab>
> </div>
{workspace?.environments.map((sourceEnvironment) => ( </TabList>
<SelectItem <TabPanel value={TabSections.Connection}>
value={sourceEnvironment.slug} <motion.div
key={`flyio-environment-${sourceEnvironment.slug}`} key="panel-1"
transition={{ duration: 0.15 }}
initial={{ opacity: 0, translateX: 30 }}
animate={{ opacity: 1, translateX: 0 }}
exit={{ opacity: 0, translateX: 30 }}
>
<FormControl label="Project Environment">
<Select
value={selectedSourceEnvironment}
onValueChange={(val) => setSelectedSourceEnvironment(val)}
className="w-full border border-mineshaft-500"
>
{workspace?.environments.map((sourceEnvironment) => (
<SelectItem
value={sourceEnvironment.slug}
key={`flyio-environment-${sourceEnvironment.slug}`}
>
{sourceEnvironment.name}
</SelectItem>
))}
</Select>
</FormControl>
<FormControl label="Secrets Path">
<Input
value={secretPath}
onChange={(evt) => setSecretPath(evt.target.value)}
placeholder="Provide a path, default is /"
/>
</FormControl>
<FormControl label="AWS Region">
<Select
value={selectedAWSRegion}
onValueChange={(val) => setSelectedAWSRegion(val)}
className="w-full border border-mineshaft-500"
>
{awsRegions.map((awsRegion) => (
<SelectItem value={awsRegion.slug} key={`flyio-environment-${awsRegion.slug}`}>
{awsRegion.name}
</SelectItem>
))}
</Select>
</FormControl>
<FormControl
label="AWS SM Secret Name"
errorText={targetSecretNameErrorText}
isError={targetSecretNameErrorText !== "" ?? false}
> >
{sourceEnvironment.name} <Input
</SelectItem> placeholder={`${workspace.name
))} .toLowerCase()
</Select> .replace(/ /g, "-")}/${selectedSourceEnvironment}`}
</FormControl> value={targetSecretName}
<FormControl label="Secrets Path" className="px-6"> onChange={(e) => setTargetSecretName(e.target.value)}
<Input />
value={secretPath} </FormControl>
onChange={(evt) => setSecretPath(evt.target.value)} </motion.div>
placeholder="Provide a path, default is /" </TabPanel>
/> <TabPanel value={TabSections.Options}>
</FormControl> <motion.div
<FormControl label="AWS Region" className="px-6"> key="panel-1"
<Select transition={{ duration: 0.15 }}
value={selectedAWSRegion} initial={{ opacity: 0, translateX: -30 }}
onValueChange={(val) => setSelectedAWSRegion(val)} animate={{ opacity: 1, translateX: 0 }}
className="w-full border border-mineshaft-500" exit={{ opacity: 0, translateX: 30 }}
> >
{awsRegions.map((awsRegion) => ( <div className="mt-2 ml-1">
<SelectItem value={awsRegion.slug} key={`flyio-environment-${awsRegion.slug}`}> <Switch
{awsRegion.name} id="tag-aws"
</SelectItem> onCheckedChange={() => setShouldTag(!shouldTag)}
))} isChecked={shouldTag}
</Select> >
</FormControl> Tag in AWS Secrets Manager
<FormControl </Switch>
label="AWS SM Secret Name" </div>
errorText={targetSecretNameErrorText} {shouldTag && (
isError={targetSecretNameErrorText !== "" ?? false} <div className="mt-4">
className="px-6" <FormControl
> label="Tag Key"
<Input >
placeholder={`${workspace.name <Input
.toLowerCase() placeholder="managed-by"
.replace(/ /g, "-")}/${selectedSourceEnvironment}`} value={tagKey}
value={targetSecretName} onChange={(e) => setTagKey(e.target.value)}
onChange={(e) => setTargetSecretName(e.target.value)} />
/> </FormControl>
</FormControl> <FormControl
label="Tag Value"
>
<Input
placeholder="managed-by"
value={tagValue}
onChange={(e) => setTagValue(e.target.value)}
/>
</FormControl>
</div>
)}
</motion.div>
</TabPanel>
</Tabs>
<Button <Button
onClick={handleButtonClick} onClick={handleButtonClick}
color="mineshaft" color="mineshaft"
@@ -77,6 +77,16 @@ const getSqlStatements = (provider: SqlProviders) => {
}; };
} }
if (provider === SqlProviders.Oracle) {
return {
creationStatement:
'CREATE USER "{{username}}" IDENTIFIED BY "{{password}}";\nGRANT CONNECT TO "{{username}}";\nGRANT CREATE SESSION TO "{{username}}";',
renewStatement: "",
revocationStatement:
'REVOKE CONNECT FROM "{{username}}";\nREVOKE CREATE SESSION FROM "{{username}}";\nDROP USER "{{username}}";'
};
}
return { return {
creationStatement: creationStatement:
"CREATE USER \"{{username}}\" WITH ENCRYPTED PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';\nGRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO \"{{username}}\";", "CREATE USER \"{{username}}\" WITH ENCRYPTED PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';\nGRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO \"{{username}}\";",
@@ -208,6 +218,7 @@ export const SqlDatabaseInputForm = ({
> >
<SelectItem value={SqlProviders.Postgres}>PostgreSQL</SelectItem> <SelectItem value={SqlProviders.Postgres}>PostgreSQL</SelectItem>
<SelectItem value={SqlProviders.MySql}>MySQL</SelectItem> <SelectItem value={SqlProviders.MySql}>MySQL</SelectItem>
<SelectItem value={SqlProviders.Oracle}>Oracle</SelectItem>
</Select> </Select>
</FormControl> </FormControl>
)} )}
@@ -193,6 +193,7 @@ export const EditDynamicSecretSqlProviderForm = ({
> >
<SelectItem value={SqlProviders.Postgres}>PostgreSQL</SelectItem> <SelectItem value={SqlProviders.Postgres}>PostgreSQL</SelectItem>
<SelectItem value={SqlProviders.MySql}>MySQL</SelectItem> <SelectItem value={SqlProviders.MySql}>MySQL</SelectItem>
<SelectItem value={SqlProviders.Oracle}>Oracle</SelectItem>
</Select> </Select>
</FormControl> </FormControl>
)} )}
@@ -5,4 +5,8 @@ export type Metadata = {
labelName: string; labelName: string;
labelValue: string; labelValue: string;
} }
secretAWSTag?: {
key: string;
value: string;
}
} }