mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-05 15:26:35 +00:00
feat(infisical-pg): completed audit log moved ee routes to normal routing pattern
This commit is contained in:
@@ -1,89 +0,0 @@
|
|||||||
import dotenv from "dotenv";
|
|
||||||
|
|
||||||
import { initDbConnection } from "./src/db";
|
|
||||||
import { TableName } from "./src/db/schemas";
|
|
||||||
import { selectAllTableCols } from "./src/lib/knex";
|
|
||||||
import picomatch from "picomatch";
|
|
||||||
|
|
||||||
dotenv.config();
|
|
||||||
// const db = initDbConnection(process.env.DB_CONNECTION_URI);
|
|
||||||
|
|
||||||
// const main = async () => {
|
|
||||||
// const folders = db
|
|
||||||
// .withRecursive("parent", (qb) => {
|
|
||||||
// qb.select({
|
|
||||||
// depth: 1,
|
|
||||||
// path: db.raw("'/'")
|
|
||||||
// })
|
|
||||||
// .select(selectAllTableCols(db, TableName.SecretFolder))
|
|
||||||
// .from(TableName.SecretFolder)
|
|
||||||
// .join(
|
|
||||||
// TableName.Environment,
|
|
||||||
// `${TableName.SecretFolder}.envId`,
|
|
||||||
// `${TableName.Environment}.id`
|
|
||||||
// )
|
|
||||||
// .where({
|
|
||||||
// projectId: "01c10de1-8743-490f-9c8a-7a19c4dc72a9",
|
|
||||||
// parentId: null
|
|
||||||
// })
|
|
||||||
// .where(`${TableName.Environment}.slug`, "dev")
|
|
||||||
// .union((qb) =>
|
|
||||||
// qb
|
|
||||||
// .select({
|
|
||||||
// depth: db.raw("parent.depth + 1"),
|
|
||||||
// path: db.raw(
|
|
||||||
// "CONCAT((CASE WHEN parent.path = '/' THEN '' ELSE parent.path END),'/', secret_folders.name)"
|
|
||||||
// )
|
|
||||||
// })
|
|
||||||
// .select(selectAllTableCols(db, TableName.SecretFolder))
|
|
||||||
// .whereRaw(
|
|
||||||
// `depth = array_position(ARRAY[${[1, 2]
|
|
||||||
// .map((_) => "?")
|
|
||||||
// .join(",")}]::varchar[], secret_folders.name,depth)`,
|
|
||||||
// [...["ui", "design"]]
|
|
||||||
// )
|
|
||||||
// .from(TableName.SecretFolder)
|
|
||||||
// .join("parent", "parent.id", `${TableName.SecretFolder}.parentId`)
|
|
||||||
// );
|
|
||||||
// })
|
|
||||||
// .select("*")
|
|
||||||
// .from("parent")
|
|
||||||
// .orderBy("depth", "desc")
|
|
||||||
// .first();
|
|
||||||
// console.log(folders.toSQL());
|
|
||||||
// console.log(JSON.stringify(await folders, null, 4));
|
|
||||||
// process.exit(0);
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
const main = async () => {
|
|
||||||
const isMatch = picomatch("/ui/**/seomthing", { strictSlashes: false });
|
|
||||||
console.log(
|
|
||||||
picomatch.isMatch(
|
|
||||||
"/ui/(base|new)/seomthing",
|
|
||||||
["/ui/base/seomthing", "/ui/(base|new)/seomthing"],
|
|
||||||
{
|
|
||||||
strictSlashes: false
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
// console.log(isMatch("/ui/(base|new)/seomthing"));
|
|
||||||
// const folders = db(TableName.SecretVersion)
|
|
||||||
// .whereIn(`${TableName.SecretVersion}.secretId`, ["8fe1c5e2-af6a-40ed-874b-6738816236bc"])
|
|
||||||
// .join(
|
|
||||||
// db(TableName.SecretVersion)
|
|
||||||
// .groupBy("secretId")
|
|
||||||
// .max("version")
|
|
||||||
// .select("secretId")
|
|
||||||
// .as("latestVersion"),
|
|
||||||
// (bd) => {
|
|
||||||
// bd.on(`${TableName.SecretVersion}.secretId`, "latestVersion.secretId").andOn(
|
|
||||||
// `${TableName.SecretVersion}.version`,
|
|
||||||
// "latestVersion.max"
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
// console.log(folders.toSQL());
|
|
||||||
// console.log(JSON.stringify(await folders, null, 4));
|
|
||||||
// process.exit(0);
|
|
||||||
};
|
|
||||||
main();
|
|
||||||
Generated
+223
-18
@@ -18,6 +18,7 @@
|
|||||||
"@fastify/session": "^10.7.0",
|
"@fastify/session": "^10.7.0",
|
||||||
"@fastify/swagger": "^8.12.0",
|
"@fastify/swagger": "^8.12.0",
|
||||||
"@fastify/swagger-ui": "^1.10.1",
|
"@fastify/swagger-ui": "^1.10.1",
|
||||||
|
"@node-saml/passport-saml": "^4.0.4",
|
||||||
"@octokit/rest": "^20.0.2",
|
"@octokit/rest": "^20.0.2",
|
||||||
"@ucast/mongo2js": "^1.3.4",
|
"@ucast/mongo2js": "^1.3.4",
|
||||||
"ajv": "^8.12.0",
|
"ajv": "^8.12.0",
|
||||||
@@ -996,6 +997,64 @@
|
|||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/@node-saml/node-saml": {
|
||||||
|
"version": "4.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@node-saml/node-saml/-/node-saml-4.0.5.tgz",
|
||||||
|
"integrity": "sha512-J5DglElbY1tjOuaR1NPtjOXkXY5bpUhDoKVoeucYN98A3w4fwgjIOPqIGcb6cQsqFq2zZ6vTCeKn5C/hvefSaw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/debug": "^4.1.7",
|
||||||
|
"@types/passport": "^1.0.11",
|
||||||
|
"@types/xml-crypto": "^1.4.2",
|
||||||
|
"@types/xml-encryption": "^1.2.1",
|
||||||
|
"@types/xml2js": "^0.4.11",
|
||||||
|
"@xmldom/xmldom": "^0.8.6",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"xml-crypto": "^3.0.1",
|
||||||
|
"xml-encryption": "^3.0.2",
|
||||||
|
"xml2js": "^0.5.0",
|
||||||
|
"xmlbuilder": "^15.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@node-saml/node-saml/node_modules/debug": {
|
||||||
|
"version": "4.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
|
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "2.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@node-saml/node-saml/node_modules/ms": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
|
},
|
||||||
|
"node_modules/@node-saml/passport-saml": {
|
||||||
|
"version": "4.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@node-saml/passport-saml/-/passport-saml-4.0.4.tgz",
|
||||||
|
"integrity": "sha512-xFw3gw0yo+K1mzlkW15NeBF7cVpRHN/4vpjmBKzov5YFImCWh/G0LcTZ8krH3yk2/eRPc3Or8LRPudVJBjmYaw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@node-saml/node-saml": "^4.0.4",
|
||||||
|
"@types/express": "^4.17.14",
|
||||||
|
"@types/passport": "^1.0.11",
|
||||||
|
"@types/passport-strategy": "^0.2.35",
|
||||||
|
"passport": "^0.6.0",
|
||||||
|
"passport-strategy": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@nodelib/fs.scandir": {
|
"node_modules/@nodelib/fs.scandir": {
|
||||||
"version": "2.1.5",
|
"version": "2.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||||
@@ -1640,7 +1699,6 @@
|
|||||||
"version": "1.19.5",
|
"version": "1.19.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz",
|
||||||
"integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==",
|
"integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/connect": "*",
|
"@types/connect": "*",
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
@@ -1650,16 +1708,22 @@
|
|||||||
"version": "3.4.38",
|
"version": "3.4.38",
|
||||||
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
|
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
|
||||||
"integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
|
"integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/debug": {
|
||||||
|
"version": "4.1.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz",
|
||||||
|
"integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/ms": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/express": {
|
"node_modules/@types/express": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz",
|
||||||
"integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==",
|
"integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/body-parser": "*",
|
"@types/body-parser": "*",
|
||||||
"@types/express-serve-static-core": "^4.17.33",
|
"@types/express-serve-static-core": "^4.17.33",
|
||||||
@@ -1671,7 +1735,6 @@
|
|||||||
"version": "4.17.41",
|
"version": "4.17.41",
|
||||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz",
|
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz",
|
||||||
"integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==",
|
"integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"@types/qs": "*",
|
"@types/qs": "*",
|
||||||
@@ -1682,8 +1745,7 @@
|
|||||||
"node_modules/@types/http-errors": {
|
"node_modules/@types/http-errors": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz",
|
||||||
"integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==",
|
"integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/jmespath": {
|
"node_modules/@types/jmespath": {
|
||||||
"version": "0.15.2",
|
"version": "0.15.2",
|
||||||
@@ -1719,14 +1781,17 @@
|
|||||||
"node_modules/@types/mime": {
|
"node_modules/@types/mime": {
|
||||||
"version": "1.3.5",
|
"version": "1.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
|
||||||
"integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
|
"integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w=="
|
||||||
"dev": true
|
},
|
||||||
|
"node_modules/@types/ms": {
|
||||||
|
"version": "0.7.34",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz",
|
||||||
|
"integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g=="
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.9.5",
|
"version": "20.9.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.5.tgz",
|
||||||
"integrity": "sha512-Uq2xbNq0chGg+/WQEU0LJTSs/1nKxz6u1iemLcGomkSnKokbW1fbLqc3HOqCf2JP7KjlL4QkS7oZZTrOQHQYgQ==",
|
"integrity": "sha512-Uq2xbNq0chGg+/WQEU0LJTSs/1nKxz6u1iemLcGomkSnKokbW1fbLqc3HOqCf2JP7KjlL4QkS7oZZTrOQHQYgQ==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~5.26.4"
|
"undici-types": "~5.26.4"
|
||||||
}
|
}
|
||||||
@@ -1753,7 +1818,6 @@
|
|||||||
"version": "1.0.16",
|
"version": "1.0.16",
|
||||||
"resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.16.tgz",
|
"resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.16.tgz",
|
||||||
"integrity": "sha512-FD0qD5hbPWQzaM0wHUnJ/T0BBCJBxCeemtnCwc/ThhTg3x9jfrAcRUmj5Dopza+MfFS9acTe3wk7rcVnRIp/0A==",
|
"integrity": "sha512-FD0qD5hbPWQzaM0wHUnJ/T0BBCJBxCeemtnCwc/ThhTg3x9jfrAcRUmj5Dopza+MfFS9acTe3wk7rcVnRIp/0A==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/express": "*"
|
"@types/express": "*"
|
||||||
}
|
}
|
||||||
@@ -1791,6 +1855,15 @@
|
|||||||
"@types/passport": "*"
|
"@types/passport": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/passport-strategy": {
|
||||||
|
"version": "0.2.38",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.38.tgz",
|
||||||
|
"integrity": "sha512-GC6eMqqojOooq993Tmnmp7AUTbbQSgilyvpCYQjT+H6JfG/g6RGc7nXEniZlp0zyKJ0WUdOiZWLBZft9Yug1uA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/express": "*",
|
||||||
|
"@types/passport": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/pg": {
|
"node_modules/@types/pg": {
|
||||||
"version": "8.10.9",
|
"version": "8.10.9",
|
||||||
"resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.10.9.tgz",
|
"resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.10.9.tgz",
|
||||||
@@ -1874,14 +1947,12 @@
|
|||||||
"node_modules/@types/qs": {
|
"node_modules/@types/qs": {
|
||||||
"version": "6.9.10",
|
"version": "6.9.10",
|
||||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz",
|
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz",
|
||||||
"integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==",
|
"integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/range-parser": {
|
"node_modules/@types/range-parser": {
|
||||||
"version": "1.2.7",
|
"version": "1.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
|
||||||
"integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
|
"integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/semver": {
|
"node_modules/@types/semver": {
|
||||||
"version": "7.5.6",
|
"version": "7.5.6",
|
||||||
@@ -1892,7 +1963,6 @@
|
|||||||
"version": "0.17.4",
|
"version": "0.17.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz",
|
||||||
"integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==",
|
"integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/mime": "^1",
|
"@types/mime": "^1",
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
@@ -1902,13 +1972,37 @@
|
|||||||
"version": "1.15.5",
|
"version": "1.15.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz",
|
||||||
"integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==",
|
"integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/http-errors": "*",
|
"@types/http-errors": "*",
|
||||||
"@types/mime": "*",
|
"@types/mime": "*",
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/xml-crypto": {
|
||||||
|
"version": "1.4.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/xml-crypto/-/xml-crypto-1.4.6.tgz",
|
||||||
|
"integrity": "sha512-A6jEW2FxLZo1CXsRWnZHUX2wzR3uDju2Bozt6rDbSmU/W8gkilaVbwFEVN0/NhnUdMVzwYobWtM6bU1QJJFb7Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*",
|
||||||
|
"xpath": "0.0.27"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/xml-encryption": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/xml-encryption/-/xml-encryption-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-I69K/WW1Dv7j6O3jh13z0X8sLWJRXbu5xnHDl9yHzUNDUBtUoBY058eb5s+x/WG6yZC1h8aKdI2EoyEPjyEh+Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/xml2js": {
|
||||||
|
"version": "0.4.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.14.tgz",
|
||||||
|
"integrity": "sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "6.13.2",
|
"version": "6.13.2",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.13.2.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.13.2.tgz",
|
||||||
@@ -2305,6 +2399,14 @@
|
|||||||
"url": "https://opencollective.com/vitest"
|
"url": "https://opencollective.com/vitest"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@xmldom/xmldom": {
|
||||||
|
"version": "0.8.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
|
||||||
|
"integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/abbrev": {
|
"node_modules/abbrev": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||||
@@ -6699,6 +6801,23 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/passport": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/passport/-/passport-0.6.0.tgz",
|
||||||
|
"integrity": "sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug==",
|
||||||
|
"dependencies": {
|
||||||
|
"passport-strategy": "1.x.x",
|
||||||
|
"pause": "0.0.1",
|
||||||
|
"utils-merge": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/jaredhanson"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/passport-github": {
|
"node_modules/passport-github": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/passport-github/-/passport-github-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/passport-github/-/passport-github-1.1.0.tgz",
|
||||||
@@ -6836,6 +6955,11 @@
|
|||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/pause": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
|
||||||
|
"integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg=="
|
||||||
|
},
|
||||||
"node_modules/pg": {
|
"node_modules/pg": {
|
||||||
"version": "8.11.3",
|
"version": "8.11.3",
|
||||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz",
|
"resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz",
|
||||||
@@ -7781,6 +7905,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/sax": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA=="
|
||||||
|
},
|
||||||
"node_modules/secure-json-parse": {
|
"node_modules/secure-json-parse": {
|
||||||
"version": "2.7.0",
|
"version": "2.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz",
|
||||||
@@ -9295,8 +9424,7 @@
|
|||||||
"node_modules/undici-types": {
|
"node_modules/undici-types": {
|
||||||
"version": "5.26.5",
|
"version": "5.26.5",
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/universal-user-agent": {
|
"node_modules/universal-user-agent": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
@@ -10297,6 +10425,83 @@
|
|||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/xml-crypto": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/xml-crypto/-/xml-crypto-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-qVurBUOQrmvlgmZqIVBqmb06TD2a/PpEUfFPgD7BuBfjmoH4zgkqaWSIJrnymlCvM2GGt9x+XtJFA+ttoAufqg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@xmldom/xmldom": "^0.8.8",
|
||||||
|
"xpath": "0.0.32"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/xml-crypto/node_modules/xpath": {
|
||||||
|
"version": "0.0.32",
|
||||||
|
"resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.32.tgz",
|
||||||
|
"integrity": "sha512-rxMJhSIoiO8vXcWvSifKqhvV96GjiD5wYb8/QHdoRyQvraTpp4IEv944nhGausZZ3u7dhQXteZuZbaqfpB7uYw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/xml-encryption": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/xml-encryption/-/xml-encryption-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-VxYXPvsWB01/aqVLd6ZMPWZ+qaj0aIdF+cStrVJMcFj3iymwZeI0ABzB3VqMYv48DkSpRhnrXqTUkR34j+UDyg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@xmldom/xmldom": "^0.8.5",
|
||||||
|
"escape-html": "^1.0.3",
|
||||||
|
"xpath": "0.0.32"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/xml-encryption/node_modules/xpath": {
|
||||||
|
"version": "0.0.32",
|
||||||
|
"resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.32.tgz",
|
||||||
|
"integrity": "sha512-rxMJhSIoiO8vXcWvSifKqhvV96GjiD5wYb8/QHdoRyQvraTpp4IEv944nhGausZZ3u7dhQXteZuZbaqfpB7uYw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/xml2js": {
|
||||||
|
"version": "0.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz",
|
||||||
|
"integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==",
|
||||||
|
"dependencies": {
|
||||||
|
"sax": ">=0.6.0",
|
||||||
|
"xmlbuilder": "~11.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/xml2js/node_modules/xmlbuilder": {
|
||||||
|
"version": "11.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
|
||||||
|
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/xmlbuilder": {
|
||||||
|
"version": "15.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz",
|
||||||
|
"integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/xpath": {
|
||||||
|
"version": "0.0.27",
|
||||||
|
"resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.27.tgz",
|
||||||
|
"integrity": "sha512-fg03WRxtkCV6ohClePNAECYsmpKKTv5L8y/X3Dn1hQrec3POx2jHZ/0P2qQ6HvsrU1BmeqXcof3NGGueG6LxwQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/xtend": {
|
"node_modules/xtend": {
|
||||||
"version": "4.0.2",
|
"version": "4.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||||
|
|||||||
@@ -72,6 +72,7 @@
|
|||||||
"@fastify/session": "^10.7.0",
|
"@fastify/session": "^10.7.0",
|
||||||
"@fastify/swagger": "^8.12.0",
|
"@fastify/swagger": "^8.12.0",
|
||||||
"@fastify/swagger-ui": "^1.10.1",
|
"@fastify/swagger-ui": "^1.10.1",
|
||||||
|
"@node-saml/passport-saml": "^4.0.4",
|
||||||
"@octokit/rest": "^20.0.2",
|
"@octokit/rest": "^20.0.2",
|
||||||
"@ucast/mongo2js": "^1.3.4",
|
"@ucast/mongo2js": "^1.3.4",
|
||||||
"ajv": "^8.12.0",
|
"ajv": "^8.12.0",
|
||||||
|
|||||||
Vendored
+7
@@ -1,7 +1,10 @@
|
|||||||
import "fastify";
|
import "fastify";
|
||||||
|
|
||||||
import { TUsers } from "@app/db/schemas";
|
import { TUsers } from "@app/db/schemas";
|
||||||
|
import { TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-service";
|
||||||
|
import { TCreateAuditLogDTO } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||||
|
import { TSamlConfigServiceFactory } from "@app/ee/services/saml-config/saml-config-service";
|
||||||
import { TSecretApprovalPolicyServiceFactory } from "@app/ee/services/secret-approval-policy/secret-approval-policy-service";
|
import { TSecretApprovalPolicyServiceFactory } from "@app/ee/services/secret-approval-policy/secret-approval-policy-service";
|
||||||
import { TSecretApprovalRequestServiceFactory } from "@app/ee/services/secret-approval-request/secret-approval-request-service";
|
import { TSecretApprovalRequestServiceFactory } from "@app/ee/services/secret-approval-request/secret-approval-request-service";
|
||||||
import { TSecretRotationServiceFactory } from "@app/ee/services/secret-rotation/secret-rotation-service";
|
import { TSecretRotationServiceFactory } from "@app/ee/services/secret-rotation/secret-rotation-service";
|
||||||
@@ -62,6 +65,8 @@ declare module "fastify" {
|
|||||||
isCompleted: string;
|
isCompleted: string;
|
||||||
providerAuthToken: string;
|
providerAuthToken: string;
|
||||||
};
|
};
|
||||||
|
auditLogInfo: Pick<TCreateAuditLogDTO, "userAgent" | "userAgentType" | "ipAddress" | "actor">;
|
||||||
|
ssoConfig: Awaited<ReturnType<TSamlConfigServiceFactory["getSaml"]>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FastifyInstance {
|
interface FastifyInstance {
|
||||||
@@ -98,6 +103,8 @@ declare module "fastify" {
|
|||||||
secretApprovalRequest: TSecretApprovalRequestServiceFactory;
|
secretApprovalRequest: TSecretApprovalRequestServiceFactory;
|
||||||
secretRotation: TSecretRotationServiceFactory;
|
secretRotation: TSecretRotationServiceFactory;
|
||||||
snapshot: TSecretSnapshotServiceFactory;
|
snapshot: TSecretSnapshotServiceFactory;
|
||||||
|
saml: TSamlConfigServiceFactory;
|
||||||
|
auditLog: TAuditLogServiceFactory;
|
||||||
};
|
};
|
||||||
|
|
||||||
// this is exclusive use for middlewares in which we need to inject data
|
// this is exclusive use for middlewares in which we need to inject data
|
||||||
|
|||||||
Vendored
+16
@@ -5,6 +5,9 @@ import {
|
|||||||
TApiKeys,
|
TApiKeys,
|
||||||
TApiKeysInsert,
|
TApiKeysInsert,
|
||||||
TApiKeysUpdate,
|
TApiKeysUpdate,
|
||||||
|
TAuditLogs,
|
||||||
|
TAuditLogsInsert,
|
||||||
|
TAuditLogsUpdate,
|
||||||
TAuthTokens,
|
TAuthTokens,
|
||||||
TAuthTokenSessions,
|
TAuthTokenSessions,
|
||||||
TAuthTokenSessionsInsert,
|
TAuthTokenSessionsInsert,
|
||||||
@@ -43,6 +46,9 @@ import {
|
|||||||
TOrganizations,
|
TOrganizations,
|
||||||
TOrganizationsInsert,
|
TOrganizationsInsert,
|
||||||
TOrganizationsUpdate,
|
TOrganizationsUpdate,
|
||||||
|
TOrgBots,
|
||||||
|
TOrgBotsInsert,
|
||||||
|
TOrgBotsUpdate,
|
||||||
TOrgMemberships,
|
TOrgMemberships,
|
||||||
TOrgMembershipsInsert,
|
TOrgMembershipsInsert,
|
||||||
TOrgMembershipsUpdate,
|
TOrgMembershipsUpdate,
|
||||||
@@ -67,6 +73,9 @@ import {
|
|||||||
TProjects,
|
TProjects,
|
||||||
TProjectsInsert,
|
TProjectsInsert,
|
||||||
TProjectsUpdate,
|
TProjectsUpdate,
|
||||||
|
TSamlConfigs,
|
||||||
|
TSamlConfigsInsert,
|
||||||
|
TSamlConfigsUpdate,
|
||||||
TSapApprovers,
|
TSapApprovers,
|
||||||
TSapApproversInsert,
|
TSapApproversInsert,
|
||||||
TSapApproversUpdate,
|
TSapApproversUpdate,
|
||||||
@@ -357,6 +366,13 @@ declare module "knex/types/tables" {
|
|||||||
TSecretSnapshotFoldersInsert,
|
TSecretSnapshotFoldersInsert,
|
||||||
TSecretSnapshotFoldersUpdate
|
TSecretSnapshotFoldersUpdate
|
||||||
>;
|
>;
|
||||||
|
[TableName.SamlConfig]: Knex.CompositeTableType<
|
||||||
|
TSamlConfigs,
|
||||||
|
TSamlConfigsInsert,
|
||||||
|
TSamlConfigsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.OrgBot]: Knex.CompositeTableType<TOrgBots, TOrgBotsInsert, TOrgBotsUpdate>;
|
||||||
|
[TableName.AuditLog]: Knex.CompositeTableType<TAuditLogs, TAuditLogsInsert, TAuditLogsUpdate>;
|
||||||
// Junction tables
|
// Junction tables
|
||||||
[TableName.JnSecretTag]: Knex.CompositeTableType<
|
[TableName.JnSecretTag]: Knex.CompositeTableType<
|
||||||
TSecretTagJunction,
|
TSecretTagJunction,
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
if (!(await knex.schema.hasTable(TableName.Secret))) {
|
if (!(await knex.schema.hasTable(TableName.Secret))) {
|
||||||
await knex.schema.createTable(TableName.Secret, (t) => {
|
await knex.schema.createTable(TableName.Secret, (t) => {
|
||||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
t.integer("version").defaultTo(1);
|
t.integer("version").defaultTo(1).notNullable();
|
||||||
t.string("type").notNullable().defaultTo(SecretType.Shared);
|
t.string("type").notNullable().defaultTo(SecretType.Shared);
|
||||||
// t.text("secretKeyHash").notNullable();
|
// t.text("secretKeyHash").notNullable();
|
||||||
// t.text("secretValueHash");
|
// t.text("secretValueHash");
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
if (!(await knex.schema.hasTable(TableName.SecretVersion))) {
|
if (!(await knex.schema.hasTable(TableName.SecretVersion))) {
|
||||||
await knex.schema.createTable(TableName.SecretVersion, (t) => {
|
await knex.schema.createTable(TableName.SecretVersion, (t) => {
|
||||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
t.integer("version").defaultTo(1);
|
t.integer("version").defaultTo(1).notNullable();
|
||||||
t.string("type").notNullable().defaultTo(SecretType.Shared);
|
t.string("type").notNullable().defaultTo(SecretType.Shared);
|
||||||
t.text("secretBlindIndex").notNullable();
|
t.text("secretBlindIndex").notNullable();
|
||||||
t.text("secretKeyCiphertext").notNullable();
|
t.text("secretKeyCiphertext").notNullable();
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SamlConfig))) {
|
||||||
|
await knex.schema.createTable(TableName.SamlConfig, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("authProvider").notNullable();
|
||||||
|
t.boolean("isActive").notNullable();
|
||||||
|
t.string("encryptedEntryPoint");
|
||||||
|
t.string("entryPointIV");
|
||||||
|
t.string("entryPointTag");
|
||||||
|
t.string("encryptedIssuer");
|
||||||
|
t.string("issuerTag");
|
||||||
|
t.string("issuerIV");
|
||||||
|
t.string("encryptedCert");
|
||||||
|
t.string("certIV");
|
||||||
|
t.string("certTag");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.uuid("orgId").notNullable().unique();
|
||||||
|
t.foreign("orgId").references("id").inTable(TableName.Organization);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await createOnUpdateTrigger(knex, TableName.SamlConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SamlConfig);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.SamlConfig);
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.OrgBot))) {
|
||||||
|
await knex.schema.createTable(TableName.OrgBot, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("name").notNullable();
|
||||||
|
t.text("publicKey").notNullable();
|
||||||
|
t.text("encryptedSymmetricKey").notNullable();
|
||||||
|
t.text("symmetricKeyIV").notNullable();
|
||||||
|
t.text("symmetricKeyTag").notNullable();
|
||||||
|
t.string("symmetricKeyAlgorithm").notNullable();
|
||||||
|
t.string("symmetricKeyKeyEncoding").notNullable();
|
||||||
|
t.text("encryptedPrivateKey").notNullable();
|
||||||
|
t.text("privateKeyIV").notNullable();
|
||||||
|
t.text("privateKeyTag").notNullable();
|
||||||
|
t.string("privateKeyAlgorithm").notNullable();
|
||||||
|
t.string("privateKeyKeyEncoding").notNullable();
|
||||||
|
// one to one relationship
|
||||||
|
t.uuid("orgId").notNullable().unique();
|
||||||
|
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await createOnUpdateTrigger(knex, TableName.OrgBot);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.OrgBot);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.OrgBot);
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.AuditLog))) {
|
||||||
|
await knex.schema.createTable(TableName.AuditLog, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("actor").notNullable();
|
||||||
|
t.jsonb("actorMetadata").notNullable();
|
||||||
|
t.string("ipAddress");
|
||||||
|
t.string("eventType").notNullable();
|
||||||
|
t.jsonb("eventMetadata");
|
||||||
|
t.string("userAgent");
|
||||||
|
t.string("userAgentType");
|
||||||
|
t.datetime("expiresAt");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
// no trigger needed as this collection is append only
|
||||||
|
t.uuid("orgId");
|
||||||
|
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
|
t.uuid("projectId");
|
||||||
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.AuditLog);
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// Code generated by automation script, DO NOT EDIT.
|
||||||
|
// Automated by pulling database and generating zod schema
|
||||||
|
// To update. Just run npm run generate:schema
|
||||||
|
// Written by akhilmhdh.
|
||||||
|
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { TImmutableDBKeys } from "./models";
|
||||||
|
|
||||||
|
export const AuditLogsSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
actor: z.string(),
|
||||||
|
actorMetadata: z.unknown(),
|
||||||
|
ipAddress: z.string().nullable().optional(),
|
||||||
|
eventType: z.string(),
|
||||||
|
eventMetadata: z.unknown().nullable().optional(),
|
||||||
|
userAgent: z.string().nullable().optional(),
|
||||||
|
userAgentType: z.string().nullable().optional(),
|
||||||
|
expiresAt: z.date().nullable().optional(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date(),
|
||||||
|
orgId: z.string().uuid().nullable().optional(),
|
||||||
|
projectId: z.string().uuid().nullable().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TAuditLogs = z.infer<typeof AuditLogsSchema>;
|
||||||
|
export type TAuditLogsInsert = Omit<TAuditLogs, TImmutableDBKeys>;
|
||||||
|
export type TAuditLogsUpdate = Partial<Omit<TAuditLogs, TImmutableDBKeys>>;
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
export * from "./api-keys";
|
export * from "./api-keys";
|
||||||
|
export * from "./audit-logs";
|
||||||
export * from "./auth-token-sessions";
|
export * from "./auth-token-sessions";
|
||||||
export * from "./auth-tokens";
|
export * from "./auth-tokens";
|
||||||
export * from "./backup-private-key";
|
export * from "./backup-private-key";
|
||||||
@@ -12,6 +13,7 @@ export * from "./incident-contacts";
|
|||||||
export * from "./integration-auths";
|
export * from "./integration-auths";
|
||||||
export * from "./integrations";
|
export * from "./integrations";
|
||||||
export * from "./models";
|
export * from "./models";
|
||||||
|
export * from "./org-bots";
|
||||||
export * from "./org-memberships";
|
export * from "./org-memberships";
|
||||||
export * from "./org-roles";
|
export * from "./org-roles";
|
||||||
export * from "./organizations";
|
export * from "./organizations";
|
||||||
@@ -23,6 +25,7 @@ export * from "./project-roles";
|
|||||||
export * from "./projects";
|
export * from "./projects";
|
||||||
export * from "./sa-request-secret-tags";
|
export * from "./sa-request-secret-tags";
|
||||||
export * from "./sa-request-secrets";
|
export * from "./sa-request-secrets";
|
||||||
|
export * from "./saml-configs";
|
||||||
export * from "./sap-approvers";
|
export * from "./sap-approvers";
|
||||||
export * from "./sar-reviewers";
|
export * from "./sar-reviewers";
|
||||||
export * from "./secret-approval-policies";
|
export * from "./secret-approval-policies";
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export enum TableName {
|
|||||||
Organization = "organizations",
|
Organization = "organizations",
|
||||||
OrgMembership = "org_memberships",
|
OrgMembership = "org_memberships",
|
||||||
OrgRoles = "org_roles",
|
OrgRoles = "org_roles",
|
||||||
|
OrgBot = "org_bots",
|
||||||
IncidentContact = "incident_contacts",
|
IncidentContact = "incident_contacts",
|
||||||
UserAction = "user_actions",
|
UserAction = "user_actions",
|
||||||
SuperAdmin = "super_admin",
|
SuperAdmin = "super_admin",
|
||||||
@@ -47,6 +48,8 @@ export enum TableName {
|
|||||||
SarSecretTag = "sa_request_secret_tags",
|
SarSecretTag = "sa_request_secret_tags",
|
||||||
SecretRotation = "secret_rotations",
|
SecretRotation = "secret_rotations",
|
||||||
SecretRotationOutput = "secret_rotation_outputs",
|
SecretRotationOutput = "secret_rotation_outputs",
|
||||||
|
SamlConfig = "saml_configs",
|
||||||
|
AuditLog = "audit_logs",
|
||||||
// junction tables
|
// junction tables
|
||||||
JnSecretTag = "secret_tag_junction",
|
JnSecretTag = "secret_tag_junction",
|
||||||
JnSecretVersionTag = "secret_version_tag_junction"
|
JnSecretVersionTag = "secret_version_tag_junction"
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// Code generated by automation script, DO NOT EDIT.
|
||||||
|
// Automated by pulling database and generating zod schema
|
||||||
|
// To update. Just run npm run generate:schema
|
||||||
|
// Written by akhilmhdh.
|
||||||
|
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { TImmutableDBKeys } from "./models";
|
||||||
|
|
||||||
|
export const OrgBotsSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
name: z.string(),
|
||||||
|
publicKey: z.string(),
|
||||||
|
encryptedSymmetricKey: z.string(),
|
||||||
|
symmetricKeyIV: z.string(),
|
||||||
|
symmetricKeyTag: z.string(),
|
||||||
|
symmetricKeyAlgorithm: z.string(),
|
||||||
|
symmetricKeyKeyEncoding: z.string(),
|
||||||
|
encryptedPrivateKey: z.string(),
|
||||||
|
privateKeyIV: z.string(),
|
||||||
|
privateKeyTag: z.string(),
|
||||||
|
privateKeyAlgorithm: z.string(),
|
||||||
|
privateKeyKeyEncoding: z.string(),
|
||||||
|
orgId: z.string().uuid(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TOrgBots = z.infer<typeof OrgBotsSchema>;
|
||||||
|
export type TOrgBotsInsert = Omit<TOrgBots, TImmutableDBKeys>;
|
||||||
|
export type TOrgBotsUpdate = Partial<Omit<TOrgBots, TImmutableDBKeys>>;
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
// Code generated by automation script, DO NOT EDIT.
|
||||||
|
// Automated by pulling database and generating zod schema
|
||||||
|
// To update. Just run npm run generate:schema
|
||||||
|
// Written by akhilmhdh.
|
||||||
|
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { TImmutableDBKeys } from "./models";
|
||||||
|
|
||||||
|
export const SamlConfigsSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
authProvider: z.string(),
|
||||||
|
isActive: z.boolean(),
|
||||||
|
encryptedEntryPoint: z.string().nullable().optional(),
|
||||||
|
entryPointIV: z.string().nullable().optional(),
|
||||||
|
entryPointTag: z.string().nullable().optional(),
|
||||||
|
encryptedIssuer: z.string().nullable().optional(),
|
||||||
|
issuerTag: z.string().nullable().optional(),
|
||||||
|
issuerIV: z.string().nullable().optional(),
|
||||||
|
encryptedCert: z.string().nullable().optional(),
|
||||||
|
certIV: z.string().nullable().optional(),
|
||||||
|
certTag: z.string().nullable().optional(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date(),
|
||||||
|
orgId: z.string().uuid(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TSamlConfigs = z.infer<typeof SamlConfigsSchema>;
|
||||||
|
export type TSamlConfigsInsert = Omit<TSamlConfigs, TImmutableDBKeys>;
|
||||||
|
export type TSamlConfigsUpdate = Partial<Omit<TSamlConfigs, TImmutableDBKeys>>;
|
||||||
@@ -9,7 +9,7 @@ import { TImmutableDBKeys } from "./models";
|
|||||||
|
|
||||||
export const SecretVersionsSchema = z.object({
|
export const SecretVersionsSchema = z.object({
|
||||||
id: z.string().uuid(),
|
id: z.string().uuid(),
|
||||||
version: z.number().default(1).nullable().optional(),
|
version: z.number().default(1),
|
||||||
type: z.string().default("shared"),
|
type: z.string().default("shared"),
|
||||||
secretBlindIndex: z.string(),
|
secretBlindIndex: z.string(),
|
||||||
secretKeyCiphertext: z.string(),
|
secretKeyCiphertext: z.string(),
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { TImmutableDBKeys } from "./models";
|
|||||||
|
|
||||||
export const SecretsSchema = z.object({
|
export const SecretsSchema = z.object({
|
||||||
id: z.string().uuid(),
|
id: z.string().uuid(),
|
||||||
version: z.number().default(1).nullable().optional(),
|
version: z.number().default(1),
|
||||||
type: z.string().default("shared"),
|
type: z.string().default("shared"),
|
||||||
secretBlindIndex: z.string(),
|
secretBlindIndex: z.string(),
|
||||||
secretKeyCiphertext: z.string(),
|
secretKeyCiphertext: z.string(),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { registerOrgRoleRouter } from "./org-role-router";
|
import { registerOrgRoleRouter } from "./org-role-router";
|
||||||
import { registerProjectRoleRouter } from "./project-role-router";
|
import { registerProjectRoleRouter } from "./project-role-router";
|
||||||
import { registerProjectRouter } from "./project-router";
|
import { registerProjectRouter } from "./project-router";
|
||||||
|
import { registerSamlRouter } from "./saml-router";
|
||||||
import { registerSecretApprovalPolicyRouter } from "./secret-approval-policy-router";
|
import { registerSecretApprovalPolicyRouter } from "./secret-approval-policy-router";
|
||||||
import { registerSecretApprovalRequestRouter } from "./secret-approval-request-router";
|
import { registerSecretApprovalRequestRouter } from "./secret-approval-request-router";
|
||||||
import { registerSecretRotationProviderRouter } from "./secret-rotation-provider-router";
|
import { registerSecretRotationProviderRouter } from "./secret-rotation-provider-router";
|
||||||
@@ -25,5 +26,6 @@ export const registerV1EERoutes = async (server: FastifyZodProvider) => {
|
|||||||
await server.register(registerSecretRotationProviderRouter, {
|
await server.register(registerSecretRotationProviderRouter, {
|
||||||
prefix: "/secret-rotation-providers"
|
prefix: "/secret-rotation-providers"
|
||||||
});
|
});
|
||||||
|
await server.register(registerSamlRouter, { prefix: "/sso" });
|
||||||
await server.register(registerSecretRotationRouter, { prefix: "/secret-rotations" });
|
await server.register(registerSecretRotationRouter, { prefix: "/secret-rotations" });
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { SecretSnapshotsSchema } from "@app/db/schemas";
|
import { AuditLogsSchema, SecretSnapshotsSchema } from "@app/db/schemas";
|
||||||
|
import { EventType, UserAgentType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
@@ -65,4 +66,74 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
|||||||
return { count };
|
return { count };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/:workspaceId/audit-logs",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
workspaceId: z.string().trim()
|
||||||
|
}),
|
||||||
|
querystring: z.object({
|
||||||
|
eventType: z.nativeEnum(EventType).optional(),
|
||||||
|
userAgentType: z.nativeEnum(UserAgentType).optional(),
|
||||||
|
startDate: z.string().datetime().optional(),
|
||||||
|
endDate: z.string().datetime().optional(),
|
||||||
|
offset: z.coerce.number().default(0),
|
||||||
|
limit: z.coerce.number().default(20),
|
||||||
|
actor: z.string().optional()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
auditLogs: AuditLogsSchema.omit({
|
||||||
|
eventMetadata: true,
|
||||||
|
eventType: true,
|
||||||
|
actor: true,
|
||||||
|
actorMetadata: true
|
||||||
|
})
|
||||||
|
.merge(
|
||||||
|
z.object({
|
||||||
|
event: z.object({
|
||||||
|
type: z.string(),
|
||||||
|
metadata: z.any()
|
||||||
|
}),
|
||||||
|
actor: z.object({
|
||||||
|
type: z.string(),
|
||||||
|
metadata: z.any()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.array()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const auditLogs = await server.services.auditLog.listProjectAuditLogs({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
projectId: req.params.workspaceId,
|
||||||
|
...req.query,
|
||||||
|
auditLogActor: req.query.actor,
|
||||||
|
actor: req.permission.type
|
||||||
|
});
|
||||||
|
return { auditLogs };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/:workspaceId/audit-logs/filters/actors",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
workspaceId: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
actors: z.string().array()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async () => ({ actors: [] })
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,237 @@
|
|||||||
|
import { Authenticator } from "@fastify/passport";
|
||||||
|
import fastifySession from "@fastify/session";
|
||||||
|
import { MultiSamlStrategy } from "@node-saml/passport-saml";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { SamlConfigsSchema } from "@app/db/schemas";
|
||||||
|
import { SamlProviders } from "@app/ee/services/saml-config/saml-config-types";
|
||||||
|
import { getConfig } from "@app/lib/config/env";
|
||||||
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
|
type TSAMLConfig = {
|
||||||
|
callbackUrl: string;
|
||||||
|
entryPoint: string;
|
||||||
|
issuer: string;
|
||||||
|
cert: string;
|
||||||
|
audience: string;
|
||||||
|
wantAuthnResponseSigned?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const registerSamlRouter = async (server: FastifyZodProvider) => {
|
||||||
|
const appCfg = getConfig();
|
||||||
|
const passport = new Authenticator({ key: "saml", userProperty: "passportUser" });
|
||||||
|
await server.register(fastifySession, { secret: appCfg.COOKIE_SECRET_SIGN_KEY });
|
||||||
|
await server.register(passport.initialize());
|
||||||
|
await server.register(passport.secureSession());
|
||||||
|
server.decorateRequest("ssoConfig", null);
|
||||||
|
passport.use(
|
||||||
|
new MultiSamlStrategy(
|
||||||
|
{
|
||||||
|
passReqToCallback: true,
|
||||||
|
getSamlOptions: async (req, done) => {
|
||||||
|
const { ssoIdentifier } = req.params;
|
||||||
|
if (!ssoIdentifier) throw new BadRequestError({ message: "Missing sso identitier" });
|
||||||
|
|
||||||
|
const ssoConfig = await server.services.saml.getSaml({
|
||||||
|
type: "ssoId",
|
||||||
|
id: ssoIdentifier
|
||||||
|
});
|
||||||
|
if (!ssoConfig) throw new BadRequestError({ message: "SSO config not found" });
|
||||||
|
|
||||||
|
const samlConfig: TSAMLConfig = {
|
||||||
|
callbackUrl: `${appCfg.SITE_URL}/api/v1/sso/saml2/${ssoIdentifier}`,
|
||||||
|
entryPoint: ssoConfig.entryPoint,
|
||||||
|
issuer: ssoConfig.issuer,
|
||||||
|
cert: ssoConfig.cert,
|
||||||
|
audience: appCfg.SITE_URL || ""
|
||||||
|
};
|
||||||
|
if (ssoConfig.authProvider === SamlProviders.JUMPCLOUD_SAML) {
|
||||||
|
samlConfig.wantAuthnResponseSigned = false;
|
||||||
|
}
|
||||||
|
if (ssoConfig.authProvider === SamlProviders.AZURE_SAML) {
|
||||||
|
if (req.body.RelayState && JSON.parse(req.body.RelayState).spIntiaited) {
|
||||||
|
samlConfig.audience = `spn:${ssoConfig.issuer}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req.ssoConfig = ssoConfig;
|
||||||
|
done(null, samlConfig);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async (req, profile, cb) => {
|
||||||
|
console.log(req.ssoConfig);
|
||||||
|
console.log(profile);
|
||||||
|
try {
|
||||||
|
const serverCfg = server.services.superAdmin.getServerCfg();
|
||||||
|
if (!profile) throw new BadRequestError({ message: "Missing profile" });
|
||||||
|
const { email, firstName } = profile;
|
||||||
|
if (!email || !firstName)
|
||||||
|
throw new BadRequestError({ message: "Invalid request. Missing email or first name" });
|
||||||
|
|
||||||
|
const { isUserCompleted, providerAuthToken } = await server.services.saml.samlLogin({
|
||||||
|
email,
|
||||||
|
firstName: profile.firstName as string,
|
||||||
|
lastName: profile.lastName as string,
|
||||||
|
isSignupAllowed: Boolean(serverCfg.allowSignUp),
|
||||||
|
relayState: (req.body as { RelayState?: string }).RelayState,
|
||||||
|
authProvider: req.ssoConfig.authProvider,
|
||||||
|
orgId: req.ssoConfig.orgId
|
||||||
|
});
|
||||||
|
cb(null, { isUserCompleted, providerAuthToken });
|
||||||
|
} catch (error) {
|
||||||
|
cb(null, {});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
() => {}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/redirect/saml2/:ssoIdentifier",
|
||||||
|
method: "GET",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
ssoIdentifier: z.string().trim()
|
||||||
|
}),
|
||||||
|
querystring: z.object({
|
||||||
|
callback_port: z.string().optional()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
preValidation: (req, res) =>
|
||||||
|
(
|
||||||
|
passport.authenticate("saml", {
|
||||||
|
failureRedirect: "/",
|
||||||
|
additionalParams: {
|
||||||
|
RelayState: JSON.stringify({
|
||||||
|
spInitiated: true,
|
||||||
|
callbackPort: req.query.callback_port ?? ""
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} as any) as any
|
||||||
|
)(req, res),
|
||||||
|
handler: () => {}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/saml2/:ssoIdentifier",
|
||||||
|
method: "GET",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
ssoIdentifier: z.string().trim()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
preValidation: passport.authenticate("saml", {
|
||||||
|
session: false,
|
||||||
|
failureFlash: true,
|
||||||
|
failureRedirect: "/login/provider/error"
|
||||||
|
// this is due to zod type difference
|
||||||
|
}) as any,
|
||||||
|
handler: (req, res) => {
|
||||||
|
if (req.passportUser.isCompleted) {
|
||||||
|
return res.redirect(
|
||||||
|
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(
|
||||||
|
req.passportUser.providerAuthToken
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return res.redirect(
|
||||||
|
`${appCfg.SITE_URL}/signup/sso?token=${encodeURIComponent(
|
||||||
|
req.passportUser.providerAuthToken
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/config",
|
||||||
|
method: "GET",
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
schema: {
|
||||||
|
querystring: z.object({
|
||||||
|
organizationId: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z
|
||||||
|
.object({
|
||||||
|
id: z.string(),
|
||||||
|
organization: z.string(),
|
||||||
|
orgId: z.string(),
|
||||||
|
authProvider: z.string(),
|
||||||
|
isActive: z.boolean(),
|
||||||
|
entryPoint: z.string(),
|
||||||
|
issuer: z.string(),
|
||||||
|
cert: z.string()
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const saml = await server.services.saml.getSaml({
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
orgId: req.query.organizationId,
|
||||||
|
type: "org"
|
||||||
|
});
|
||||||
|
return saml;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/config",
|
||||||
|
method: "POST",
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
schema: {
|
||||||
|
body: z.object({
|
||||||
|
organizationId: z.string(),
|
||||||
|
authProvider: z.nativeEnum(SamlProviders),
|
||||||
|
isActive: z.boolean(),
|
||||||
|
entryPoint: z.string(),
|
||||||
|
issuer: z.string(),
|
||||||
|
cert: z.string()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: SamlConfigsSchema
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const saml = await server.services.saml.createSamlCfg({
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
orgId: req.body.organizationId,
|
||||||
|
...req.body
|
||||||
|
});
|
||||||
|
return saml;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/config",
|
||||||
|
method: "PATCH",
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
schema: {
|
||||||
|
body: z
|
||||||
|
.object({
|
||||||
|
authProvider: z.nativeEnum(SamlProviders),
|
||||||
|
isActive: z.boolean(),
|
||||||
|
entryPoint: z.string(),
|
||||||
|
issuer: z.string(),
|
||||||
|
cert: z.string()
|
||||||
|
})
|
||||||
|
.partial()
|
||||||
|
.merge(z.object({ organizationId: z.string() })),
|
||||||
|
response: {
|
||||||
|
200: SamlConfigsSchema
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const saml = await server.services.saml.updateSamlCfg({
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
orgId: req.body.organizationId,
|
||||||
|
...req.body
|
||||||
|
});
|
||||||
|
return saml;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
SecretsSchema,
|
SecretsSchema,
|
||||||
SecretVersionsSchema
|
SecretVersionsSchema
|
||||||
} from "@app/db/schemas";
|
} from "@app/db/schemas";
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import {
|
import {
|
||||||
ApprovalStatus,
|
ApprovalStatus,
|
||||||
RequestState
|
RequestState
|
||||||
@@ -230,6 +231,23 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
|
|||||||
approvalId: req.params.id,
|
approvalId: req.params.id,
|
||||||
status: req.body.status
|
status: req.body.status
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const isClosing = approval.status === RequestState.Closed;
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: approval.projectId,
|
||||||
|
...req.auditLogInfo,
|
||||||
|
event: {
|
||||||
|
type: isClosing ? EventType.SECRET_APPROVAL_CLOSED : EventType.SECRET_APPROVAL_REOPENED,
|
||||||
|
metadata: {
|
||||||
|
[isClosing ? ("closedBy" as const) : ("reopenedBy" as const)]:
|
||||||
|
approval.statusChangeBy as string,
|
||||||
|
secretApprovalRequestId: approval.id,
|
||||||
|
secretApprovalRequestSlug: approval.slug
|
||||||
|
} as any
|
||||||
|
// akhilmhdh: had to apply any to avoid ts issue with this
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return { approval };
|
return { approval };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TDbClient } from "@app/db";
|
||||||
|
import { TableName } from "@app/db/schemas";
|
||||||
|
import { ormify, stripUndefinedInWhere } from "@app/lib/knex";
|
||||||
|
|
||||||
|
export type TAuditLogDalFactory = ReturnType<typeof auditLogDalFactory>;
|
||||||
|
|
||||||
|
type TFindQuery = {
|
||||||
|
actor?: string;
|
||||||
|
projectId?: string;
|
||||||
|
orgId?: string;
|
||||||
|
eventType?: string;
|
||||||
|
startDate?: string;
|
||||||
|
endDate?: string;
|
||||||
|
userAgentType?: string;
|
||||||
|
limit?: number;
|
||||||
|
offset?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const auditLogDalFactory = (db: TDbClient) => {
|
||||||
|
const auditLogOrm = ormify(db, TableName.AuditLog);
|
||||||
|
|
||||||
|
const find = async (
|
||||||
|
{
|
||||||
|
orgId,
|
||||||
|
projectId,
|
||||||
|
userAgentType,
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
|
limit = 20,
|
||||||
|
offset = 0,
|
||||||
|
actor,
|
||||||
|
eventType
|
||||||
|
}: TFindQuery,
|
||||||
|
tx?: Knex
|
||||||
|
) => {
|
||||||
|
const sqlQuery = (tx || db)(TableName.AuditLog)
|
||||||
|
.where(
|
||||||
|
stripUndefinedInWhere({
|
||||||
|
projectId,
|
||||||
|
orgId,
|
||||||
|
eventType,
|
||||||
|
actor,
|
||||||
|
userAgentType
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.limit(limit)
|
||||||
|
.offset(offset);
|
||||||
|
if (startDate) {
|
||||||
|
sqlQuery.where("createdAt", ">=", startDate);
|
||||||
|
}
|
||||||
|
if (endDate) {
|
||||||
|
sqlQuery.where("createdAt", "<=", endDate);
|
||||||
|
}
|
||||||
|
const docs = await sqlQuery;
|
||||||
|
return docs;
|
||||||
|
};
|
||||||
|
|
||||||
|
return { ...auditLogOrm, find };
|
||||||
|
};
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import { QueueJobs, QueueName, TQueueServiceFactory } from "@app/queue";
|
||||||
|
|
||||||
|
import { TAuditLogDalFactory } from "./audit-log-dal";
|
||||||
|
import { TCreateAuditLogDTO } from "./audit-log-types";
|
||||||
|
|
||||||
|
type TAuditLogQueueServiceFactoryDep = {
|
||||||
|
auditLogDal: TAuditLogDalFactory;
|
||||||
|
queueService: TQueueServiceFactory;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TAuditLogQueueServiceFactory = ReturnType<typeof auditLogQueueServiceFactory>;
|
||||||
|
|
||||||
|
export const auditLogQueueServiceFactory = ({
|
||||||
|
auditLogDal,
|
||||||
|
queueService
|
||||||
|
}: TAuditLogQueueServiceFactoryDep) => {
|
||||||
|
const pushToLog = async (data: TCreateAuditLogDTO) => {
|
||||||
|
await queueService.queue(QueueName.AuditLog, QueueJobs.AuditLog, data, {
|
||||||
|
removeOnFail: {
|
||||||
|
count: 5
|
||||||
|
},
|
||||||
|
removeOnComplete: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
queueService.start(QueueName.AuditLog, async (job) => {
|
||||||
|
const { actor, orgId, event, ipAddress, projectId, userAgent, userAgentType } = job.data;
|
||||||
|
const MS_IN_DAY = 24 * 60 * 60 * 1000;
|
||||||
|
await auditLogDal.create({
|
||||||
|
actor: actor.type,
|
||||||
|
actorMetadata: actor.metadata,
|
||||||
|
userAgent,
|
||||||
|
projectId,
|
||||||
|
ipAddress,
|
||||||
|
orgId,
|
||||||
|
eventType: event.type,
|
||||||
|
expiresAt: new Date(Date.now() + 30 * MS_IN_DAY),
|
||||||
|
eventMetadata: event.metadata,
|
||||||
|
userAgentType
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
pushToLog
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
|
|
||||||
|
import { TPermissionServiceFactory } from "../permission/permission-service";
|
||||||
|
import { ProjectPermissionActions, ProjectPermissionSub } from "../permission/project-permission";
|
||||||
|
import { TAuditLogDalFactory } from "./audit-log-dal";
|
||||||
|
import { TAuditLogQueueServiceFactory } from "./audit-log-queue";
|
||||||
|
import { EventType, TCreateAuditLogDTO, TListProjectAuditLogDTO } from "./audit-log-types";
|
||||||
|
|
||||||
|
type TAuditLogServiceFactoryDep = {
|
||||||
|
auditLogDal: TAuditLogDalFactory;
|
||||||
|
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||||
|
auditLogQueue: TAuditLogQueueServiceFactory;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TAuditLogServiceFactory = ReturnType<typeof auditLogServiceFactory>;
|
||||||
|
|
||||||
|
export const auditLogServiceFactory = ({
|
||||||
|
auditLogDal,
|
||||||
|
auditLogQueue,
|
||||||
|
permissionService
|
||||||
|
}: TAuditLogServiceFactoryDep) => {
|
||||||
|
const listProjectAuditLogs = async ({
|
||||||
|
userAgentType,
|
||||||
|
eventType,
|
||||||
|
offset,
|
||||||
|
limit,
|
||||||
|
endDate,
|
||||||
|
startDate,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
projectId,
|
||||||
|
auditLogActor
|
||||||
|
}: TListProjectAuditLogDTO) => {
|
||||||
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Read,
|
||||||
|
ProjectPermissionSub.AuditLogs
|
||||||
|
);
|
||||||
|
const auditLogs = await auditLogDal.find({
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
eventType,
|
||||||
|
userAgentType,
|
||||||
|
actor: auditLogActor,
|
||||||
|
projectId
|
||||||
|
});
|
||||||
|
return auditLogs.map(
|
||||||
|
({ eventType: logEventType, actor: eActor, actorMetadata, eventMetadata, ...el }) => ({
|
||||||
|
...el,
|
||||||
|
event: { type: logEventType, metadata: eventMetadata },
|
||||||
|
actor: { type: eActor, metadata: actorMetadata }
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const createAuditLog = async (data: TCreateAuditLogDTO) => {
|
||||||
|
// add all cases in which project id or org id cannot be added
|
||||||
|
if (data.event.type !== EventType.LOGIN_IDENTITY_UNIVERSAL_AUTH) {
|
||||||
|
if (!data.projectId && !data.orgId)
|
||||||
|
throw new BadRequestError({ message: "Must either project id or org id" });
|
||||||
|
}
|
||||||
|
return auditLogQueue.pushToLog(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
createAuditLog,
|
||||||
|
listProjectAuditLogs
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,674 @@
|
|||||||
|
import { TProjectPermission } from "@app/lib/types";
|
||||||
|
import { ActorType } from "@app/services/auth/auth-type";
|
||||||
|
import { TIdentityTrustedIp } from "@app/services/identity/identity-types";
|
||||||
|
|
||||||
|
export type TListProjectAuditLogDTO = {
|
||||||
|
auditLogActor?: string;
|
||||||
|
projectId: string;
|
||||||
|
eventType?: string;
|
||||||
|
startDate?: string;
|
||||||
|
endDate?: string;
|
||||||
|
userAgentType?: string;
|
||||||
|
limit?: number;
|
||||||
|
offset?: number;
|
||||||
|
} & TProjectPermission;
|
||||||
|
|
||||||
|
export type TCreateAuditLogDTO = {
|
||||||
|
event: Event;
|
||||||
|
actor: UserActor | IdentityActor | ServiceActor;
|
||||||
|
orgId?: string;
|
||||||
|
projectId?: string;
|
||||||
|
} & BaseAuthData;
|
||||||
|
|
||||||
|
interface BaseAuthData {
|
||||||
|
ipAddress?: string;
|
||||||
|
userAgent?: string;
|
||||||
|
userAgentType?: UserAgentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum UserAgentType {
|
||||||
|
WEB = "web",
|
||||||
|
CLI = "cli",
|
||||||
|
K8_OPERATOR = "k8-operator",
|
||||||
|
TERRAFORM = "terraform",
|
||||||
|
OTHER = "other",
|
||||||
|
PYTHON_SDK = "InfisicalPythonSDK",
|
||||||
|
NODE_SDK = "InfisicalNodeSDK"
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum EventType {
|
||||||
|
GET_SECRETS = "get-secrets",
|
||||||
|
GET_SECRET = "get-secret",
|
||||||
|
REVEAL_SECRET = "reveal-secret",
|
||||||
|
CREATE_SECRET = "create-secret",
|
||||||
|
CREATE_SECRETS = "create-secrets",
|
||||||
|
UPDATE_SECRET = "update-secret",
|
||||||
|
UPDATE_SECRETS = "update-secrets",
|
||||||
|
DELETE_SECRET = "delete-secret",
|
||||||
|
DELETE_SECRETS = "delete-secrets",
|
||||||
|
GET_WORKSPACE_KEY = "get-workspace-key",
|
||||||
|
AUTHORIZE_INTEGRATION = "authorize-integration",
|
||||||
|
UNAUTHORIZE_INTEGRATION = "unauthorize-integration",
|
||||||
|
CREATE_INTEGRATION = "create-integration",
|
||||||
|
DELETE_INTEGRATION = "delete-integration",
|
||||||
|
ADD_TRUSTED_IP = "add-trusted-ip",
|
||||||
|
UPDATE_TRUSTED_IP = "update-trusted-ip",
|
||||||
|
DELETE_TRUSTED_IP = "delete-trusted-ip",
|
||||||
|
CREATE_SERVICE_TOKEN = "create-service-token", // v2
|
||||||
|
DELETE_SERVICE_TOKEN = "delete-service-token", // v2
|
||||||
|
CREATE_IDENTITY = "create-identity",
|
||||||
|
UPDATE_IDENTITY = "update-identity",
|
||||||
|
DELETE_IDENTITY = "delete-identity",
|
||||||
|
LOGIN_IDENTITY_UNIVERSAL_AUTH = "login-identity-universal-auth",
|
||||||
|
ADD_IDENTITY_UNIVERSAL_AUTH = "add-identity-universal-auth",
|
||||||
|
UPDATE_IDENTITY_UNIVERSAL_AUTH = "update-identity-universal-auth",
|
||||||
|
GET_IDENTITY_UNIVERSAL_AUTH = "get-identity-universal-auth",
|
||||||
|
CREATE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "create-identity-universal-auth-client-secret",
|
||||||
|
REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "revoke-identity-universal-auth-client-secret",
|
||||||
|
GET_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRETS = "get-identity-universal-auth-client-secret",
|
||||||
|
CREATE_ENVIRONMENT = "create-environment",
|
||||||
|
UPDATE_ENVIRONMENT = "update-environment",
|
||||||
|
DELETE_ENVIRONMENT = "delete-environment",
|
||||||
|
ADD_WORKSPACE_MEMBER = "add-workspace-member",
|
||||||
|
ADD_BATCH_WORKSPACE_MEMBER = "add-workspace-members",
|
||||||
|
REMOVE_WORKSPACE_MEMBER = "remove-workspace-member",
|
||||||
|
CREATE_FOLDER = "create-folder",
|
||||||
|
UPDATE_FOLDER = "update-folder",
|
||||||
|
DELETE_FOLDER = "delete-folder",
|
||||||
|
CREATE_WEBHOOK = "create-webhook",
|
||||||
|
UPDATE_WEBHOOK_STATUS = "update-webhook-status",
|
||||||
|
DELETE_WEBHOOK = "delete-webhook",
|
||||||
|
GET_SECRET_IMPORTS = "get-secret-imports",
|
||||||
|
CREATE_SECRET_IMPORT = "create-secret-import",
|
||||||
|
UPDATE_SECRET_IMPORT = "update-secret-import",
|
||||||
|
DELETE_SECRET_IMPORT = "delete-secret-import",
|
||||||
|
UPDATE_USER_WORKSPACE_ROLE = "update-user-workspace-role",
|
||||||
|
UPDATE_USER_WORKSPACE_DENIED_PERMISSIONS = "update-user-workspace-denied-permissions",
|
||||||
|
SECRET_APPROVAL_MERGED = "secret-approval-merged",
|
||||||
|
SECRET_APPROVAL_REQUEST = "secret-approval-request",
|
||||||
|
SECRET_APPROVAL_CLOSED = "secret-approval-closed",
|
||||||
|
SECRET_APPROVAL_REOPENED = "secret-approval-reopened"
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UserActorMetadata {
|
||||||
|
userId: string;
|
||||||
|
email: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ServiceActorMetadata {
|
||||||
|
serviceId: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IdentityActorMetadata {
|
||||||
|
identityId: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserActor {
|
||||||
|
type: ActorType.USER;
|
||||||
|
metadata: UserActorMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServiceActor {
|
||||||
|
type: ActorType.SERVICE;
|
||||||
|
metadata: ServiceActorMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IdentityActor {
|
||||||
|
type: ActorType.IDENTITY;
|
||||||
|
metadata: IdentityActorMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Actor = UserActor | ServiceActor | IdentityActor;
|
||||||
|
|
||||||
|
interface GetSecretsEvent {
|
||||||
|
type: EventType.GET_SECRETS;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
numberOfSecrets: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetSecretEvent {
|
||||||
|
type: EventType.GET_SECRET;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
secretId: string;
|
||||||
|
secretKey: string;
|
||||||
|
secretVersion: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateSecretEvent {
|
||||||
|
type: EventType.CREATE_SECRET;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
secretId: string;
|
||||||
|
secretKey: string;
|
||||||
|
secretVersion: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateSecretBatchEvent {
|
||||||
|
type: EventType.CREATE_SECRETS;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
secrets: Array<{ secretId: string; secretKey: string; secretVersion: number }>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateSecretEvent {
|
||||||
|
type: EventType.UPDATE_SECRET;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
secretId: string;
|
||||||
|
secretKey: string;
|
||||||
|
secretVersion: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateSecretBatchEvent {
|
||||||
|
type: EventType.UPDATE_SECRETS;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
secrets: Array<{ secretId: string; secretKey: string; secretVersion: number }>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteSecretEvent {
|
||||||
|
type: EventType.DELETE_SECRET;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
secretId: string;
|
||||||
|
secretKey: string;
|
||||||
|
secretVersion: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteSecretBatchEvent {
|
||||||
|
type: EventType.DELETE_SECRETS;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
secrets: Array<{ secretId: string; secretKey: string; secretVersion: number }>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetWorkspaceKeyEvent {
|
||||||
|
type: EventType.GET_WORKSPACE_KEY;
|
||||||
|
metadata: {
|
||||||
|
keyId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AuthorizeIntegrationEvent {
|
||||||
|
type: EventType.AUTHORIZE_INTEGRATION;
|
||||||
|
metadata: {
|
||||||
|
integration: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UnauthorizeIntegrationEvent {
|
||||||
|
type: EventType.UNAUTHORIZE_INTEGRATION;
|
||||||
|
metadata: {
|
||||||
|
integration: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateIntegrationEvent {
|
||||||
|
type: EventType.CREATE_INTEGRATION;
|
||||||
|
metadata: {
|
||||||
|
integrationId: string;
|
||||||
|
integration: string; // TODO: fix type
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
url?: string;
|
||||||
|
app?: string;
|
||||||
|
appId?: string;
|
||||||
|
targetEnvironment?: string;
|
||||||
|
targetEnvironmentId?: string;
|
||||||
|
targetService?: string;
|
||||||
|
targetServiceId?: string;
|
||||||
|
path?: string;
|
||||||
|
region?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteIntegrationEvent {
|
||||||
|
type: EventType.DELETE_INTEGRATION;
|
||||||
|
metadata: {
|
||||||
|
integrationId: string;
|
||||||
|
integration: string; // TODO: fix type
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
url?: string;
|
||||||
|
app?: string;
|
||||||
|
appId?: string;
|
||||||
|
targetEnvironment?: string;
|
||||||
|
targetEnvironmentId?: string;
|
||||||
|
targetService?: string;
|
||||||
|
targetServiceId?: string;
|
||||||
|
path?: string;
|
||||||
|
region?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AddTrustedIPEvent {
|
||||||
|
type: EventType.ADD_TRUSTED_IP;
|
||||||
|
metadata: {
|
||||||
|
trustedIpId: string;
|
||||||
|
ipAddress: string;
|
||||||
|
prefix?: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateTrustedIPEvent {
|
||||||
|
type: EventType.UPDATE_TRUSTED_IP;
|
||||||
|
metadata: {
|
||||||
|
trustedIpId: string;
|
||||||
|
ipAddress: string;
|
||||||
|
prefix?: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteTrustedIPEvent {
|
||||||
|
type: EventType.DELETE_TRUSTED_IP;
|
||||||
|
metadata: {
|
||||||
|
trustedIpId: string;
|
||||||
|
ipAddress: string;
|
||||||
|
prefix?: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateServiceTokenEvent {
|
||||||
|
type: EventType.CREATE_SERVICE_TOKEN;
|
||||||
|
metadata: {
|
||||||
|
name: string;
|
||||||
|
scopes: Array<{
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteServiceTokenEvent {
|
||||||
|
type: EventType.DELETE_SERVICE_TOKEN;
|
||||||
|
metadata: {
|
||||||
|
name: string;
|
||||||
|
scopes: Array<{
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateIdentityEvent {
|
||||||
|
// note: currently not logging org-role
|
||||||
|
type: EventType.CREATE_IDENTITY;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateIdentityEvent {
|
||||||
|
type: EventType.UPDATE_IDENTITY;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
name?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteIdentityEvent {
|
||||||
|
type: EventType.DELETE_IDENTITY;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LoginIdentityUniversalAuthEvent {
|
||||||
|
type: EventType.LOGIN_IDENTITY_UNIVERSAL_AUTH;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
identityUniversalAuthId: string;
|
||||||
|
clientSecretId: string;
|
||||||
|
identityAccessTokenId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AddIdentityUniversalAuthEvent {
|
||||||
|
type: EventType.ADD_IDENTITY_UNIVERSAL_AUTH;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
clientSecretTrustedIps: Array<TIdentityTrustedIp>;
|
||||||
|
accessTokenTTL: number;
|
||||||
|
accessTokenMaxTTL: number;
|
||||||
|
accessTokenNumUsesLimit: number;
|
||||||
|
accessTokenTrustedIps: Array<TIdentityTrustedIp>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateIdentityUniversalAuthEvent {
|
||||||
|
type: EventType.UPDATE_IDENTITY_UNIVERSAL_AUTH;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
clientSecretTrustedIps?: Array<TIdentityTrustedIp>;
|
||||||
|
accessTokenTTL?: number;
|
||||||
|
accessTokenMaxTTL?: number;
|
||||||
|
accessTokenNumUsesLimit?: number;
|
||||||
|
accessTokenTrustedIps?: Array<TIdentityTrustedIp>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetIdentityUniversalAuthEvent {
|
||||||
|
type: EventType.GET_IDENTITY_UNIVERSAL_AUTH;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateIdentityUniversalAuthClientSecretEvent {
|
||||||
|
type: EventType.CREATE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
clientSecretId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetIdentityUniversalAuthClientSecretsEvent {
|
||||||
|
type: EventType.GET_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRETS;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RevokeIdentityUniversalAuthClientSecretEvent {
|
||||||
|
type: EventType.REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
clientSecretId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateEnvironmentEvent {
|
||||||
|
type: EventType.CREATE_ENVIRONMENT;
|
||||||
|
metadata: {
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateEnvironmentEvent {
|
||||||
|
type: EventType.UPDATE_ENVIRONMENT;
|
||||||
|
metadata: {
|
||||||
|
oldName: string;
|
||||||
|
newName: string;
|
||||||
|
oldSlug: string;
|
||||||
|
newSlug: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteEnvironmentEvent {
|
||||||
|
type: EventType.DELETE_ENVIRONMENT;
|
||||||
|
metadata: {
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AddWorkspaceMemberEvent {
|
||||||
|
type: EventType.ADD_WORKSPACE_MEMBER;
|
||||||
|
metadata: {
|
||||||
|
userId: string;
|
||||||
|
email: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AddBatchWorkspaceMemberEvent {
|
||||||
|
type: EventType.ADD_BATCH_WORKSPACE_MEMBER;
|
||||||
|
metadata: Array<{
|
||||||
|
userId: string;
|
||||||
|
email: string;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RemoveWorkspaceMemberEvent {
|
||||||
|
type: EventType.REMOVE_WORKSPACE_MEMBER;
|
||||||
|
metadata: {
|
||||||
|
userId: string;
|
||||||
|
email: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateFolderEvent {
|
||||||
|
type: EventType.CREATE_FOLDER;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
folderId: string;
|
||||||
|
folderName: string;
|
||||||
|
folderPath: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateFolderEvent {
|
||||||
|
type: EventType.UPDATE_FOLDER;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
folderId: string;
|
||||||
|
oldFolderName: string;
|
||||||
|
newFolderName: string;
|
||||||
|
folderPath: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteFolderEvent {
|
||||||
|
type: EventType.DELETE_FOLDER;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
folderId: string;
|
||||||
|
folderName: string;
|
||||||
|
folderPath: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateWebhookEvent {
|
||||||
|
type: EventType.CREATE_WEBHOOK;
|
||||||
|
metadata: {
|
||||||
|
webhookId: string;
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
webhookUrl: string;
|
||||||
|
isDisabled: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateWebhookStatusEvent {
|
||||||
|
type: EventType.UPDATE_WEBHOOK_STATUS;
|
||||||
|
metadata: {
|
||||||
|
webhookId: string;
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
webhookUrl: string;
|
||||||
|
isDisabled: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteWebhookEvent {
|
||||||
|
type: EventType.DELETE_WEBHOOK;
|
||||||
|
metadata: {
|
||||||
|
webhookId: string;
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
webhookUrl: string;
|
||||||
|
isDisabled: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetSecretImportsEvent {
|
||||||
|
type: EventType.GET_SECRET_IMPORTS;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
folderId: string;
|
||||||
|
numberOfImports: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateSecretImportEvent {
|
||||||
|
type: EventType.CREATE_SECRET_IMPORT;
|
||||||
|
metadata: {
|
||||||
|
secretImportId: string;
|
||||||
|
folderId: string;
|
||||||
|
importFromEnvironment: string;
|
||||||
|
importFromSecretPath: string;
|
||||||
|
importToEnvironment: string;
|
||||||
|
importToSecretPath: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateSecretImportEvent {
|
||||||
|
type: EventType.UPDATE_SECRET_IMPORT;
|
||||||
|
metadata: {
|
||||||
|
secretImportId: string;
|
||||||
|
folderId: string;
|
||||||
|
importToEnvironment: string;
|
||||||
|
importToSecretPath: string;
|
||||||
|
position: number;
|
||||||
|
orderBefore?: {
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
}[];
|
||||||
|
orderAfter?: {
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteSecretImportEvent {
|
||||||
|
type: EventType.DELETE_SECRET_IMPORT;
|
||||||
|
metadata: {
|
||||||
|
secretImportId: string;
|
||||||
|
folderId: string;
|
||||||
|
importFromEnvironment: string;
|
||||||
|
importFromSecretPath: string;
|
||||||
|
importToEnvironment: string;
|
||||||
|
importToSecretPath: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateUserRole {
|
||||||
|
type: EventType.UPDATE_USER_WORKSPACE_ROLE;
|
||||||
|
metadata: {
|
||||||
|
userId: string;
|
||||||
|
email: string;
|
||||||
|
oldRole: string;
|
||||||
|
newRole: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateUserDeniedPermissions {
|
||||||
|
type: EventType.UPDATE_USER_WORKSPACE_DENIED_PERMISSIONS;
|
||||||
|
metadata: {
|
||||||
|
userId: string;
|
||||||
|
email: string;
|
||||||
|
deniedPermissions: {
|
||||||
|
environmentSlug: string;
|
||||||
|
ability: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
interface SecretApprovalMerge {
|
||||||
|
type: EventType.SECRET_APPROVAL_MERGED;
|
||||||
|
metadata: {
|
||||||
|
mergedBy: string;
|
||||||
|
secretApprovalRequestSlug: string;
|
||||||
|
secretApprovalRequestId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SecretApprovalClosed {
|
||||||
|
type: EventType.SECRET_APPROVAL_CLOSED;
|
||||||
|
metadata: {
|
||||||
|
closedBy: string;
|
||||||
|
secretApprovalRequestSlug: string;
|
||||||
|
secretApprovalRequestId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SecretApprovalReopened {
|
||||||
|
type: EventType.SECRET_APPROVAL_REOPENED;
|
||||||
|
metadata: {
|
||||||
|
reopenedBy: string;
|
||||||
|
secretApprovalRequestSlug: string;
|
||||||
|
secretApprovalRequestId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SecretApprovalRequest {
|
||||||
|
type: EventType.SECRET_APPROVAL_REQUEST;
|
||||||
|
metadata: {
|
||||||
|
committedBy: string;
|
||||||
|
secretApprovalRequestSlug: string;
|
||||||
|
secretApprovalRequestId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Event =
|
||||||
|
| GetSecretsEvent
|
||||||
|
| GetSecretEvent
|
||||||
|
| CreateSecretEvent
|
||||||
|
| CreateSecretBatchEvent
|
||||||
|
| UpdateSecretEvent
|
||||||
|
| UpdateSecretBatchEvent
|
||||||
|
| DeleteSecretEvent
|
||||||
|
| DeleteSecretBatchEvent
|
||||||
|
| GetWorkspaceKeyEvent
|
||||||
|
| AuthorizeIntegrationEvent
|
||||||
|
| UnauthorizeIntegrationEvent
|
||||||
|
| CreateIntegrationEvent
|
||||||
|
| DeleteIntegrationEvent
|
||||||
|
| AddTrustedIPEvent
|
||||||
|
| UpdateTrustedIPEvent
|
||||||
|
| DeleteTrustedIPEvent
|
||||||
|
| CreateServiceTokenEvent
|
||||||
|
| DeleteServiceTokenEvent
|
||||||
|
| CreateIdentityEvent
|
||||||
|
| UpdateIdentityEvent
|
||||||
|
| DeleteIdentityEvent
|
||||||
|
| LoginIdentityUniversalAuthEvent
|
||||||
|
| AddIdentityUniversalAuthEvent
|
||||||
|
| UpdateIdentityUniversalAuthEvent
|
||||||
|
| GetIdentityUniversalAuthEvent
|
||||||
|
| CreateIdentityUniversalAuthClientSecretEvent
|
||||||
|
| GetIdentityUniversalAuthClientSecretsEvent
|
||||||
|
| RevokeIdentityUniversalAuthClientSecretEvent
|
||||||
|
| CreateEnvironmentEvent
|
||||||
|
| UpdateEnvironmentEvent
|
||||||
|
| DeleteEnvironmentEvent
|
||||||
|
| AddWorkspaceMemberEvent
|
||||||
|
| AddBatchWorkspaceMemberEvent
|
||||||
|
| RemoveWorkspaceMemberEvent
|
||||||
|
| CreateFolderEvent
|
||||||
|
| UpdateFolderEvent
|
||||||
|
| DeleteFolderEvent
|
||||||
|
| CreateWebhookEvent
|
||||||
|
| UpdateWebhookStatusEvent
|
||||||
|
| DeleteWebhookEvent
|
||||||
|
| GetSecretImportsEvent
|
||||||
|
| CreateSecretImportEvent
|
||||||
|
| UpdateSecretImportEvent
|
||||||
|
| DeleteSecretImportEvent
|
||||||
|
| UpdateUserRole
|
||||||
|
| UpdateUserDeniedPermissions
|
||||||
|
| SecretApprovalMerge
|
||||||
|
| SecretApprovalClosed
|
||||||
|
| SecretApprovalRequest
|
||||||
|
| SecretApprovalReopened;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { TDbClient } from "@app/db";
|
||||||
|
import { TableName } from "@app/db/schemas";
|
||||||
|
import { ormify } from "@app/lib/knex";
|
||||||
|
|
||||||
|
export type TSamlConfigDalFactory = ReturnType<typeof samlConfigDalFactory>;
|
||||||
|
|
||||||
|
export const samlConfigDalFactory = (db: TDbClient) => {
|
||||||
|
const samlCfgOrm = ormify(db, TableName.SamlConfig);
|
||||||
|
return samlCfgOrm;
|
||||||
|
};
|
||||||
@@ -0,0 +1,348 @@
|
|||||||
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
import jwt from "jsonwebtoken";
|
||||||
|
|
||||||
|
import {
|
||||||
|
OrgMembershipRole,
|
||||||
|
OrgMembershipStatus,
|
||||||
|
SecretKeyEncoding,
|
||||||
|
TSamlConfigs,
|
||||||
|
TSamlConfigsUpdate
|
||||||
|
} from "@app/db/schemas";
|
||||||
|
import { getConfig } from "@app/lib/config/env";
|
||||||
|
import {
|
||||||
|
decryptSymmetric,
|
||||||
|
encryptSymmetric,
|
||||||
|
infisicalSymmetricDecrypt
|
||||||
|
} from "@app/lib/crypto/encryption";
|
||||||
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
|
import { AuthTokenType } from "@app/services/auth/auth-type";
|
||||||
|
import { TOrgBotDalFactory } from "@app/services/org/org-bot-dal";
|
||||||
|
import { TOrgDalFactory } from "@app/services/org/org-dal";
|
||||||
|
import { TUserDalFactory } from "@app/services/user/user-dal";
|
||||||
|
|
||||||
|
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||||
|
import { TPermissionServiceFactory } from "../permission/permission-service";
|
||||||
|
import { TSamlConfigDalFactory } from "./saml-config-dal";
|
||||||
|
import {
|
||||||
|
SamlProviders,
|
||||||
|
TCreateSamlCfgDTO,
|
||||||
|
TGetSamlCfgDTO,
|
||||||
|
TSamlLoginDTO,
|
||||||
|
TUpdateSamlCfgDTO
|
||||||
|
} from "./saml-config-types";
|
||||||
|
|
||||||
|
type TSamlConfigServiceFactoryDep = {
|
||||||
|
samlConfigDal: TSamlConfigDalFactory;
|
||||||
|
userDal: Pick<TUserDalFactory, "create" | "findUserByEmail" | "transaction" | "updateById">;
|
||||||
|
orgDal: Pick<
|
||||||
|
TOrgDalFactory,
|
||||||
|
"createMembership" | "updateMembershipById" | "findMembership" | "findOrgById"
|
||||||
|
>;
|
||||||
|
orgBotDal: Pick<TOrgBotDalFactory, "findOne">;
|
||||||
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TSamlConfigServiceFactory = ReturnType<typeof samlConfigServiceFactory>;
|
||||||
|
|
||||||
|
export const samlConfigServiceFactory = ({
|
||||||
|
samlConfigDal,
|
||||||
|
orgBotDal,
|
||||||
|
orgDal,
|
||||||
|
userDal,
|
||||||
|
permissionService
|
||||||
|
}: TSamlConfigServiceFactoryDep) => {
|
||||||
|
const createSamlCfg = async ({
|
||||||
|
cert,
|
||||||
|
actor,
|
||||||
|
orgId,
|
||||||
|
issuer,
|
||||||
|
actorId,
|
||||||
|
isActive,
|
||||||
|
entryPoint,
|
||||||
|
authProvider
|
||||||
|
}: TCreateSamlCfgDTO) => {
|
||||||
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
OrgPermissionActions.Create,
|
||||||
|
OrgPermissionSubjects.Sso
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO(akhilmhdh-pg): licence check
|
||||||
|
|
||||||
|
const orgBot = await orgBotDal.findOne({ orgId });
|
||||||
|
if (!orgBot)
|
||||||
|
throw new BadRequestError({ message: "Org bot not found", name: "OrgBotNotFound" });
|
||||||
|
const key = infisicalSymmetricDecrypt({
|
||||||
|
ciphertext: orgBot.encryptedSymmetricKey,
|
||||||
|
iv: orgBot.symmetricKeyIV,
|
||||||
|
tag: orgBot.symmetricKeyTag,
|
||||||
|
keyEncoding: orgBot.symmetricKeyKeyEncoding as SecretKeyEncoding
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
ciphertext: encryptedEntryPoint,
|
||||||
|
iv: entryPointIV,
|
||||||
|
tag: entryPointTag
|
||||||
|
} = encryptSymmetric(entryPoint, key);
|
||||||
|
const {
|
||||||
|
ciphertext: encryptedIssuer,
|
||||||
|
iv: issuerIV,
|
||||||
|
tag: issuerTag
|
||||||
|
} = encryptSymmetric(issuer, key);
|
||||||
|
|
||||||
|
const { ciphertext: encryptedCert, iv: certIV, tag: certTag } = encryptSymmetric(cert, key);
|
||||||
|
const samlConfig = await samlConfigDal.create({
|
||||||
|
orgId,
|
||||||
|
authProvider,
|
||||||
|
isActive,
|
||||||
|
encryptedEntryPoint,
|
||||||
|
entryPointIV,
|
||||||
|
entryPointTag,
|
||||||
|
encryptedIssuer,
|
||||||
|
issuerIV,
|
||||||
|
issuerTag,
|
||||||
|
encryptedCert,
|
||||||
|
certIV,
|
||||||
|
certTag
|
||||||
|
});
|
||||||
|
return samlConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateSamlCfg = async ({
|
||||||
|
orgId,
|
||||||
|
actor,
|
||||||
|
cert,
|
||||||
|
actorId,
|
||||||
|
issuer,
|
||||||
|
isActive,
|
||||||
|
entryPoint,
|
||||||
|
authProvider
|
||||||
|
}: TUpdateSamlCfgDTO) => {
|
||||||
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
OrgPermissionActions.Edit,
|
||||||
|
OrgPermissionSubjects.Sso
|
||||||
|
);
|
||||||
|
const updateQuery: TSamlConfigsUpdate = { authProvider, isActive };
|
||||||
|
const orgBot = await orgBotDal.findOne({ orgId });
|
||||||
|
if (!orgBot)
|
||||||
|
throw new BadRequestError({ message: "Org bot not found", name: "OrgBotNotFound" });
|
||||||
|
const key = infisicalSymmetricDecrypt({
|
||||||
|
ciphertext: orgBot.encryptedSymmetricKey,
|
||||||
|
iv: orgBot.symmetricKeyIV,
|
||||||
|
tag: orgBot.symmetricKeyTag,
|
||||||
|
keyEncoding: orgBot.symmetricKeyKeyEncoding as SecretKeyEncoding
|
||||||
|
});
|
||||||
|
|
||||||
|
if (entryPoint) {
|
||||||
|
const {
|
||||||
|
ciphertext: encryptedEntryPoint,
|
||||||
|
iv: entryPointIV,
|
||||||
|
tag: entryPointTag
|
||||||
|
} = encryptSymmetric(entryPoint, key);
|
||||||
|
updateQuery.encryptedEntryPoint = encryptedEntryPoint;
|
||||||
|
updateQuery.entryPointIV = entryPointIV;
|
||||||
|
updateQuery.entryPointTag = entryPointTag;
|
||||||
|
}
|
||||||
|
if (issuer) {
|
||||||
|
const {
|
||||||
|
ciphertext: encryptedIssuer,
|
||||||
|
iv: issuerIV,
|
||||||
|
tag: issuerTag
|
||||||
|
} = encryptSymmetric(issuer, key);
|
||||||
|
updateQuery.encryptedIssuer = encryptedIssuer;
|
||||||
|
updateQuery.issuerIV = issuerIV;
|
||||||
|
updateQuery.issuerTag = issuerTag;
|
||||||
|
}
|
||||||
|
if (cert) {
|
||||||
|
const { ciphertext: encryptedCert, iv: certIV, tag: certTag } = encryptSymmetric(cert, key);
|
||||||
|
updateQuery.encryptedCert = encryptedCert;
|
||||||
|
updateQuery.certIV = certIV;
|
||||||
|
updateQuery.certTag = certTag;
|
||||||
|
}
|
||||||
|
const [ssoConfig] = await samlConfigDal.update({ orgId }, updateQuery);
|
||||||
|
return ssoConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSaml = async (dto: TGetSamlCfgDTO) => {
|
||||||
|
let ssoConfig: TSamlConfigs | undefined;
|
||||||
|
if (dto.type === "org") {
|
||||||
|
ssoConfig = await samlConfigDal.findOne({ orgId: dto.orgId });
|
||||||
|
if (!ssoConfig) return;
|
||||||
|
} else if (dto.type === "ssoId") {
|
||||||
|
ssoConfig = await samlConfigDal.findById(dto.id);
|
||||||
|
}
|
||||||
|
if (!ssoConfig) throw new BadRequestError({ message: "Failed to find organization SSO data" });
|
||||||
|
|
||||||
|
// when dto is type id means it's internally used
|
||||||
|
if (dto.type === "org") {
|
||||||
|
const { permission } = await permissionService.getOrgPermission(
|
||||||
|
dto.actor,
|
||||||
|
dto.actorId,
|
||||||
|
ssoConfig!.orgId
|
||||||
|
);
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
OrgPermissionActions.Read,
|
||||||
|
OrgPermissionSubjects.Sso
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const {
|
||||||
|
entryPointTag,
|
||||||
|
entryPointIV,
|
||||||
|
encryptedEntryPoint,
|
||||||
|
certTag,
|
||||||
|
certIV,
|
||||||
|
encryptedCert,
|
||||||
|
issuerTag,
|
||||||
|
issuerIV,
|
||||||
|
encryptedIssuer
|
||||||
|
} = ssoConfig;
|
||||||
|
|
||||||
|
const orgBot = await orgBotDal.findOne({ orgId: ssoConfig.orgId });
|
||||||
|
if (!orgBot)
|
||||||
|
throw new BadRequestError({ message: "Org bot not found", name: "OrgBotNotFound" });
|
||||||
|
const key = infisicalSymmetricDecrypt({
|
||||||
|
ciphertext: orgBot.encryptedSymmetricKey,
|
||||||
|
iv: orgBot.symmetricKeyIV,
|
||||||
|
tag: orgBot.symmetricKeyTag,
|
||||||
|
keyEncoding: orgBot.symmetricKeyKeyEncoding as SecretKeyEncoding
|
||||||
|
});
|
||||||
|
|
||||||
|
let entryPoint = "";
|
||||||
|
if (encryptedEntryPoint && entryPointIV && entryPointTag) {
|
||||||
|
entryPoint = decryptSymmetric({
|
||||||
|
ciphertext: encryptedEntryPoint,
|
||||||
|
key,
|
||||||
|
tag: entryPointTag,
|
||||||
|
iv: entryPointIV
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let issuer = "";
|
||||||
|
if (encryptedIssuer && issuerTag && issuerIV) {
|
||||||
|
issuer = decryptSymmetric({
|
||||||
|
key,
|
||||||
|
tag: issuerTag,
|
||||||
|
iv: issuerIV,
|
||||||
|
ciphertext: encryptedIssuer
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let cert = "";
|
||||||
|
if (encryptedCert && certTag && certIV) {
|
||||||
|
cert = decryptSymmetric({ key, tag: certTag, iv: certIV, ciphertext: encryptedCert });
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: ssoConfig.id,
|
||||||
|
organization: ssoConfig.orgId,
|
||||||
|
orgId: ssoConfig.orgId,
|
||||||
|
authProvider: ssoConfig.authProvider,
|
||||||
|
isActive: ssoConfig.isActive,
|
||||||
|
entryPoint,
|
||||||
|
issuer,
|
||||||
|
cert
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const samlLogin = async ({
|
||||||
|
firstName,
|
||||||
|
email,
|
||||||
|
lastName,
|
||||||
|
authProvider,
|
||||||
|
orgId,
|
||||||
|
relayState,
|
||||||
|
isSignupAllowed
|
||||||
|
}: TSamlLoginDTO) => {
|
||||||
|
const appCfg = getConfig();
|
||||||
|
let user = await userDal.findUserByEmail(email);
|
||||||
|
const isSamlSignUpDisabled = !isSignupAllowed && !user;
|
||||||
|
if (isSamlSignUpDisabled)
|
||||||
|
throw new BadRequestError({ message: "User signup disabled", name: "Saml SSO login" });
|
||||||
|
|
||||||
|
const organization = await orgDal.findOrgById(orgId);
|
||||||
|
if (!organization) throw new BadRequestError({ message: "Org not found" });
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
const hasSamlEnabled = (user.authMethods || []).some((method) =>
|
||||||
|
Object.values(SamlProviders).includes(method as SamlProviders)
|
||||||
|
);
|
||||||
|
await userDal.transaction(async (tx) => {
|
||||||
|
if (!hasSamlEnabled) {
|
||||||
|
await userDal.updateById(user.id, { authMethods: [authProvider] }, tx);
|
||||||
|
}
|
||||||
|
const [orgMembership] = await orgDal.findMembership({ userId: user.id, orgId }, { tx });
|
||||||
|
if (!orgMembership) {
|
||||||
|
await orgDal.createMembership(
|
||||||
|
{
|
||||||
|
userId: user.id,
|
||||||
|
orgId,
|
||||||
|
inviteEmail: email,
|
||||||
|
role: OrgMembershipRole.Member,
|
||||||
|
status: OrgMembershipStatus.Accepted
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
} else if (orgMembership.status === OrgMembershipStatus.Invited) {
|
||||||
|
await orgDal.updateMembershipById(
|
||||||
|
orgMembership.id,
|
||||||
|
{
|
||||||
|
status: OrgMembershipStatus.Accepted
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
user = await userDal.transaction(async (tx) => {
|
||||||
|
const newUser = await userDal.create(
|
||||||
|
{
|
||||||
|
email,
|
||||||
|
firstName,
|
||||||
|
lastName,
|
||||||
|
authMethods: [authProvider]
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
await orgDal.createMembership({
|
||||||
|
inviteEmail: email,
|
||||||
|
orgId,
|
||||||
|
role: OrgMembershipRole.Member,
|
||||||
|
status: OrgMembershipStatus.Invited
|
||||||
|
});
|
||||||
|
return newUser;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const isUserCompleted = Boolean(user.isAccepted);
|
||||||
|
const providerAuthToken = jwt.sign(
|
||||||
|
{
|
||||||
|
authTokenType: AuthTokenType.PROVIDER_TOKEN,
|
||||||
|
userId: user.id,
|
||||||
|
email: user.email,
|
||||||
|
firstName,
|
||||||
|
lastName,
|
||||||
|
organizationName: organization.name,
|
||||||
|
organizationId: organization.id,
|
||||||
|
authMethod: authProvider,
|
||||||
|
isUserCompleted,
|
||||||
|
...(relayState
|
||||||
|
? {
|
||||||
|
callbackPort: JSON.parse(relayState).callbackPort as string
|
||||||
|
}
|
||||||
|
: {})
|
||||||
|
},
|
||||||
|
appCfg.JWT_AUTH_SECRET,
|
||||||
|
{
|
||||||
|
expiresIn: appCfg.JWT_PROVIDER_AUTH_LIFETIME
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return { isUserCompleted, providerAuthToken };
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
createSamlCfg,
|
||||||
|
updateSamlCfg,
|
||||||
|
getSaml,
|
||||||
|
samlLogin
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import { TOrgPermission } from "@app/lib/types";
|
||||||
|
import { ActorType } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
|
export enum SamlProviders {
|
||||||
|
OKTA_SAML = "okta-saml",
|
||||||
|
AZURE_SAML = "azure-saml",
|
||||||
|
JUMPCLOUD_SAML = "jumpcloud-saml"
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TCreateSamlCfgDTO = {
|
||||||
|
authProvider: SamlProviders;
|
||||||
|
isActive: boolean;
|
||||||
|
entryPoint: string;
|
||||||
|
issuer: string;
|
||||||
|
cert: string;
|
||||||
|
} & TOrgPermission;
|
||||||
|
|
||||||
|
export type TUpdateSamlCfgDTO = Partial<{
|
||||||
|
authProvider: SamlProviders;
|
||||||
|
isActive: boolean;
|
||||||
|
entryPoint: string;
|
||||||
|
issuer: string;
|
||||||
|
cert: string;
|
||||||
|
}> &
|
||||||
|
TOrgPermission;
|
||||||
|
|
||||||
|
export type TGetSamlCfgDTO =
|
||||||
|
| { type: "org"; orgId: string; actor: ActorType; actorId: string }
|
||||||
|
| {
|
||||||
|
type: "ssoId";
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TSamlLoginDTO = {
|
||||||
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName?: string;
|
||||||
|
authProvider: string;
|
||||||
|
orgId: string;
|
||||||
|
isSignupAllowed: boolean;
|
||||||
|
// saml thingy
|
||||||
|
relayState?: string;
|
||||||
|
};
|
||||||
@@ -84,12 +84,12 @@ export const secretApprovalRequestDalFactory = (db: TDbClient) => {
|
|||||||
childrenMapper: [
|
childrenMapper: [
|
||||||
{
|
{
|
||||||
key: "reviewerMemberId",
|
key: "reviewerMemberId",
|
||||||
label: "reviewers",
|
label: "reviewers" as const,
|
||||||
mapper: ({ reviewerMemberId: member, reviewerStatus: status }) =>
|
mapper: ({ reviewerMemberId: member, reviewerStatus: status }) =>
|
||||||
member ? { member, status } : undefined
|
member ? { member, status } : undefined
|
||||||
},
|
},
|
||||||
{ key: "approverId", label: "approvers", mapper: ({ approverId }) => approverId }
|
{ key: "approverId", label: "approvers" as const, mapper: ({ approverId }) => approverId }
|
||||||
] as const
|
]
|
||||||
});
|
});
|
||||||
if (!formatedDoc?.[0]) return;
|
if (!formatedDoc?.[0]) return;
|
||||||
return {
|
return {
|
||||||
@@ -213,12 +213,12 @@ export const secretApprovalRequestDalFactory = (db: TDbClient) => {
|
|||||||
childrenMapper: [
|
childrenMapper: [
|
||||||
{
|
{
|
||||||
key: "reviewerMemberId",
|
key: "reviewerMemberId",
|
||||||
label: "reviewers",
|
label: "reviewers" as const,
|
||||||
mapper: ({ reviewerMemberId: member, reviewerStatus: s }) =>
|
mapper: ({ reviewerMemberId: member, reviewerStatus: s }) =>
|
||||||
member ? { member, status: s } : undefined
|
member ? { member, status: s } : undefined
|
||||||
},
|
},
|
||||||
{ key: "approverId", label: "approvers", mapper: ({ approverId }) => approverId }
|
{ key: "approverId", label: "approvers" as const, mapper: ({ approverId }) => approverId }
|
||||||
] as const
|
]
|
||||||
});
|
});
|
||||||
return formatedDoc.map((el) => ({
|
return formatedDoc.map((el) => ({
|
||||||
...el,
|
...el,
|
||||||
|
|||||||
+1
-1
@@ -181,7 +181,7 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
status,
|
status,
|
||||||
statusChangeBy: membership.id
|
statusChangeBy: membership.id
|
||||||
});
|
});
|
||||||
return updatedRequest;
|
return { ...secretApprovalRequest, ...updatedRequest };
|
||||||
};
|
};
|
||||||
|
|
||||||
const mergeSecretApprovalRequest = async ({
|
const mergeSecretApprovalRequest = async ({
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ export const secretRotationDalFactory = (db: TDbClient) => {
|
|||||||
childrenMapper: [
|
childrenMapper: [
|
||||||
{
|
{
|
||||||
key: "secId",
|
key: "secId",
|
||||||
label: "outputs",
|
label: "outputs" as const,
|
||||||
mapper: ({
|
mapper: ({
|
||||||
secId,
|
secId,
|
||||||
outputKey,
|
outputKey,
|
||||||
@@ -92,7 +92,7 @@ export const secretRotationDalFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
] as const
|
]
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "SecretRotationFind" });
|
throw new DatabaseError({ error, name: "SecretRotationFind" });
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ import {
|
|||||||
TSecretFolderVersions,
|
TSecretFolderVersions,
|
||||||
TSecretSnapshotFolders,
|
TSecretSnapshotFolders,
|
||||||
TSecretSnapshots,
|
TSecretSnapshots,
|
||||||
TSecretVersions} from "@app/db/schemas";
|
TSecretVersions
|
||||||
|
} from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import { ormify, selectAllTableCols, sqlNestRelationships } from "@app/lib/knex";
|
import { ormify, selectAllTableCols, sqlNestRelationships } from "@app/lib/knex";
|
||||||
|
|
||||||
@@ -109,15 +110,15 @@ export const snapshotDalFactory = (db: TDbClient) => {
|
|||||||
childrenMapper: [
|
childrenMapper: [
|
||||||
{
|
{
|
||||||
key: "id",
|
key: "id",
|
||||||
label: "secretVersions",
|
label: "secretVersions" as const,
|
||||||
mapper: (el) => SecretVersionsSchema.parse(el)
|
mapper: (el) => SecretVersionsSchema.parse(el)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "folderVerId",
|
key: "folderVerId",
|
||||||
label: "folderVersion",
|
label: "folderVersion" as const,
|
||||||
mapper: ({ folderVerId: id, folderVerName: name }) => ({ id, name })
|
mapper: ({ folderVerId: id, folderVerName: name }) => ({ id, name })
|
||||||
}
|
}
|
||||||
] as const
|
]
|
||||||
})?.[0];
|
})?.[0];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "FindSecretSnapshotDataById" });
|
throw new DatabaseError({ error, name: "FindSecretSnapshotDataById" });
|
||||||
@@ -237,7 +238,7 @@ export const snapshotDalFactory = (db: TDbClient) => {
|
|||||||
childrenMapper: [
|
childrenMapper: [
|
||||||
{
|
{
|
||||||
key: "id",
|
key: "id",
|
||||||
label: "secretVersions",
|
label: "secretVersions" as const,
|
||||||
mapper: (el) => ({
|
mapper: (el) => ({
|
||||||
...SecretVersionsSchema.parse(el),
|
...SecretVersionsSchema.parse(el),
|
||||||
latestSecretVersion: el.latestSecretVersion
|
latestSecretVersion: el.latestSecretVersion
|
||||||
@@ -245,14 +246,14 @@ export const snapshotDalFactory = (db: TDbClient) => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "folderVerId",
|
key: "folderVerId",
|
||||||
label: "folderVersion",
|
label: "folderVersion" as const,
|
||||||
mapper: ({ folderVerId: id, folderVerName: name, latestFolderVersion }) => ({
|
mapper: ({ folderVerId: id, folderVerName: name, latestFolderVersion }) => ({
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
latestFolderVersion
|
latestFolderVersion
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
] as const
|
]
|
||||||
});
|
});
|
||||||
return formated;
|
return formated;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -1,190 +0,0 @@
|
|||||||
import dotenv from "dotenv";
|
|
||||||
|
|
||||||
import { initDbConnection } from "./db";
|
|
||||||
import {
|
|
||||||
SecretVersionsSchema,
|
|
||||||
TableName,
|
|
||||||
TSecretFolderVersions,
|
|
||||||
TSecrets,
|
|
||||||
TSecretSnapshotFolders,
|
|
||||||
TSecretSnapshots,
|
|
||||||
TSecretVersions} from "./db/schemas";
|
|
||||||
import { selectAllTableCols, sqlNestRelationships } from "./lib/knex";
|
|
||||||
|
|
||||||
dotenv.config();
|
|
||||||
// const db = initDbConnection(process.env.DB_CONNECTION_URI);
|
|
||||||
|
|
||||||
// const main = async () => {
|
|
||||||
// const folders = db
|
|
||||||
// .withRecursive("parent", (qb) => {
|
|
||||||
// qb.select({
|
|
||||||
// depth: 1,
|
|
||||||
// path: db.raw("'/'")
|
|
||||||
// })
|
|
||||||
// .select(selectAllTableCols(db, TableName.SecretFolder))
|
|
||||||
// .from(TableName.SecretFolder)
|
|
||||||
// .join(
|
|
||||||
// TableName.Environment,
|
|
||||||
// `${TableName.SecretFolder}.envId`,
|
|
||||||
// `${TableName.Environment}.id`
|
|
||||||
// )
|
|
||||||
// .where({
|
|
||||||
// projectId: "01c10de1-8743-490f-9c8a-7a19c4dc72a9",
|
|
||||||
// parentId: null
|
|
||||||
// })
|
|
||||||
// .where(`${TableName.Environment}.slug`, "dev")
|
|
||||||
// .union((qb) =>
|
|
||||||
// qb
|
|
||||||
// .select({
|
|
||||||
// depth: db.raw("parent.depth + 1"),
|
|
||||||
// path: db.raw(
|
|
||||||
// "CONCAT((CASE WHEN parent.path = '/' THEN '' ELSE parent.path END),'/', secret_folders.name)"
|
|
||||||
// )
|
|
||||||
// })
|
|
||||||
// .select(selectAllTableCols(db, TableName.SecretFolder))
|
|
||||||
// .whereRaw(
|
|
||||||
// `depth = array_position(ARRAY[${[1, 2]
|
|
||||||
// .map((_) => "?")
|
|
||||||
// .join(",")}]::varchar[], secret_folders.name,depth)`,
|
|
||||||
// [...["ui", "design"]]
|
|
||||||
// )
|
|
||||||
// .from(TableName.SecretFolder)
|
|
||||||
// .join("parent", "parent.id", `${TableName.SecretFolder}.parentId`)
|
|
||||||
// );
|
|
||||||
// })
|
|
||||||
// .select("*")
|
|
||||||
// .from("parent")
|
|
||||||
// .orderBy("depth", "desc")
|
|
||||||
// .first();
|
|
||||||
// console.log(folders.toSQL());
|
|
||||||
// console.log(JSON.stringify(await folders, null, 4));
|
|
||||||
// process.exit(0);
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
const main = async () => {
|
|
||||||
const db = initDbConnection(process.env.DB_CONNECTION_URI);
|
|
||||||
|
|
||||||
const folders = db
|
|
||||||
.withRecursive("parent", (qb) => {
|
|
||||||
qb.from(TableName.Snapshot)
|
|
||||||
.leftJoin<TSecretSnapshotFolders>(
|
|
||||||
TableName.SnapshotFolder,
|
|
||||||
`${TableName.SnapshotFolder}.snapshotId`,
|
|
||||||
`${TableName.Snapshot}.id`
|
|
||||||
)
|
|
||||||
.leftJoin<TSecretFolderVersions>(
|
|
||||||
TableName.SecretFolderVersion,
|
|
||||||
`${TableName.SnapshotFolder}.folderVersionId`,
|
|
||||||
`${TableName.SecretFolderVersion}.id`
|
|
||||||
)
|
|
||||||
.select(selectAllTableCols(TableName.Snapshot))
|
|
||||||
.select({ depth: 1 })
|
|
||||||
.select(
|
|
||||||
db.ref("name").withSchema(TableName.SecretFolderVersion).as("folderVerName"),
|
|
||||||
db.ref("folderId").withSchema(TableName.SecretFolderVersion).as("folderVerId")
|
|
||||||
)
|
|
||||||
.where(`${TableName.Snapshot}.id`, "abe694d3-957f-40f5-a907-952d3e5ccaf1")
|
|
||||||
.union((cb) =>
|
|
||||||
cb
|
|
||||||
.select(selectAllTableCols(TableName.Snapshot))
|
|
||||||
.select({ depth: db.raw("parent.depth + 1") })
|
|
||||||
.select(
|
|
||||||
db.ref("name").withSchema(TableName.SecretFolderVersion).as("folderVerName"),
|
|
||||||
db.ref("folderId").withSchema(TableName.SecretFolderVersion).as("folderVerId")
|
|
||||||
)
|
|
||||||
.from(TableName.Snapshot)
|
|
||||||
.join<TSecretSnapshots, TSecretSnapshots & { secretId: string; max: number }>(
|
|
||||||
db(TableName.Snapshot)
|
|
||||||
.groupBy("folderId")
|
|
||||||
.max("createdAt")
|
|
||||||
.select("folderId")
|
|
||||||
.as("latestVersion"),
|
|
||||||
`${TableName.Snapshot}.createdAt`,
|
|
||||||
"latestVersion.max"
|
|
||||||
)
|
|
||||||
.leftJoin<TSecretSnapshotFolders>(
|
|
||||||
TableName.SnapshotFolder,
|
|
||||||
`${TableName.SnapshotFolder}.snapshotId`,
|
|
||||||
`${TableName.Snapshot}.id`
|
|
||||||
)
|
|
||||||
.leftJoin<TSecretFolderVersions>(
|
|
||||||
TableName.SecretFolderVersion,
|
|
||||||
`${TableName.SnapshotFolder}.folderVersionId`,
|
|
||||||
`${TableName.SecretFolderVersion}.id`
|
|
||||||
)
|
|
||||||
.join("parent", "parent.folderVerId", `${TableName.Snapshot}.folderId`)
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.orderBy("depth", "asc")
|
|
||||||
.from<TSecretSnapshots & { folderVerId: string; folderVerName: string }>("parent")
|
|
||||||
.leftJoin<TSecretSnapshots>(
|
|
||||||
TableName.SnapshotSecret,
|
|
||||||
`parent.id`,
|
|
||||||
`${TableName.SnapshotSecret}.snapshotId`
|
|
||||||
)
|
|
||||||
.leftJoin<TSecretVersions>(
|
|
||||||
TableName.SecretVersion,
|
|
||||||
`${TableName.SnapshotSecret}.secretVersionId`,
|
|
||||||
`${TableName.SecretVersion}.id`
|
|
||||||
)
|
|
||||||
.leftJoin<{ latestSecretVersion: number }>(
|
|
||||||
db(TableName.SecretVersion)
|
|
||||||
.groupBy("secretId")
|
|
||||||
.select("secretId")
|
|
||||||
.max("version")
|
|
||||||
.as("secGroupByMaxVersion"),
|
|
||||||
`${TableName.SecretVersion}.secretId`,
|
|
||||||
"secGroupByMaxVersion.secretId"
|
|
||||||
)
|
|
||||||
.leftJoin<{ latestFolderVersion: number }>(
|
|
||||||
db(TableName.SecretFolderVersion)
|
|
||||||
.groupBy("folderId")
|
|
||||||
.select("folderId")
|
|
||||||
.max("version")
|
|
||||||
.as("folderGroupByMaxVersion"),
|
|
||||||
`parent.folderId`,
|
|
||||||
"folderGroupByMaxVersion.folderId"
|
|
||||||
)
|
|
||||||
.select(selectAllTableCols(TableName.SecretVersion))
|
|
||||||
.select(
|
|
||||||
db.ref("id").withSchema("parent").as("snapshotId"),
|
|
||||||
db.ref("folderId").withSchema("parent").as("snapshotFolderId"),
|
|
||||||
db.ref("parentFolderId").withSchema("parent").as("snapshotParentFolderId"),
|
|
||||||
db.ref("folderVerName").withSchema("parent"),
|
|
||||||
db.ref("folderVerId").withSchema("parent"),
|
|
||||||
db.ref("max").withSchema("secGroupByMaxVersion").as("latestSecretVersion"),
|
|
||||||
db.ref("max").withSchema("folderGroupByMaxVersion").as("latestFolderVersion")
|
|
||||||
);
|
|
||||||
console.log(folders.toSQL());
|
|
||||||
const data = await folders;
|
|
||||||
// console.log(data);
|
|
||||||
const formated = sqlNestRelationships({
|
|
||||||
data,
|
|
||||||
key: "snapshotId",
|
|
||||||
parentMapper: ({ snapshotId: id }) => ({
|
|
||||||
id
|
|
||||||
}),
|
|
||||||
childrenMapper: [
|
|
||||||
{
|
|
||||||
key: "id",
|
|
||||||
label: "secretVersions",
|
|
||||||
mapper: (el) => ({
|
|
||||||
...SecretVersionsSchema.parse(el),
|
|
||||||
latestSecretVersion: el.latestSecretVersion
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "folderVerId",
|
|
||||||
label: "folderVersion",
|
|
||||||
mapper: ({ folderVerId: id, folderVerName: name, latestFolderVersion }) => ({
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
version: latestFolderVersion
|
|
||||||
})
|
|
||||||
}
|
|
||||||
] as const
|
|
||||||
});
|
|
||||||
console.log(formated);
|
|
||||||
process.exit(0);
|
|
||||||
};
|
|
||||||
main();
|
|
||||||
@@ -122,6 +122,8 @@ export const decryptAsymmetric = ({
|
|||||||
return naclUtils.encodeUTF8(plaintext);
|
return naclUtils.encodeUTF8(plaintext);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const generateSymmetricKey = (size = 32) => crypto.randomBytes(size).toString("base64");
|
||||||
|
|
||||||
export const generateAsymmetricKeyPair = () => {
|
export const generateAsymmetricKeyPair = () => {
|
||||||
const pair = nacl.box.keyPair();
|
const pair = nacl.box.keyPair();
|
||||||
|
|
||||||
|
|||||||
@@ -15,3 +15,23 @@ export const pick = <T extends object, TKeys extends keyof T>(
|
|||||||
{} as Pick<T, TKeys>
|
{} as Pick<T, TKeys>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes (shakes out) undefined entries from an
|
||||||
|
* object. Optional second argument shakes out values
|
||||||
|
* by custom evaluation.
|
||||||
|
*/
|
||||||
|
export const shake = <RemovedKeys extends string, T = {}>(
|
||||||
|
obj: T,
|
||||||
|
filter: (value: any) => boolean = (x) => x === undefined || x === null
|
||||||
|
): Omit<T, RemovedKeys> => {
|
||||||
|
if (!obj) return {} as T;
|
||||||
|
const keys = Object.keys(obj) as (keyof T)[];
|
||||||
|
return keys.reduce((acc, key) => {
|
||||||
|
if (filter(obj[key])) {
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
acc[key] = obj[key];
|
||||||
|
return acc;
|
||||||
|
}, {} as T);
|
||||||
|
};
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ import { Tables } from "knex/types/tables";
|
|||||||
export const selectAllTableCols = <Tname extends keyof Tables>(tableName: Tname) =>
|
export const selectAllTableCols = <Tname extends keyof Tables>(tableName: Tname) =>
|
||||||
`${tableName}.*` as keyof Tables[Tname]["base"];
|
`${tableName}.*` as keyof Tables[Tname]["base"];
|
||||||
|
|
||||||
export const stripUndefinedInWhere = <T extends object>(val: T) => {
|
export const stripUndefinedInWhere = <T extends object>(val: T): Exclude<T, undefined> => {
|
||||||
const copy = val;
|
const copy = val;
|
||||||
Object.entries(copy).forEach(([key, value]) => {
|
Object.entries(copy).forEach(([key, value]) => {
|
||||||
if (typeof value === "undefined") {
|
if (typeof value === "undefined") {
|
||||||
delete copy[key as keyof T];
|
delete copy[key as keyof T];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return copy;
|
return copy as Exclude<T, undefined>;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
import { Job, JobsOptions, Queue, Worker, WorkerListener } from "bullmq";
|
import { Job, JobsOptions, Queue, Worker, WorkerListener } from "bullmq";
|
||||||
import Redis from "ioredis";
|
import Redis from "ioredis";
|
||||||
|
|
||||||
|
import { TCreateAuditLogDTO } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
|
|
||||||
export enum QueueName {
|
export enum QueueName {
|
||||||
SecretRotation = "secret-rotation"
|
SecretRotation = "secret-rotation",
|
||||||
|
AuditLog = "audit-log"
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum QueueJobs {
|
export enum QueueJobs {
|
||||||
SecretRotation = "secret-rotation-job"
|
SecretRotation = "secret-rotation-job",
|
||||||
|
AuditLog = "audit-log-job"
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TQueueJobTypes = {
|
export type TQueueJobTypes = {
|
||||||
@@ -14,6 +18,10 @@ export type TQueueJobTypes = {
|
|||||||
payload: { rotationId: string };
|
payload: { rotationId: string };
|
||||||
name: QueueJobs.SecretRotation;
|
name: QueueJobs.SecretRotation;
|
||||||
};
|
};
|
||||||
|
[QueueName.AuditLog]: {
|
||||||
|
name: QueueJobs.AuditLog;
|
||||||
|
payload: TCreateAuditLogDTO;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TQueueServiceFactory = ReturnType<typeof queueServiceFactory>;
|
export type TQueueServiceFactory = ReturnType<typeof queueServiceFactory>;
|
||||||
@@ -65,7 +73,7 @@ export const queueServiceFactory = (redisUrl: string) => {
|
|||||||
name: T,
|
name: T,
|
||||||
job: TQueueJobTypes[T]["name"],
|
job: TQueueJobTypes[T]["name"],
|
||||||
data: TQueueJobTypes[T]["payload"],
|
data: TQueueJobTypes[T]["payload"],
|
||||||
opts: JobsOptions & { jobId: string }
|
opts: JobsOptions & { jobId?: string }
|
||||||
) => {
|
) => {
|
||||||
const q = queueContainer[name];
|
const q = queueContainer[name];
|
||||||
await q.add(job, data, opts);
|
await q.add(job, data, opts);
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import fp from "fastify-plugin";
|
||||||
|
|
||||||
|
import { UserAgentType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
|
import { ActorType } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
|
export const getUserAgentType = (userAgent: string | undefined) => {
|
||||||
|
if (userAgent === undefined) {
|
||||||
|
return UserAgentType.OTHER;
|
||||||
|
}
|
||||||
|
if (userAgent === UserAgentType.CLI) {
|
||||||
|
return UserAgentType.CLI;
|
||||||
|
}
|
||||||
|
if (userAgent === UserAgentType.K8_OPERATOR) {
|
||||||
|
return UserAgentType.K8_OPERATOR;
|
||||||
|
}
|
||||||
|
if (userAgent === UserAgentType.TERRAFORM) {
|
||||||
|
return UserAgentType.TERRAFORM;
|
||||||
|
}
|
||||||
|
if (userAgent.toLowerCase().includes("mozilla")) {
|
||||||
|
return UserAgentType.WEB;
|
||||||
|
}
|
||||||
|
if (userAgent.includes(UserAgentType.NODE_SDK)) {
|
||||||
|
return UserAgentType.NODE_SDK;
|
||||||
|
}
|
||||||
|
if (userAgent.includes(UserAgentType.PYTHON_SDK)) {
|
||||||
|
return UserAgentType.PYTHON_SDK;
|
||||||
|
}
|
||||||
|
return UserAgentType.OTHER;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const injectAuditLogInfo = fp(async (server: FastifyZodProvider) => {
|
||||||
|
server.decorateRequest("auditLogInfo", null);
|
||||||
|
server.addHook("onRequest", async (req) => {
|
||||||
|
if (!req.auth) return;
|
||||||
|
const userAgent = req.headers["user-agent"] ?? "";
|
||||||
|
const payload = {
|
||||||
|
ipAddress: req.realIp,
|
||||||
|
userAgent,
|
||||||
|
userAgentType: getUserAgentType(userAgent)
|
||||||
|
} as typeof req.auditLogInfo;
|
||||||
|
if (req.auth.actor === ActorType.USER) {
|
||||||
|
payload.actor = {
|
||||||
|
type: ActorType.USER,
|
||||||
|
metadata: {
|
||||||
|
email: req.auth.user.email,
|
||||||
|
userId: req.auth.userId
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
throw new BadRequestError({ message: "Missing logic for other actor" });
|
||||||
|
}
|
||||||
|
req.auditLogInfo = payload;
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -2,8 +2,13 @@ import { Knex } from "knex";
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { registerV1EERoutes } from "@app/ee/routes/v1";
|
import { registerV1EERoutes } from "@app/ee/routes/v1";
|
||||||
|
import { auditLogDalFactory } from "@app/ee/services/audit-log/audit-log-dal";
|
||||||
|
import { auditLogQueueServiceFactory } from "@app/ee/services/audit-log/audit-log-queue";
|
||||||
|
import { auditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-service";
|
||||||
import { permissionDalFactory } from "@app/ee/services/permission/permission-dal";
|
import { permissionDalFactory } from "@app/ee/services/permission/permission-dal";
|
||||||
import { permissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { permissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||||
|
import { samlConfigDalFactory } from "@app/ee/services/saml-config/saml-config-dal";
|
||||||
|
import { samlConfigServiceFactory } from "@app/ee/services/saml-config/saml-config-service";
|
||||||
import { sapApproverDalFactory } from "@app/ee/services/secret-approval-policy/sap-approver-dal";
|
import { sapApproverDalFactory } from "@app/ee/services/secret-approval-policy/sap-approver-dal";
|
||||||
import { secretApprovalPolicyDalFactory } from "@app/ee/services/secret-approval-policy/secret-approval-policy-dal";
|
import { secretApprovalPolicyDalFactory } from "@app/ee/services/secret-approval-policy/secret-approval-policy-dal";
|
||||||
import { secretApprovalPolicyServiceFactory } from "@app/ee/services/secret-approval-policy/secret-approval-policy-service";
|
import { secretApprovalPolicyServiceFactory } from "@app/ee/services/secret-approval-policy/secret-approval-policy-service";
|
||||||
@@ -43,6 +48,7 @@ import { integrationServiceFactory } from "@app/services/integration/integration
|
|||||||
import { integrationAuthDalFactory } from "@app/services/integration-auth/integration-auth-dal";
|
import { integrationAuthDalFactory } from "@app/services/integration-auth/integration-auth-dal";
|
||||||
import { integrationAuthServiceFactory } from "@app/services/integration-auth/integration-auth-service";
|
import { integrationAuthServiceFactory } from "@app/services/integration-auth/integration-auth-service";
|
||||||
import { incidentContactDalFactory } from "@app/services/org/incident-contacts-dal";
|
import { incidentContactDalFactory } from "@app/services/org/incident-contacts-dal";
|
||||||
|
import { orgBotDalFactory } from "@app/services/org/org-bot-dal";
|
||||||
import { orgDalFactory } from "@app/services/org/org-dal";
|
import { orgDalFactory } from "@app/services/org/org-dal";
|
||||||
import { orgRoleDalFactory } from "@app/services/org/org-role-dal";
|
import { orgRoleDalFactory } from "@app/services/org/org-role-dal";
|
||||||
import { orgRoleServiceFactory } from "@app/services/org/org-role-service";
|
import { orgRoleServiceFactory } from "@app/services/org/org-role-service";
|
||||||
@@ -80,6 +86,7 @@ import { userServiceFactory } from "@app/services/user/user-service";
|
|||||||
import { webhookDalFactory } from "@app/services/webhook/webhook-dal";
|
import { webhookDalFactory } from "@app/services/webhook/webhook-dal";
|
||||||
import { webhookServiceFactory } from "@app/services/webhook/webhook-service";
|
import { webhookServiceFactory } from "@app/services/webhook/webhook-service";
|
||||||
|
|
||||||
|
import { injectAuditLogInfo } from "../plugins/audit-log";
|
||||||
import { injectIdentity } from "../plugins/auth/inject-identity";
|
import { injectIdentity } from "../plugins/auth/inject-identity";
|
||||||
import { injectPermission } from "../plugins/auth/inject-permission";
|
import { injectPermission } from "../plugins/auth/inject-permission";
|
||||||
import { registerV1Routes } from "./v1";
|
import { registerV1Routes } from "./v1";
|
||||||
@@ -99,6 +106,7 @@ export const registerRoutes = async (
|
|||||||
const authDal = authDalFactory(db);
|
const authDal = authDalFactory(db);
|
||||||
const authTokenDal = tokenDalFactory(db);
|
const authTokenDal = tokenDalFactory(db);
|
||||||
const orgDal = orgDalFactory(db);
|
const orgDal = orgDalFactory(db);
|
||||||
|
const orgBotDal = orgBotDalFactory(db);
|
||||||
const incidentContactDal = incidentContactDalFactory(db);
|
const incidentContactDal = incidentContactDalFactory(db);
|
||||||
const orgRoleDal = orgRoleDalFactory(db);
|
const orgRoleDal = orgRoleDalFactory(db);
|
||||||
const superAdminDal = superAdminDalFactory(db);
|
const superAdminDal = superAdminDalFactory(db);
|
||||||
@@ -132,8 +140,11 @@ export const registerRoutes = async (
|
|||||||
const identityUaDal = identityUaDalFactory(db);
|
const identityUaDal = identityUaDalFactory(db);
|
||||||
const identityUaClientSecretDal = identityUaClientSecretDalFactory(db);
|
const identityUaClientSecretDal = identityUaClientSecretDalFactory(db);
|
||||||
|
|
||||||
|
const auditLogDal = auditLogDalFactory(db);
|
||||||
|
|
||||||
// ee db layer ops
|
// ee db layer ops
|
||||||
const permissionDal = permissionDalFactory(db);
|
const permissionDal = permissionDalFactory(db);
|
||||||
|
const samlConfigDal = samlConfigDalFactory(db);
|
||||||
const sapApproverDal = sapApproverDalFactory(db);
|
const sapApproverDal = sapApproverDalFactory(db);
|
||||||
const secretApprovalPolicyDal = secretApprovalPolicyDalFactory(db);
|
const secretApprovalPolicyDal = secretApprovalPolicyDalFactory(db);
|
||||||
const secretApprovalRequestDal = secretApprovalRequestDalFactory(db);
|
const secretApprovalRequestDal = secretApprovalRequestDalFactory(db);
|
||||||
@@ -146,6 +157,8 @@ export const registerRoutes = async (
|
|||||||
const snapshotFolderDal = snapshotFolderDalFactory(db);
|
const snapshotFolderDal = snapshotFolderDalFactory(db);
|
||||||
|
|
||||||
const permissionService = permissionServiceFactory({ permissionDal, orgRoleDal, projectRoleDal });
|
const permissionService = permissionServiceFactory({ permissionDal, orgRoleDal, projectRoleDal });
|
||||||
|
const auditLogQueue = auditLogQueueServiceFactory({ auditLogDal, queueService });
|
||||||
|
const auditLogService = auditLogServiceFactory({ auditLogDal, permissionService, auditLogQueue });
|
||||||
const sapService = secretApprovalPolicyServiceFactory({
|
const sapService = secretApprovalPolicyServiceFactory({
|
||||||
projectMembershipDal,
|
projectMembershipDal,
|
||||||
projectEnvDal,
|
projectEnvDal,
|
||||||
@@ -153,6 +166,13 @@ export const registerRoutes = async (
|
|||||||
permissionService,
|
permissionService,
|
||||||
secretApprovalPolicyDal
|
secretApprovalPolicyDal
|
||||||
});
|
});
|
||||||
|
const samlService = samlConfigServiceFactory({
|
||||||
|
permissionService,
|
||||||
|
orgBotDal,
|
||||||
|
orgDal,
|
||||||
|
userDal,
|
||||||
|
samlConfigDal
|
||||||
|
});
|
||||||
const sarService = secretApprovalRequestServiceFactory({
|
const sarService = secretApprovalRequestServiceFactory({
|
||||||
permissionService,
|
permissionService,
|
||||||
folderDal,
|
folderDal,
|
||||||
@@ -180,7 +200,8 @@ export const registerRoutes = async (
|
|||||||
incidentContactDal,
|
incidentContactDal,
|
||||||
tokenService,
|
tokenService,
|
||||||
smtpService,
|
smtpService,
|
||||||
userDal
|
userDal,
|
||||||
|
orgBotDal
|
||||||
});
|
});
|
||||||
const signupService = authSignupServiceFactory({
|
const signupService = authSignupServiceFactory({
|
||||||
tokenService,
|
tokenService,
|
||||||
@@ -354,7 +375,9 @@ export const registerRoutes = async (
|
|||||||
secretApprovalPolicy: sapService,
|
secretApprovalPolicy: sapService,
|
||||||
secretApprovalRequest: sarService,
|
secretApprovalRequest: sarService,
|
||||||
secretRotation: secretRotationService,
|
secretRotation: secretRotationService,
|
||||||
snapshot: snapshotService
|
snapshot: snapshotService,
|
||||||
|
saml: samlService,
|
||||||
|
auditLog: auditLogService
|
||||||
});
|
});
|
||||||
|
|
||||||
server.decorate<FastifyZodProvider["store"]>("store", {
|
server.decorate<FastifyZodProvider["store"]>("store", {
|
||||||
@@ -363,6 +386,7 @@ export const registerRoutes = async (
|
|||||||
|
|
||||||
await server.register(injectIdentity);
|
await server.register(injectIdentity);
|
||||||
await server.register(injectPermission);
|
await server.register(injectPermission);
|
||||||
|
await server.register(injectAuditLogInfo);
|
||||||
|
|
||||||
server.route({
|
server.route({
|
||||||
url: "/status",
|
url: "/status",
|
||||||
@@ -394,9 +418,13 @@ export const registerRoutes = async (
|
|||||||
});
|
});
|
||||||
|
|
||||||
// register routes for v1
|
// register routes for v1
|
||||||
await server.register(registerV1Routes, { prefix: "/v1" });
|
await server.register(
|
||||||
|
async (v1Server) => {
|
||||||
|
await v1Server.register(registerV1EERoutes);
|
||||||
|
await v1Server.register(registerV1Routes);
|
||||||
|
},
|
||||||
|
{ prefix: "/v1" }
|
||||||
|
);
|
||||||
await server.register(registerV2Routes, { prefix: "/v2" });
|
await server.register(registerV2Routes, { prefix: "/v2" });
|
||||||
await server.register(registerV3Routes, { prefix: "/v3" });
|
await server.register(registerV3Routes, { prefix: "/v3" });
|
||||||
|
|
||||||
await server.register(registerV1EERoutes, { prefix: "/ee/v1" });
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { IdentitiesSchema, OrgMembershipRole } from "@app/db/schemas";
|
import { IdentitiesSchema, OrgMembershipRole } from "@app/db/schemas";
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
@@ -28,6 +29,19 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
|
|||||||
...req.body,
|
...req.body,
|
||||||
orgId: req.body.organizationId
|
orgId: req.body.organizationId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.body.organizationId,
|
||||||
|
event: {
|
||||||
|
type: EventType.CREATE_IDENTITY,
|
||||||
|
metadata: {
|
||||||
|
name: identity.name,
|
||||||
|
identityId: identity.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return { identity };
|
return { identity };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -57,6 +71,19 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
|
|||||||
id: req.params.identityId,
|
id: req.params.identityId,
|
||||||
...req.body
|
...req.body
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: identity.orgId,
|
||||||
|
event: {
|
||||||
|
type: EventType.UPDATE_IDENTITY,
|
||||||
|
metadata: {
|
||||||
|
name: identity.name,
|
||||||
|
identityId: identity.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return { identity };
|
return { identity };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -81,6 +108,17 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
|
|||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
id: req.params.identityId
|
id: req.params.identityId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: identity.orgId,
|
||||||
|
event: {
|
||||||
|
type: EventType.DELETE_IDENTITY,
|
||||||
|
metadata: {
|
||||||
|
identityId: identity.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { identity };
|
return { identity };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { IdentityUaClientSecretsSchema, IdentityUniversalAuthsSchema } from "@app/db/schemas";
|
import { IdentityUaClientSecretsSchema, IdentityUniversalAuthsSchema } from "@app/db/schemas";
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
import { TIdentityTrustedIp } from "@app/services/identity/identity-types";
|
||||||
|
|
||||||
export const sanitizedClientSecretSchema = IdentityUaClientSecretsSchema.pick({
|
export const sanitizedClientSecretSchema = IdentityUaClientSecretsSchema.pick({
|
||||||
id: true,
|
id: true,
|
||||||
@@ -36,10 +38,21 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { identityUa, accessToken } = await server.services.identityUa.login(
|
const { identityUa, accessToken, identityAccessToken, validClientSecretInfo } =
|
||||||
req.body.clientId,
|
await server.services.identityUa.login(req.body.clientId, req.body.clientSecret);
|
||||||
req.body.clientSecret
|
|
||||||
);
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
event: {
|
||||||
|
type: EventType.LOGIN_IDENTITY_UNIVERSAL_AUTH,
|
||||||
|
metadata: {
|
||||||
|
clientSecretId: validClientSecretInfo.id,
|
||||||
|
identityId: identityUa.identityId,
|
||||||
|
identityAccessTokenId: identityAccessToken.id,
|
||||||
|
identityUniversalAuthId: identityUa.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return {
|
return {
|
||||||
accessToken,
|
accessToken,
|
||||||
tokenType: "Bearer" as const,
|
tokenType: "Bearer" as const,
|
||||||
@@ -102,6 +115,24 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
|||||||
...req.body,
|
...req.body,
|
||||||
identityId: req.params.identityId
|
identityId: req.params.identityId
|
||||||
});
|
});
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: identityUniversalAuth.orgId,
|
||||||
|
event: {
|
||||||
|
type: EventType.ADD_IDENTITY_UNIVERSAL_AUTH,
|
||||||
|
metadata: {
|
||||||
|
identityId: identityUniversalAuth.identityId,
|
||||||
|
accessTokenTTL: identityUniversalAuth.accessTokenTTL,
|
||||||
|
accessTokenMaxTTL: identityUniversalAuth.accessTokenMaxTTL,
|
||||||
|
accessTokenTrustedIps:
|
||||||
|
identityUniversalAuth.accessTokenTrustedIps as TIdentityTrustedIp[],
|
||||||
|
clientSecretTrustedIps:
|
||||||
|
identityUniversalAuth.clientSecretTrustedIps as TIdentityTrustedIp[],
|
||||||
|
accessTokenNumUsesLimit: identityUniversalAuth.accessTokenNumUsesLimit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return { identityUniversalAuth };
|
return { identityUniversalAuth };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -152,6 +183,25 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
|||||||
...req.body,
|
...req.body,
|
||||||
identityId: req.params.identityId
|
identityId: req.params.identityId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: identityUniversalAuth.orgId,
|
||||||
|
event: {
|
||||||
|
type: EventType.UPDATE_IDENTITY_UNIVERSAL_AUTH,
|
||||||
|
metadata: {
|
||||||
|
identityId: identityUniversalAuth.identityId,
|
||||||
|
accessTokenTTL: identityUniversalAuth.accessTokenTTL,
|
||||||
|
accessTokenMaxTTL: identityUniversalAuth.accessTokenMaxTTL,
|
||||||
|
accessTokenTrustedIps:
|
||||||
|
identityUniversalAuth.accessTokenTrustedIps as TIdentityTrustedIp[],
|
||||||
|
clientSecretTrustedIps:
|
||||||
|
identityUniversalAuth.clientSecretTrustedIps as TIdentityTrustedIp[],
|
||||||
|
accessTokenNumUsesLimit: identityUniversalAuth.accessTokenNumUsesLimit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return { identityUniversalAuth };
|
return { identityUniversalAuth };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -176,6 +226,18 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
|||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
identityId: req.params.identityId
|
identityId: req.params.identityId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: identityUniversalAuth.orgId,
|
||||||
|
event: {
|
||||||
|
type: EventType.GET_IDENTITY_UNIVERSAL_AUTH,
|
||||||
|
metadata: {
|
||||||
|
identityId: identityUniversalAuth.identityId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return { identityUniversalAuth };
|
return { identityUniversalAuth };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -201,13 +263,26 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { clientSecret, clientSecretData } =
|
const { clientSecret, clientSecretData, orgId } =
|
||||||
await server.services.identityUa.createUaClientSecret({
|
await server.services.identityUa.createUaClientSecret({
|
||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
identityId: req.params.identityId,
|
identityId: req.params.identityId,
|
||||||
...req.body
|
...req.body
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId,
|
||||||
|
event: {
|
||||||
|
type: EventType.CREATE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET,
|
||||||
|
metadata: {
|
||||||
|
identityId: req.params.identityId,
|
||||||
|
clientSecretId: clientSecretData.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return { clientSecret, clientSecretData };
|
return { clientSecret, clientSecretData };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -227,10 +302,22 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const clientSecretData = await server.services.identityUa.getUaClientSecrets({
|
const { clientSecrets: clientSecretData, orgId } =
|
||||||
actor: req.permission.type,
|
await server.services.identityUa.getUaClientSecrets({
|
||||||
actorId: req.permission.id,
|
actor: req.permission.type,
|
||||||
identityId: req.params.identityId
|
actorId: req.permission.id,
|
||||||
|
identityId: req.params.identityId
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId,
|
||||||
|
event: {
|
||||||
|
type: EventType.GET_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRETS,
|
||||||
|
metadata: {
|
||||||
|
identityId: req.params.identityId
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { clientSecretData };
|
return { clientSecretData };
|
||||||
}
|
}
|
||||||
@@ -258,6 +345,19 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
|||||||
identityId: req.params.identityId,
|
identityId: req.params.identityId,
|
||||||
clientSecretId: req.params.clientSecretId
|
clientSecretId: req.params.clientSecretId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: clientSecretData.orgId,
|
||||||
|
event: {
|
||||||
|
type: EventType.REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET,
|
||||||
|
metadata: {
|
||||||
|
identityId: clientSecretData.identityId,
|
||||||
|
clientSecretId: clientSecretData.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return { clientSecretData };
|
return { clientSecretData };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
@@ -77,6 +78,18 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
|
|||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
id: req.params.integrationAuthId
|
id: req.params.integrationAuthId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: integrationAuth.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.UNAUTHORIZE_INTEGRATION,
|
||||||
|
metadata: {
|
||||||
|
integration: integrationAuth.integration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return { integrationAuth };
|
return { integrationAuth };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -85,6 +98,45 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
|
|||||||
url: "/oauth-token",
|
url: "/oauth-token",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
schema: {
|
||||||
|
body: z.object({
|
||||||
|
workspaceId: z.string().trim(),
|
||||||
|
code: z.string().trim(),
|
||||||
|
integration: z.string().trim(),
|
||||||
|
url: z.string().trim().url().optional()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
integrationAuth: integrationAuthPubSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const integrationAuth = await server.services.integrationAuth.oauthExchange({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actor: req.permission.type,
|
||||||
|
projectId: req.body.workspaceId,
|
||||||
|
...req.body
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: req.body.workspaceId,
|
||||||
|
event: {
|
||||||
|
type: EventType.AUTHORIZE_INTEGRATION,
|
||||||
|
metadata: {
|
||||||
|
integration: integrationAuth.integration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { integrationAuth };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/access-token",
|
||||||
|
method: "POST",
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
schema: {
|
schema: {
|
||||||
body: z.object({
|
body: z.object({
|
||||||
workspaceId: z.string().trim(),
|
workspaceId: z.string().trim(),
|
||||||
@@ -108,6 +160,17 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
|
|||||||
projectId: req.body.workspaceId,
|
projectId: req.body.workspaceId,
|
||||||
...req.body
|
...req.body
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: req.body.workspaceId,
|
||||||
|
event: {
|
||||||
|
type: EventType.AUTHORIZE_INTEGRATION,
|
||||||
|
metadata: {
|
||||||
|
integration: integrationAuth.integration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { integrationAuth };
|
return { integrationAuth };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { IntegrationsSchema } from "@app/db/schemas";
|
import { IntegrationsSchema } from "@app/db/schemas";
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
|
import { shake } from "@app/lib/fn";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
@@ -45,11 +47,33 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const integration = await server.services.integration.createIntegration({
|
const { integration, integrationAuth } = await server.services.integration.createIntegration({
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
...req.body
|
...req.body
|
||||||
});
|
});
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: integrationAuth.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.CREATE_INTEGRATION,
|
||||||
|
metadata: shake({
|
||||||
|
integrationId: integration.id.toString(),
|
||||||
|
integration: integration.integration,
|
||||||
|
environment: req.body.sourceEnvironment,
|
||||||
|
secretPath: req.body.secretPath,
|
||||||
|
url: integration.url,
|
||||||
|
app: integration.app,
|
||||||
|
appId: integration.appId,
|
||||||
|
targetEnvironment: integration.targetEnvironment,
|
||||||
|
targetEnvironmentId: integration.targetEnvironmentId,
|
||||||
|
targetService: integration.targetService,
|
||||||
|
targetServiceId: integration.targetServiceId,
|
||||||
|
path: integration.path,
|
||||||
|
region: integration.region
|
||||||
|
}) as any
|
||||||
|
}
|
||||||
|
});
|
||||||
return { integration };
|
return { integration };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -108,6 +132,29 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => {
|
|||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
id: req.params.integrationId
|
id: req.params.integrationId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: integration.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.DELETE_INTEGRATION,
|
||||||
|
metadata: shake({
|
||||||
|
integrationId: integration.id,
|
||||||
|
integration: integration.integration,
|
||||||
|
environment: integration.environment.slug,
|
||||||
|
secretPath: integration.secretPath,
|
||||||
|
url: integration.url,
|
||||||
|
app: integration.app,
|
||||||
|
appId: integration.appId,
|
||||||
|
targetEnvironment: integration.targetEnvironment,
|
||||||
|
targetEnvironmentId: integration.targetEnvironmentId,
|
||||||
|
targetService: integration.targetService,
|
||||||
|
targetServiceId: integration.targetServiceId,
|
||||||
|
path: integration.path,
|
||||||
|
region: integration.region
|
||||||
|
}) as any
|
||||||
|
}
|
||||||
|
});
|
||||||
return { integration };
|
return { integration };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { ProjectEnvironmentsSchema } from "@app/db/schemas";
|
import { ProjectEnvironmentsSchema } from "@app/db/schemas";
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
@@ -32,6 +33,18 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
|
|||||||
projectId: req.params.workspaceId,
|
projectId: req.params.workspaceId,
|
||||||
...req.body
|
...req.body
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: environment.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.CREATE_ENVIRONMENT,
|
||||||
|
metadata: {
|
||||||
|
name: environment.name,
|
||||||
|
slug: environment.slug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return {
|
return {
|
||||||
message: "Successfully created new environment",
|
message: "Successfully created new environment",
|
||||||
workspace: req.params.workspaceId,
|
workspace: req.params.workspaceId,
|
||||||
@@ -62,13 +75,28 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const environment = await server.services.projectEnv.updateEnvironment({
|
const { environment, old } = await server.services.projectEnv.updateEnvironment({
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
projectId: req.params.workspaceId,
|
projectId: req.params.workspaceId,
|
||||||
id: req.params.id,
|
id: req.params.id,
|
||||||
...req.body
|
...req.body
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: environment.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.UPDATE_ENVIRONMENT,
|
||||||
|
metadata: {
|
||||||
|
oldName: old.name,
|
||||||
|
oldSlug: old.slug,
|
||||||
|
newName: old.name,
|
||||||
|
newSlug: old.slug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
message: "Successfully updated environment",
|
message: "Successfully updated environment",
|
||||||
workspace: req.params.workspaceId,
|
workspace: req.params.workspaceId,
|
||||||
@@ -101,6 +129,19 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
|
|||||||
projectId: req.params.workspaceId,
|
projectId: req.params.workspaceId,
|
||||||
id: req.params.id
|
id: req.params.id
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: environment.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.DELETE_ENVIRONMENT,
|
||||||
|
metadata: {
|
||||||
|
slug: environment.slug,
|
||||||
|
name: environment.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
message: "Successfully deleted environment",
|
message: "Successfully deleted environment",
|
||||||
workspace: req.params.workspaceId,
|
workspace: req.params.workspaceId,
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { ProjectMembershipsSchema, UserEncryptionKeysSchema, UsersSchema } from "@app/db/schemas";
|
import {
|
||||||
|
OrgMembershipsSchema,
|
||||||
|
ProjectMembershipsSchema,
|
||||||
|
UserEncryptionKeysSchema,
|
||||||
|
UsersSchema
|
||||||
|
} from "@app/db/schemas";
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
@@ -42,6 +48,55 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/:workspaceId/memberships",
|
||||||
|
method: "POST",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
workspaceId: z.string().trim()
|
||||||
|
}),
|
||||||
|
body: z.object({
|
||||||
|
members: z
|
||||||
|
.object({
|
||||||
|
orgMembershipId: z.string().trim(),
|
||||||
|
workspaceEncryptedKey: z.string().trim(),
|
||||||
|
workspaceEncryptedNonce: z.string().trim()
|
||||||
|
})
|
||||||
|
.array()
|
||||||
|
.min(1)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
success: z.boolean(),
|
||||||
|
data: OrgMembershipsSchema.array()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const data = await server.services.projectMembership.addUsersToProject({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actor: req.permission.type,
|
||||||
|
projectId: req.params.workspaceId,
|
||||||
|
members: req.body.members
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: req.params.workspaceId,
|
||||||
|
...req.auditLogInfo,
|
||||||
|
event: {
|
||||||
|
type: EventType.ADD_BATCH_WORKSPACE_MEMBER,
|
||||||
|
metadata: data.map(({ userId }) => ({
|
||||||
|
userId: userId || "",
|
||||||
|
email: ""
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data, success: true };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
server.route({
|
server.route({
|
||||||
url: "/:workspaceId/memberships/:membershipId",
|
url: "/:workspaceId/memberships/:membershipId",
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
@@ -68,6 +123,20 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
|
|||||||
membershipId: req.params.membershipId,
|
membershipId: req.params.membershipId,
|
||||||
role: req.body.role
|
role: req.body.role
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: req.params.workspaceId,
|
||||||
|
event: {
|
||||||
|
type: EventType.UPDATE_USER_WORKSPACE_ROLE,
|
||||||
|
metadata: {
|
||||||
|
userId: membership.userId,
|
||||||
|
newRole: req.body.role,
|
||||||
|
oldRole: membership.role,
|
||||||
|
email: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { membership };
|
return { membership };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -94,6 +163,18 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
|
|||||||
projectId: req.params.workspaceId,
|
projectId: req.params.workspaceId,
|
||||||
membershipId: req.params.membershipId
|
membershipId: req.params.membershipId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: req.params.workspaceId,
|
||||||
|
event: {
|
||||||
|
type: EventType.REMOVE_WORKSPACE_MEMBER,
|
||||||
|
metadata: {
|
||||||
|
userId: membership.userId,
|
||||||
|
email: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { membership };
|
return { membership };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
UserEncryptionKeysSchema,
|
UserEncryptionKeysSchema,
|
||||||
UsersSchema
|
UsersSchema
|
||||||
} from "@app/db/schemas";
|
} from "@app/db/schemas";
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
@@ -265,6 +266,18 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
|||||||
projectId: req.params.workspaceId,
|
projectId: req.params.workspaceId,
|
||||||
email: req.body.email
|
email: req.body.email
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: req.params.workspaceId,
|
||||||
|
event: {
|
||||||
|
type: EventType.ADD_WORKSPACE_MEMBER,
|
||||||
|
metadata: {
|
||||||
|
userId: invitee.id,
|
||||||
|
email: invitee.email
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { invitee, latestKey };
|
return { invitee, latestKey };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { SecretFoldersSchema } from "@app/db/schemas";
|
import { SecretFoldersSchema } from "@app/db/schemas";
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
@@ -28,6 +29,19 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
|
|||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
...req.body
|
...req.body
|
||||||
});
|
});
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: req.body.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.CREATE_FOLDER,
|
||||||
|
metadata: {
|
||||||
|
environment: req.body.environment,
|
||||||
|
folderId: folder.id,
|
||||||
|
folderName: folder.name,
|
||||||
|
folderPath: req.body.path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { folder };
|
return { folder };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -53,12 +67,26 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const folder = await server.services.folder.updateFolder({
|
const { folder, old } = await server.services.folder.updateFolder({
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
...req.body,
|
...req.body,
|
||||||
id: req.params.folderId
|
id: req.params.folderId
|
||||||
});
|
});
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: req.body.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.UPDATE_FOLDER,
|
||||||
|
metadata: {
|
||||||
|
environment: req.body.environment,
|
||||||
|
folderId: folder.id,
|
||||||
|
folderPath: req.body.path,
|
||||||
|
newFolderName: folder.name,
|
||||||
|
oldFolderName: old.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { folder };
|
return { folder };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -89,6 +117,19 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
|
|||||||
...req.body,
|
...req.body,
|
||||||
id: req.params.folderId
|
id: req.params.folderId
|
||||||
});
|
});
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: req.body.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.DELETE_FOLDER,
|
||||||
|
metadata: {
|
||||||
|
environment: req.body.environment,
|
||||||
|
folderId: folder.id,
|
||||||
|
folderPath: req.body.path,
|
||||||
|
folderName: folder.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { folder };
|
return { folder };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { SecretImportsSchema, SecretsSchema } from "@app/db/schemas";
|
import { SecretImportsSchema, SecretsSchema } from "@app/db/schemas";
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
@@ -37,6 +38,22 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
|
|||||||
...req.body,
|
...req.body,
|
||||||
data: req.body.import
|
data: req.body.import
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: req.body.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.CREATE_SECRET_IMPORT,
|
||||||
|
metadata: {
|
||||||
|
secretImportId: secretImport.id,
|
||||||
|
folderId: secretImport.folderId,
|
||||||
|
importFromSecretPath: secretImport.importPath,
|
||||||
|
importFromEnvironment: secretImport.importEnv.slug,
|
||||||
|
importToEnvironment: req.body.environment,
|
||||||
|
importToSecretPath: req.body.path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { message: "Successfully created secret import", secretImport };
|
return { message: "Successfully created secret import", secretImport };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -78,6 +95,22 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
|
|||||||
...req.body,
|
...req.body,
|
||||||
data: req.body.import
|
data: req.body.import
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: req.body.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.UPDATE_SECRET_IMPORT,
|
||||||
|
metadata: {
|
||||||
|
secretImportId: secretImport.id,
|
||||||
|
folderId: secretImport.folderId,
|
||||||
|
position: secretImport.position,
|
||||||
|
importToEnvironment: req.body.environment,
|
||||||
|
importToSecretPath: req.body.path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return { message: "Successfully updated secret import", secretImport };
|
return { message: "Successfully updated secret import", secretImport };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -113,6 +146,22 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
|
|||||||
id: req.params.secretImportId,
|
id: req.params.secretImportId,
|
||||||
...req.body
|
...req.body
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: req.body.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.DELETE_SECRET_IMPORT,
|
||||||
|
metadata: {
|
||||||
|
secretImportId: secretImport.id,
|
||||||
|
folderId: secretImport.folderId,
|
||||||
|
importFromEnvironment: secretImport.importEnv.slug,
|
||||||
|
importFromSecretPath: secretImport.importPath,
|
||||||
|
importToEnvironment: req.body.environment,
|
||||||
|
importToSecretPath: req.body.path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { message: "Successfully deleted secret import", secretImport };
|
return { message: "Successfully deleted secret import", secretImport };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -146,6 +195,19 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
|
|||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
...req.query
|
...req.query
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: req.query.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.GET_SECRET_IMPORTS,
|
||||||
|
metadata: {
|
||||||
|
environment: req.query.environment,
|
||||||
|
folderId: secretImports?.[0]?.folderId,
|
||||||
|
numberOfImports: secretImports.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { message: "Successfully fetched secret imports", secretImports };
|
return { message: "Successfully fetched secret imports", secretImports };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { WebhooksSchema } from "@app/db/schemas";
|
import { WebhooksSchema } from "@app/db/schemas";
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
@@ -9,10 +10,10 @@ export const sanitizedWebhookSchema = WebhooksSchema.omit({
|
|||||||
iv: true,
|
iv: true,
|
||||||
tag: true,
|
tag: true,
|
||||||
algorithm: true,
|
algorithm: true,
|
||||||
keyEncoding: true,
|
keyEncoding: true
|
||||||
}).merge(
|
}).merge(
|
||||||
z.object({
|
z.object({
|
||||||
projectId:z.string(),
|
projectId: z.string(),
|
||||||
environment: z.object({
|
environment: z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
@@ -48,6 +49,22 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => {
|
|||||||
projectId: req.body.workspaceId,
|
projectId: req.body.workspaceId,
|
||||||
...req.body
|
...req.body
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: req.body.workspaceId,
|
||||||
|
event: {
|
||||||
|
type: EventType.CREATE_WEBHOOK,
|
||||||
|
metadata: {
|
||||||
|
environment: webhook.environment.slug,
|
||||||
|
webhookId: webhook.id,
|
||||||
|
isDisabled: webhook.isDisabled,
|
||||||
|
secretPath: webhook.secretPath,
|
||||||
|
webhookUrl: webhook.url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return { message: "Successfully created webhook", webhook };
|
return { message: "Successfully created webhook", webhook };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -77,6 +94,22 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => {
|
|||||||
id: req.params.webhookId,
|
id: req.params.webhookId,
|
||||||
isDisabled: req.body.isDisabled
|
isDisabled: req.body.isDisabled
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: webhook.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.UPDATE_WEBHOOK_STATUS,
|
||||||
|
metadata: {
|
||||||
|
environment: webhook.environment.slug,
|
||||||
|
webhookId: webhook.id,
|
||||||
|
isDisabled: webhook.isDisabled,
|
||||||
|
secretPath: webhook.secretPath,
|
||||||
|
webhookUrl: webhook.url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return { message: "Successfully updated webhook", webhook };
|
return { message: "Successfully updated webhook", webhook };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -96,6 +129,22 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => {
|
|||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
id: req.params.webhookId
|
id: req.params.webhookId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: webhook.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.DELETE_WEBHOOK,
|
||||||
|
metadata: {
|
||||||
|
environment: webhook.environment.slug,
|
||||||
|
webhookId: webhook.id,
|
||||||
|
isDisabled: webhook.isDisabled,
|
||||||
|
secretPath: webhook.secretPath,
|
||||||
|
webhookUrl: webhook.url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return { message: "Successfully deleted webhook", webhook };
|
return { message: "Successfully deleted webhook", webhook };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { ProjectKeysSchema } from "@app/db/schemas";
|
import { ProjectKeysSchema } from "@app/db/schemas";
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
@@ -30,6 +31,17 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
|||||||
projectId: req.params.workspaceId
|
projectId: req.params.workspaceId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: req.params.workspaceId,
|
||||||
|
event: {
|
||||||
|
type: EventType.GET_WORKSPACE_KEY,
|
||||||
|
metadata: {
|
||||||
|
keyId: key.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { ServiceTokensSchema } from "@app/db/schemas";
|
import { ServiceTokensSchema } from "@app/db/schemas";
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
@@ -68,6 +69,18 @@ export const registerServiceTokenRouter = async (server: FastifyZodProvider) =>
|
|||||||
...req.body,
|
...req.body,
|
||||||
projectId: req.body.workspaceId
|
projectId: req.body.workspaceId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: serviceToken.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.CREATE_SERVICE_TOKEN,
|
||||||
|
metadata: {
|
||||||
|
name: serviceToken.name,
|
||||||
|
scopes: req.body.scopes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { serviceToken: token, serviceTokenData: serviceToken };
|
return { serviceToken: token, serviceTokenData: serviceToken };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -92,6 +105,19 @@ export const registerServiceTokenRouter = async (server: FastifyZodProvider) =>
|
|||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
id: req.params.serviceTokenId
|
id: req.params.serviceTokenId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: serviceTokenData.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.DELETE_SERVICE_TOKEN,
|
||||||
|
metadata: {
|
||||||
|
name: serviceTokenData.name,
|
||||||
|
scopes: serviceTokenData.scopes as Array<{ environment: string; secretPath: string }>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return { serviceTokenData };
|
return { serviceTokenData };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { SecretApprovalRequestsSchema, SecretsSchema, SecretType } from "@app/db/schemas";
|
import { SecretApprovalRequestsSchema, SecretsSchema, SecretType } from "@app/db/schemas";
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { CommitType } from "@app/ee/services/secret-approval-request/secret-approval-request-types";
|
import { CommitType } from "@app/ee/services/secret-approval-request/secret-approval-request-types";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { ActorType, AuthMode } from "@app/services/auth/auth-type";
|
import { ActorType, AuthMode } from "@app/services/auth/auth-type";
|
||||||
@@ -35,6 +36,19 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
path: req.query.secretPath
|
path: req.query.secretPath
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: req.query.workspaceId,
|
||||||
|
...req.auditLogInfo,
|
||||||
|
event: {
|
||||||
|
type: EventType.GET_SECRETS,
|
||||||
|
metadata: {
|
||||||
|
environment: req.query.environment,
|
||||||
|
secretPath: req.query.secretPath,
|
||||||
|
numberOfSecrets: secrets.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return { secrets };
|
return { secrets };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -74,6 +88,20 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
type: req.query.type
|
type: req.query.type
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: req.query.workspaceId,
|
||||||
|
...req.auditLogInfo,
|
||||||
|
event: {
|
||||||
|
type: EventType.GET_SECRET,
|
||||||
|
metadata: {
|
||||||
|
environment: req.query.environment,
|
||||||
|
secretPath: req.query.secretPath,
|
||||||
|
secretId: secret.id,
|
||||||
|
secretKey: req.params.secretName,
|
||||||
|
secretVersion: secret.version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { secret };
|
return { secret };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -167,6 +195,19 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: req.body.workspaceId,
|
||||||
|
...req.auditLogInfo,
|
||||||
|
event: {
|
||||||
|
type: EventType.SECRET_APPROVAL_REQUEST,
|
||||||
|
metadata: {
|
||||||
|
committedBy: approval.committerId,
|
||||||
|
secretApprovalRequestId: approval.id,
|
||||||
|
secretApprovalRequestSlug: approval.slug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { approval };
|
return { approval };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,6 +232,20 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
metadata
|
metadata
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: req.body.workspaceId,
|
||||||
|
...req.auditLogInfo,
|
||||||
|
event: {
|
||||||
|
type: EventType.CREATE_SECRET,
|
||||||
|
metadata: {
|
||||||
|
environment: req.body.environment,
|
||||||
|
secretPath: req.body.secretPath,
|
||||||
|
secretId: secret.id,
|
||||||
|
secretKey: req.params.secretName,
|
||||||
|
secretVersion: secret.version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { secret };
|
return { secret };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -296,6 +351,19 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: req.body.workspaceId,
|
||||||
|
...req.auditLogInfo,
|
||||||
|
event: {
|
||||||
|
type: EventType.SECRET_APPROVAL_REQUEST,
|
||||||
|
metadata: {
|
||||||
|
committedBy: approval.committerId,
|
||||||
|
secretApprovalRequestId: approval.id,
|
||||||
|
secretApprovalRequestSlug: approval.slug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { approval };
|
return { approval };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -325,6 +393,20 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
newSecretName
|
newSecretName
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: req.body.workspaceId,
|
||||||
|
...req.auditLogInfo,
|
||||||
|
event: {
|
||||||
|
type: EventType.UPDATE_SECRET,
|
||||||
|
metadata: {
|
||||||
|
environment: req.body.environment,
|
||||||
|
secretPath: req.body.secretPath,
|
||||||
|
secretId: secret.id,
|
||||||
|
secretKey: req.params.secretName,
|
||||||
|
secretVersion: secret.version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { secret };
|
return { secret };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -382,6 +464,19 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: req.body.workspaceId,
|
||||||
|
...req.auditLogInfo,
|
||||||
|
event: {
|
||||||
|
type: EventType.SECRET_APPROVAL_REQUEST,
|
||||||
|
metadata: {
|
||||||
|
committedBy: approval.committerId,
|
||||||
|
secretApprovalRequestId: approval.id,
|
||||||
|
secretApprovalRequestSlug: approval.slug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { approval };
|
return { approval };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -397,6 +492,20 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
secretId
|
secretId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: req.body.workspaceId,
|
||||||
|
...req.auditLogInfo,
|
||||||
|
event: {
|
||||||
|
type: EventType.DELETE_SECRET,
|
||||||
|
metadata: {
|
||||||
|
environment: req.body.environment,
|
||||||
|
secretPath: req.body.secretPath,
|
||||||
|
secretId: secret.id,
|
||||||
|
secretKey: req.params.secretName,
|
||||||
|
secretVersion: secret.version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { secret };
|
return { secret };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -463,6 +572,19 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
[CommitType.Create]: inputSecrets.filter(({ type }) => type === "shared")
|
[CommitType.Create]: inputSecrets.filter(({ type }) => type === "shared")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: req.body.workspaceId,
|
||||||
|
...req.auditLogInfo,
|
||||||
|
event: {
|
||||||
|
type: EventType.SECRET_APPROVAL_REQUEST,
|
||||||
|
metadata: {
|
||||||
|
committedBy: approval.committerId,
|
||||||
|
secretApprovalRequestId: approval.id,
|
||||||
|
secretApprovalRequestSlug: approval.slug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { approval };
|
return { approval };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -476,6 +598,22 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
secrets: inputSecrets
|
secrets: inputSecrets
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: req.body.workspaceId,
|
||||||
|
...req.auditLogInfo,
|
||||||
|
event: {
|
||||||
|
type: EventType.CREATE_SECRETS,
|
||||||
|
metadata: {
|
||||||
|
environment: req.body.environment,
|
||||||
|
secretPath: req.body.secretPath,
|
||||||
|
secrets: secrets.map((secret, i) => ({
|
||||||
|
secretId: secret.id,
|
||||||
|
secretKey: inputSecrets[i].secretName,
|
||||||
|
secretVersion: secret.version
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { secrets };
|
return { secrets };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -542,6 +680,19 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
[CommitType.Update]: inputSecrets.filter(({ type }) => type === "shared")
|
[CommitType.Update]: inputSecrets.filter(({ type }) => type === "shared")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: req.body.workspaceId,
|
||||||
|
...req.auditLogInfo,
|
||||||
|
event: {
|
||||||
|
type: EventType.SECRET_APPROVAL_REQUEST,
|
||||||
|
metadata: {
|
||||||
|
committedBy: approval.committerId,
|
||||||
|
secretApprovalRequestId: approval.id,
|
||||||
|
secretApprovalRequestSlug: approval.slug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { approval };
|
return { approval };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -554,6 +705,22 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
secrets: inputSecrets
|
secrets: inputSecrets
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: req.body.workspaceId,
|
||||||
|
...req.auditLogInfo,
|
||||||
|
event: {
|
||||||
|
type: EventType.UPDATE_SECRETS,
|
||||||
|
metadata: {
|
||||||
|
environment: req.body.environment,
|
||||||
|
secretPath: req.body.secretPath,
|
||||||
|
secrets: secrets.map((secret, i) => ({
|
||||||
|
secretId: secret.id,
|
||||||
|
secretKey: inputSecrets[i].secretName,
|
||||||
|
secretVersion: secret.version
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { secrets };
|
return { secrets };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -609,6 +776,18 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
[CommitType.Delete]: inputSecrets.filter(({ type }) => type === "shared")
|
[CommitType.Delete]: inputSecrets.filter(({ type }) => type === "shared")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: req.body.workspaceId,
|
||||||
|
...req.auditLogInfo,
|
||||||
|
event: {
|
||||||
|
type: EventType.SECRET_APPROVAL_REQUEST,
|
||||||
|
metadata: {
|
||||||
|
committedBy: approval.committerId,
|
||||||
|
secretApprovalRequestId: approval.id,
|
||||||
|
secretApprovalRequestSlug: approval.slug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { approval };
|
return { approval };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -621,6 +800,22 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
secrets: inputSecrets
|
secrets: inputSecrets
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: req.body.workspaceId,
|
||||||
|
...req.auditLogInfo,
|
||||||
|
event: {
|
||||||
|
type: EventType.DELETE_SECRETS,
|
||||||
|
metadata: {
|
||||||
|
environment: req.body.environment,
|
||||||
|
secretPath: req.body.secretPath,
|
||||||
|
secrets: secrets.map((secret, i) => ({
|
||||||
|
secretId: secret.id,
|
||||||
|
secretKey: inputSecrets[i].secretName,
|
||||||
|
secretVersion: secret.version
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return { secrets };
|
return { secrets };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ export enum AuthMode {
|
|||||||
export enum ActorType { // would extend to AWS, Azure, ...
|
export enum ActorType { // would extend to AWS, Azure, ...
|
||||||
USER = "user", // userIdentity
|
USER = "user", // userIdentity
|
||||||
SERVICE = "service",
|
SERVICE = "service",
|
||||||
IDENTITY = "identity"
|
IDENTITY = "identity",
|
||||||
|
Machine = "machine"
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AuthModeJwtTokenPayload = {
|
export type AuthModeJwtTokenPayload = {
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ export const identityUaServiceFactory = ({
|
|||||||
: identityAccessToken.accessTokenMaxTTL
|
: identityAccessToken.accessTokenMaxTTL
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return { accessToken, identityUa };
|
return { accessToken, identityUa, validClientSecretInfo, identityAccessToken };
|
||||||
};
|
};
|
||||||
|
|
||||||
const attachUa = async ({
|
const attachUa = async ({
|
||||||
@@ -216,7 +216,7 @@ export const identityUaServiceFactory = ({
|
|||||||
);
|
);
|
||||||
return doc;
|
return doc;
|
||||||
});
|
});
|
||||||
return identityUa;
|
return { ...identityUa, orgId: identityMembershipOrg.orgId };
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateUa = async ({
|
const updateUa = async ({
|
||||||
@@ -295,7 +295,7 @@ export const identityUaServiceFactory = ({
|
|||||||
? JSON.stringify(reformattedAccessTokenTrustedIps)
|
? JSON.stringify(reformattedAccessTokenTrustedIps)
|
||||||
: undefined
|
: undefined
|
||||||
});
|
});
|
||||||
return updatedUaAuth;
|
return { ...updatedUaAuth, orgId: identityMembershipOrg.orgId };
|
||||||
};
|
};
|
||||||
|
|
||||||
const getIdentityUa = async ({ identityId, actorId, actor }: TGetUaDTO) => {
|
const getIdentityUa = async ({ identityId, actorId, actor }: TGetUaDTO) => {
|
||||||
@@ -317,7 +317,7 @@ export const identityUaServiceFactory = ({
|
|||||||
OrgPermissionActions.Read,
|
OrgPermissionActions.Read,
|
||||||
OrgPermissionSubjects.Identity
|
OrgPermissionSubjects.Identity
|
||||||
);
|
);
|
||||||
return uaIdentityAuth;
|
return { ...uaIdentityAuth, orgId: identityMembershipOrg.orgId };
|
||||||
};
|
};
|
||||||
|
|
||||||
const createUaClientSecret = async ({
|
const createUaClientSecret = async ({
|
||||||
@@ -375,7 +375,8 @@ export const identityUaServiceFactory = ({
|
|||||||
return {
|
return {
|
||||||
clientSecret,
|
clientSecret,
|
||||||
clientSecretData: identityUaClientSecret,
|
clientSecretData: identityUaClientSecret,
|
||||||
uaAuth: identityUniversalAuth
|
uaAuth: identityUniversalAuth,
|
||||||
|
orgId: identityMembershipOrg.orgId
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -415,7 +416,7 @@ export const identityUaServiceFactory = ({
|
|||||||
identityUAId: identityUniversalAuth.id,
|
identityUAId: identityUniversalAuth.id,
|
||||||
isClientSecretRevoked: false
|
isClientSecretRevoked: false
|
||||||
});
|
});
|
||||||
return clientSecrets;
|
return { clientSecrets, orgId: identityMembershipOrg.orgId };
|
||||||
};
|
};
|
||||||
|
|
||||||
const revokeUaClientSecret = async ({
|
const revokeUaClientSecret = async ({
|
||||||
@@ -454,7 +455,7 @@ export const identityUaServiceFactory = ({
|
|||||||
const clientSecret = await identityUaClientSecretDal.updateById(clientSecretId, {
|
const clientSecret = await identityUaClientSecretDal.updateById(clientSecretId, {
|
||||||
isClientSecretRevoked: true
|
isClientSecretRevoked: true
|
||||||
});
|
});
|
||||||
return clientSecret;
|
return { ...clientSecret, identityId, orgId: identityMembershipOrg.orgId };
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -111,8 +111,7 @@ export const identityServiceFactory = ({
|
|||||||
return newIdentity;
|
return newIdentity;
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO(akhilmhdh-pg): add audit log here
|
return { ...identity, orgId: identityOrgMembership.orgId };
|
||||||
return identity;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteIdentity = async ({ actorId, actor, id }: TDeleteIdentityDTO) => {
|
const deleteIdentity = async ({ actorId, actor, id }: TDeleteIdentityDTO) => {
|
||||||
@@ -139,7 +138,7 @@ export const identityServiceFactory = ({
|
|||||||
throw new ForbiddenRequestError({ message: "Failed to delete more privileged identity" });
|
throw new ForbiddenRequestError({ message: "Failed to delete more privileged identity" });
|
||||||
|
|
||||||
const deletedIdentity = await identityDal.deleteById(id);
|
const deletedIdentity = await identityDal.deleteById(id);
|
||||||
return deletedIdentity;
|
return { ...deletedIdentity, orgId: identityOrgMembership.orgId };
|
||||||
};
|
};
|
||||||
|
|
||||||
const listOrgIdentities = async ({ orgId, actor, actorId }: TOrgPermission) => {
|
const listOrgIdentities = async ({ orgId, actor, actorId }: TOrgPermission) => {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { IPType } from "@app/lib/ip";
|
||||||
import { TOrgPermission } from "@app/lib/types";
|
import { TOrgPermission } from "@app/lib/types";
|
||||||
|
|
||||||
export type TCreateIdentityDTO = {
|
export type TCreateIdentityDTO = {
|
||||||
@@ -14,3 +15,9 @@ export type TUpdateIdentityDTO = {
|
|||||||
export type TDeleteIdentityDTO = {
|
export type TDeleteIdentityDTO = {
|
||||||
id: string;
|
id: string;
|
||||||
} & Omit<TOrgPermission, "orgId">;
|
} & Omit<TOrgPermission, "orgId">;
|
||||||
|
|
||||||
|
export interface TIdentityTrustedIp {
|
||||||
|
ipAddress: string;
|
||||||
|
type: IPType;
|
||||||
|
prefix: number;
|
||||||
|
}
|
||||||
|
|||||||
@@ -998,7 +998,7 @@ export const integrationAuthServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
listIntegrationAuthByProjectId,
|
listIntegrationAuthByProjectId,
|
||||||
getIntegrationOptions,
|
getIntegrationOptions,
|
||||||
getIntegrationAuth,
|
getIntegrationAuth,
|
||||||
oauthExchange,
|
oauthExchange,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export type TGetIntegrationAuthDTO = {
|
|||||||
export type TOauthExchangeDTO = {
|
export type TOauthExchangeDTO = {
|
||||||
integration: string;
|
integration: string;
|
||||||
code: string;
|
code: string;
|
||||||
url: string;
|
url?: string;
|
||||||
} & TProjectPermission;
|
} & TProjectPermission;
|
||||||
|
|
||||||
export type TSaveIntegrationAccessTokenDTO = {
|
export type TSaveIntegrationAccessTokenDTO = {
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ export const integrationServiceFactory = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// TODO(akhilmhdh-pg): audit log
|
// TODO(akhilmhdh-pg): audit log
|
||||||
return integration;
|
return { integration, integrationAuth };
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateIntegration = async ({
|
const updateIntegration = async ({
|
||||||
@@ -150,7 +150,7 @@ export const integrationServiceFactory = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const deletedIntegration = await integrationDal.deleteById(id);
|
const deletedIntegration = await integrationDal.deleteById(id);
|
||||||
return deletedIntegration;
|
return { ...integration, ...deletedIntegration };
|
||||||
};
|
};
|
||||||
|
|
||||||
const listIntegrationByProject = async ({ actor, actorId, projectId }: TProjectPermission) => {
|
const listIntegrationByProject = async ({ actor, actorId, projectId }: TProjectPermission) => {
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { TDbClient } from "@app/db";
|
||||||
|
import { TableName } from "@app/db/schemas";
|
||||||
|
import { ormify } from "@app/lib/knex";
|
||||||
|
|
||||||
|
export type TOrgBotDalFactory = ReturnType<typeof orgBotDalFactory>;
|
||||||
|
|
||||||
|
export const orgBotDalFactory = (db: TDbClient) => {
|
||||||
|
const orgBotOrm = ormify(db, TableName.OrgBot);
|
||||||
|
return orgBotOrm;
|
||||||
|
};
|
||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
TOrgMembershipsUpdate
|
TOrgMembershipsUpdate
|
||||||
} from "@app/db/schemas";
|
} from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import { withTransaction } from "@app/lib/knex";
|
import { ormify, withTransaction } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TOrgDalFactory = ReturnType<typeof orgDalFactory>;
|
export type TOrgDalFactory = ReturnType<typeof orgDalFactory>;
|
||||||
|
|
||||||
@@ -110,14 +110,7 @@ export const orgDalFactory = (db: TDbClient) => {
|
|||||||
|
|
||||||
// MEMBERSHIP OPERATIONS
|
// MEMBERSHIP OPERATIONS
|
||||||
// --------------------
|
// --------------------
|
||||||
const findMembership = async (filter: Partial<TOrgMemberships>, tx?: Knex) => {
|
const orgMembershipOrm = ormify(db, TableName.OrgMembership);
|
||||||
try {
|
|
||||||
const membership = await (tx || db)(TableName.OrgMembership).where(filter);
|
|
||||||
return membership;
|
|
||||||
} catch (error) {
|
|
||||||
throw new DatabaseError({ error, name: "Find org membership" });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const createMembership = async (data: TOrgMembershipsInsert, tx?: Knex) => {
|
const createMembership = async (data: TOrgMembershipsInsert, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
@@ -175,7 +168,7 @@ export const orgDalFactory = (db: TDbClient) => {
|
|||||||
create,
|
create,
|
||||||
updateById,
|
updateById,
|
||||||
deleteById,
|
deleteById,
|
||||||
findMembership,
|
findMembership: orgMembershipOrm.find,
|
||||||
createMembership,
|
createMembership,
|
||||||
updateMembershipById,
|
updateMembershipById,
|
||||||
deleteMembershipById,
|
deleteMembershipById,
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import {
|
|||||||
} from "@app/ee/services/permission/org-permission";
|
} from "@app/ee/services/permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
|
import { generateAsymmetricKeyPair } from "@app/lib/crypto";
|
||||||
|
import { generateSymmetricKey, infisicalSymmetricEncypt } from "@app/lib/crypto/encryption";
|
||||||
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
|
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
|
||||||
import { isDisposableEmail } from "@app/lib/validator";
|
import { isDisposableEmail } from "@app/lib/validator";
|
||||||
|
|
||||||
@@ -17,6 +19,7 @@ import { TokenType } from "../auth-token/auth-token-types";
|
|||||||
import { SmtpTemplates, TSmtpService } from "../smtp/smtp-service";
|
import { SmtpTemplates, TSmtpService } from "../smtp/smtp-service";
|
||||||
import { TUserDalFactory } from "../user/user-dal";
|
import { TUserDalFactory } from "../user/user-dal";
|
||||||
import { TIncidentContactsDalFactory } from "./incident-contacts-dal";
|
import { TIncidentContactsDalFactory } from "./incident-contacts-dal";
|
||||||
|
import { TOrgBotDalFactory } from "./org-bot-dal";
|
||||||
import { TOrgDalFactory } from "./org-dal";
|
import { TOrgDalFactory } from "./org-dal";
|
||||||
import { TOrgRoleDalFactory } from "./org-role-dal";
|
import { TOrgRoleDalFactory } from "./org-role-dal";
|
||||||
import {
|
import {
|
||||||
@@ -28,6 +31,7 @@ import {
|
|||||||
|
|
||||||
type TOrgServiceFactoryDep = {
|
type TOrgServiceFactoryDep = {
|
||||||
orgDal: TOrgDalFactory;
|
orgDal: TOrgDalFactory;
|
||||||
|
orgBotDal: TOrgBotDalFactory;
|
||||||
orgRoleDal: TOrgRoleDalFactory;
|
orgRoleDal: TOrgRoleDalFactory;
|
||||||
userDal: TUserDalFactory;
|
userDal: TUserDalFactory;
|
||||||
incidentContactDal: TIncidentContactsDalFactory;
|
incidentContactDal: TIncidentContactsDalFactory;
|
||||||
@@ -45,7 +49,8 @@ export const orgServiceFactory = ({
|
|||||||
incidentContactDal,
|
incidentContactDal,
|
||||||
permissionService,
|
permissionService,
|
||||||
smtpService,
|
smtpService,
|
||||||
tokenService
|
tokenService,
|
||||||
|
orgBotDal
|
||||||
}: TOrgServiceFactoryDep) => {
|
}: TOrgServiceFactoryDep) => {
|
||||||
/*
|
/*
|
||||||
* Get organization details by the organization id
|
* Get organization details by the organization id
|
||||||
@@ -95,6 +100,23 @@ export const orgServiceFactory = ({
|
|||||||
* Create organization
|
* Create organization
|
||||||
* */
|
* */
|
||||||
const createOrganization = async (userId: string, orgName: string) => {
|
const createOrganization = async (userId: string, orgName: string) => {
|
||||||
|
const { privateKey, publicKey } = generateAsymmetricKeyPair();
|
||||||
|
const key = generateSymmetricKey();
|
||||||
|
const {
|
||||||
|
ciphertext: encryptedPrivateKey,
|
||||||
|
iv: privateKeyIV,
|
||||||
|
tag: privateKeyTag,
|
||||||
|
encoding: privateKeyKeyEncoding,
|
||||||
|
algorithm: privateKeyAlgorithm
|
||||||
|
} = infisicalSymmetricEncypt(privateKey);
|
||||||
|
const {
|
||||||
|
ciphertext: encryptedSymmetricKey,
|
||||||
|
iv: symmetricKeyIV,
|
||||||
|
tag: symmetricKeyTag,
|
||||||
|
encoding: symmetricKeyKeyEncoding,
|
||||||
|
algorithm: symmetricKeyAlgorithm
|
||||||
|
} = infisicalSymmetricEncypt(key);
|
||||||
|
|
||||||
const organization = await orgDal.transaction(async (tx) => {
|
const organization = await orgDal.transaction(async (tx) => {
|
||||||
const org = await orgDal.create({ name: orgName }, tx);
|
const org = await orgDal.create({ name: orgName }, tx);
|
||||||
await orgDal.createMembership(
|
await orgDal.createMembership(
|
||||||
@@ -106,6 +128,24 @@ export const orgServiceFactory = ({
|
|||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
|
await orgBotDal.create(
|
||||||
|
{
|
||||||
|
name: org.name,
|
||||||
|
publicKey,
|
||||||
|
privateKeyIV,
|
||||||
|
encryptedPrivateKey,
|
||||||
|
symmetricKeyIV,
|
||||||
|
symmetricKeyTag,
|
||||||
|
encryptedSymmetricKey,
|
||||||
|
symmetricKeyAlgorithm,
|
||||||
|
orgId: org.id,
|
||||||
|
privateKeyTag,
|
||||||
|
privateKeyAlgorithm,
|
||||||
|
privateKeyKeyEncoding,
|
||||||
|
symmetricKeyKeyEncoding
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
return org;
|
return org;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -178,7 +218,7 @@ export const orgServiceFactory = ({
|
|||||||
// Thus the signup flow is not needed anymore
|
// Thus the signup flow is not needed anymore
|
||||||
const [inviteeMembership] = await orgDal.findMembership(
|
const [inviteeMembership] = await orgDal.findMembership(
|
||||||
{ orgId, userId: inviteeUser.id },
|
{ orgId, userId: inviteeUser.id },
|
||||||
tx
|
{ tx }
|
||||||
);
|
);
|
||||||
if (inviteeMembership && inviteeMembership.status === OrgMembershipStatus.Accepted) {
|
if (inviteeMembership && inviteeMembership.status === OrgMembershipStatus.Accepted) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
|
|||||||
@@ -58,6 +58,9 @@ export const projectEnvServiceFactory = ({
|
|||||||
ProjectPermissionSub.Environments
|
ProjectPermissionSub.Environments
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const oldEnv = await projectEnvDal.findOne({ id, projectId });
|
||||||
|
if (!oldEnv) throw new BadRequestError({ message: "Environment not found" });
|
||||||
|
|
||||||
if (slug) {
|
if (slug) {
|
||||||
const existingEnv = await projectEnvDal.findOne({ slug });
|
const existingEnv = await projectEnvDal.findOne({ slug });
|
||||||
if (existingEnv && existingEnv.id !== id) {
|
if (existingEnv && existingEnv.id !== id) {
|
||||||
@@ -68,8 +71,8 @@ export const projectEnvServiceFactory = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const [env] = await projectEnvDal.update({ id, projectId }, { name, slug });
|
const env = await projectEnvDal.updateById(oldEnv.id, { name, slug });
|
||||||
return env;
|
return { environment: env, old: oldEnv };
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteEnvironment = async ({ projectId, actor, actorId, id }: TDeleteEnvDTO) => {
|
const deleteEnvironment = async ({ projectId, actor, actorId, id }: TDeleteEnvDTO) => {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
} from "@app/ee/services/permission/project-permission";
|
} from "@app/ee/services/permission/project-permission";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
|
import { groupBy } from "@app/lib/fn";
|
||||||
|
|
||||||
import { TOrgDalFactory } from "../org/org-dal";
|
import { TOrgDalFactory } from "../org/org-dal";
|
||||||
import { TProjectDalFactory } from "../project/project-dal";
|
import { TProjectDalFactory } from "../project/project-dal";
|
||||||
@@ -17,6 +18,7 @@ import { SmtpTemplates, TSmtpService } from "../smtp/smtp-service";
|
|||||||
import { TUserDalFactory } from "../user/user-dal";
|
import { TUserDalFactory } from "../user/user-dal";
|
||||||
import { TProjectMembershipDalFactory } from "./project-membership-dal";
|
import { TProjectMembershipDalFactory } from "./project-membership-dal";
|
||||||
import {
|
import {
|
||||||
|
TAddUsersToWorkspaceDTO,
|
||||||
TDeleteProjectMembershipDTO,
|
TDeleteProjectMembershipDTO,
|
||||||
TGetProjectMembershipDTO,
|
TGetProjectMembershipDTO,
|
||||||
TInviteUserToProjectDTO,
|
TInviteUserToProjectDTO,
|
||||||
@@ -31,7 +33,7 @@ type TProjectMembershipServiceFactoryDep = {
|
|||||||
projectRoleDal: Pick<TProjectRoleDalFactory, "findOne">;
|
projectRoleDal: Pick<TProjectRoleDalFactory, "findOne">;
|
||||||
orgDal: Pick<TOrgDalFactory, "findMembership">;
|
orgDal: Pick<TOrgDalFactory, "findMembership">;
|
||||||
projectDal: Pick<TProjectDalFactory, "findById">;
|
projectDal: Pick<TProjectDalFactory, "findById">;
|
||||||
projectKeyDal: Pick<TProjectKeyDalFactory, "findLatestProjectKey" | "delete">;
|
projectKeyDal: Pick<TProjectKeyDalFactory, "findLatestProjectKey" | "delete" | "insertMany">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TProjectMembershipServiceFactory = ReturnType<typeof projectMembershipServiceFactory>;
|
export type TProjectMembershipServiceFactory = ReturnType<typeof projectMembershipServiceFactory>;
|
||||||
@@ -122,6 +124,71 @@ export const projectMembershipServiceFactory = ({
|
|||||||
return { invitee, latestKey };
|
return { invitee, latestKey };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const addUsersToProject = async ({
|
||||||
|
projectId,
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
members
|
||||||
|
}: TAddUsersToWorkspaceDTO) => {
|
||||||
|
const project = await projectDal.findById(projectId);
|
||||||
|
if (!project) throw new BadRequestError({ message: "Project not found" });
|
||||||
|
|
||||||
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionSub.Member
|
||||||
|
);
|
||||||
|
const orgMembers = await orgDal.findMembership({
|
||||||
|
orgId: project.orgId,
|
||||||
|
$in: { id: members.map(({ orgMembershipId }) => orgMembershipId) }
|
||||||
|
});
|
||||||
|
if (orgMembers.length !== members.length)
|
||||||
|
throw new BadRequestError({ message: "Some users are not part of org" });
|
||||||
|
|
||||||
|
const existingMembers = await projectMembershipDal.find({
|
||||||
|
projectId,
|
||||||
|
$in: { userId: orgMembers.map(({ userId }) => userId).filter(Boolean) as string[] }
|
||||||
|
});
|
||||||
|
if (existingMembers.length)
|
||||||
|
throw new BadRequestError({ message: "Some users are already part of project" });
|
||||||
|
|
||||||
|
await projectMembershipDal.transaction(async (tx) => {
|
||||||
|
await projectMembershipDal.insertMany(
|
||||||
|
orgMembers.map(({ userId }) => ({
|
||||||
|
projectId,
|
||||||
|
userId: userId as string,
|
||||||
|
role: ProjectMembershipRole.Member
|
||||||
|
})),
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
const encKeyGroupByOrgMembId = groupBy(members, (i) => i.orgMembershipId);
|
||||||
|
await projectKeyDal.insertMany(
|
||||||
|
orgMembers.map(({ userId, id }) => ({
|
||||||
|
encryptedKey: encKeyGroupByOrgMembId[id][0].workspaceEncryptedKey,
|
||||||
|
nonce: encKeyGroupByOrgMembId[id][0].workspaceEncryptedNonce,
|
||||||
|
senderId: actorId,
|
||||||
|
receiverId: userId as string,
|
||||||
|
projectId
|
||||||
|
})),
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
});
|
||||||
|
const sender = await userDal.findById(actorId);
|
||||||
|
const appCfg = getConfig();
|
||||||
|
await smtpService.sendMail({
|
||||||
|
template: SmtpTemplates.WorkspaceInvite,
|
||||||
|
subjectLine: "Infisical workspace invitation",
|
||||||
|
recipients: orgMembers.map(({ userId }) => userId).filter(Boolean) as string[],
|
||||||
|
substitutions: {
|
||||||
|
inviterFirstName: sender.firstName,
|
||||||
|
inviterEmail: sender.email,
|
||||||
|
workspaceName: project.name,
|
||||||
|
callback_url: `${appCfg.SITE_URL}/login`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return orgMembers;
|
||||||
|
};
|
||||||
|
|
||||||
const updateProjectMembership = async ({
|
const updateProjectMembership = async ({
|
||||||
actorId,
|
actorId,
|
||||||
actor,
|
actor,
|
||||||
@@ -186,6 +253,7 @@ export const projectMembershipServiceFactory = ({
|
|||||||
getProjectMemberships,
|
getProjectMemberships,
|
||||||
inviteUserToProject,
|
inviteUserToProject,
|
||||||
updateProjectMembership,
|
updateProjectMembership,
|
||||||
deleteProjectMembership
|
deleteProjectMembership,
|
||||||
|
addUsersToProject
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,3 +14,11 @@ export type TUpdateProjectMembershipDTO = {
|
|||||||
export type TDeleteProjectMembershipDTO = {
|
export type TDeleteProjectMembershipDTO = {
|
||||||
membershipId: string;
|
membershipId: string;
|
||||||
} & TProjectPermission;
|
} & TProjectPermission;
|
||||||
|
|
||||||
|
export type TAddUsersToWorkspaceDTO = {
|
||||||
|
members: {
|
||||||
|
orgMembershipId: string;
|
||||||
|
workspaceEncryptedKey: string;
|
||||||
|
workspaceEncryptedNonce: string;
|
||||||
|
}[];
|
||||||
|
} & TProjectPermission;
|
||||||
|
|||||||
@@ -91,14 +91,16 @@ export const secretFolderServiceFactory = ({
|
|||||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
|
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const parentFolder = await folderDal.findBySecretPath(projectId, environment, path);
|
||||||
|
if (!parentFolder) throw new BadRequestError({ message: "Secret path not found" });
|
||||||
|
|
||||||
const env = await projectEnvDal.findOne({ projectId, slug: environment });
|
const env = await projectEnvDal.findOne({ projectId, slug: environment });
|
||||||
if (!env)
|
if (!env)
|
||||||
throw new BadRequestError({ message: "Environment not found", name: "Create folder" });
|
throw new BadRequestError({ message: "Environment not found", name: "Update folder" });
|
||||||
|
const folder = await folderDal.findOne({ envId: env.id, id, parentId: parentFolder.id });
|
||||||
const folder = await folderDal.transaction(async (tx) => {
|
if (!folder) throw new BadRequestError({ message: "Folder not found" });
|
||||||
const parentFolder = await folderDal.findBySecretPath(projectId, environment, path, tx);
|
|
||||||
if (!parentFolder) throw new BadRequestError({ message: "Secret path not found" });
|
|
||||||
|
|
||||||
|
const newFolder = await folderDal.transaction(async (tx) => {
|
||||||
const [doc] = await folderDal.update(
|
const [doc] = await folderDal.update(
|
||||||
{ envId: env.id, id, parentId: parentFolder.id },
|
{ envId: env.id, id, parentId: parentFolder.id },
|
||||||
{ name },
|
{ name },
|
||||||
@@ -117,8 +119,8 @@ export const secretFolderServiceFactory = ({
|
|||||||
return doc;
|
return doc;
|
||||||
});
|
});
|
||||||
|
|
||||||
await snapshotService.performSnapshot(folder.parentId as string);
|
await snapshotService.performSnapshot(newFolder.parentId as string);
|
||||||
return folder;
|
return { folder: newFolder, old: folder };
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteFolder = async ({
|
const deleteFolder = async ({
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ import {
|
|||||||
ProjectPermissionSub
|
ProjectPermissionSub
|
||||||
} from "@app/ee/services/permission/project-permission";
|
} from "@app/ee/services/permission/project-permission";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
|
import { groupBy } from "@app/lib/fn";
|
||||||
|
|
||||||
import { TProjectEnvDalFactory } from "../project-env/project-env-dal";
|
import { TProjectEnvDalFactory } from "../project-env/project-env-dal";
|
||||||
|
import { TSecretDalFactory } from "../secret/secret-dal";
|
||||||
import { TSecretFolderDalFactory } from "../secret-folder/secret-folder-dal";
|
import { TSecretFolderDalFactory } from "../secret-folder/secret-folder-dal";
|
||||||
import { TSecretImportDalFactory } from "./secret-import-dal";
|
import { TSecretImportDalFactory } from "./secret-import-dal";
|
||||||
import {
|
import {
|
||||||
@@ -17,8 +19,6 @@ import {
|
|||||||
TGetSecretsFromImportDTO,
|
TGetSecretsFromImportDTO,
|
||||||
TUpdateSecretImportDTO
|
TUpdateSecretImportDTO
|
||||||
} from "./secret-import-types";
|
} from "./secret-import-types";
|
||||||
import { TSecretDalFactory } from "../secret/secret-dal";
|
|
||||||
import { groupBy } from "@app/lib/fn";
|
|
||||||
|
|
||||||
type TSecretImportServiceFactoryDep = {
|
type TSecretImportServiceFactoryDep = {
|
||||||
secretImportDal: TSecretImportDalFactory;
|
secretImportDal: TSecretImportDalFactory;
|
||||||
|
|||||||
@@ -256,9 +256,10 @@ export const secretServiceFactory = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { keyName2BlindIndex } = await fnSecretBlindIndexCheck({
|
const { keyName2BlindIndex } = await fnSecretBlindIndexCheck({
|
||||||
inputSecrets: [{ secretName: inputSecret.secretName }],
|
inputSecrets: [{ secretName: inputSecret.secretName, type: inputSecret.type as SecretType }],
|
||||||
folderId,
|
folderId,
|
||||||
isNew: true,
|
isNew: true,
|
||||||
|
userId: actorId,
|
||||||
blindIndexCfg
|
blindIndexCfg
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -539,6 +540,7 @@ export const secretServiceFactory = ({
|
|||||||
fnSecretBulkInsert({
|
fnSecretBulkInsert({
|
||||||
inputSecrets: inputSecrets.map(({ secretName, ...el }) => ({
|
inputSecrets: inputSecrets.map(({ secretName, ...el }) => ({
|
||||||
...el,
|
...el,
|
||||||
|
version:0,
|
||||||
secretBlindIndex: keyName2BlindIndex[secretName],
|
secretBlindIndex: keyName2BlindIndex[secretName],
|
||||||
type: SecretType.Shared,
|
type: SecretType.Shared,
|
||||||
algorithm: SecretEncryptionAlgo.AES_256_GCM,
|
algorithm: SecretEncryptionAlgo.AES_256_GCM,
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export const useCreateProjectRole = () => {
|
|||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: ({ projectId, permissions, ...dto }: TCreateProjectRoleDTO) =>
|
mutationFn: ({ projectId, permissions, ...dto }: TCreateProjectRoleDTO) =>
|
||||||
apiRequest.post(`/api/ee/v1/workspace/${projectId}/roles`, {
|
apiRequest.post(`/api/v1/workspace/${projectId}/roles`, {
|
||||||
...dto,
|
...dto,
|
||||||
permissions: permissions.length ? packRules(permissions) : []
|
permissions: permissions.length ? packRules(permissions) : []
|
||||||
}),
|
}),
|
||||||
@@ -33,7 +33,7 @@ export const useUpdateProjectRole = () => {
|
|||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: ({ id, projectId, permissions, ...dto }: TUpdateProjectRoleDTO) =>
|
mutationFn: ({ id, projectId, permissions, ...dto }: TUpdateProjectRoleDTO) =>
|
||||||
apiRequest.patch(`/api/ee/v1/workspace/${projectId}/roles/${id}`, {
|
apiRequest.patch(`/api/v1/workspace/${projectId}/roles/${id}`, {
|
||||||
...dto,
|
...dto,
|
||||||
permissions: permissions?.length ? packRules(permissions) : []
|
permissions: permissions?.length ? packRules(permissions) : []
|
||||||
}),
|
}),
|
||||||
@@ -48,7 +48,7 @@ export const useDeleteProjectRole = () => {
|
|||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: ({ projectId, id }: TDeleteProjectRoleDTO) =>
|
mutationFn: ({ projectId, id }: TDeleteProjectRoleDTO) =>
|
||||||
apiRequest.delete(`/api/ee/v1/workspace/${projectId}/roles/${id}`, {
|
apiRequest.delete(`/api/v1/workspace/${projectId}/roles/${id}`, {
|
||||||
data: { projectId }
|
data: { projectId }
|
||||||
}),
|
}),
|
||||||
onSuccess: (_, { projectId }) => {
|
onSuccess: (_, { projectId }) => {
|
||||||
@@ -62,7 +62,7 @@ export const useCreateOrgRole = () => {
|
|||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: ({ orgId, permissions, ...dto }: TCreateOrgRoleDTO) =>
|
mutationFn: ({ orgId, permissions, ...dto }: TCreateOrgRoleDTO) =>
|
||||||
apiRequest.post(`/api/ee/v1/organization/${orgId}/roles`, {
|
apiRequest.post(`/api/v1/organization/${orgId}/roles`, {
|
||||||
...dto,
|
...dto,
|
||||||
permissions: permissions.length ? packRules(permissions) : []
|
permissions: permissions.length ? packRules(permissions) : []
|
||||||
}),
|
}),
|
||||||
@@ -77,7 +77,7 @@ export const useUpdateOrgRole = () => {
|
|||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: ({ id, orgId, permissions, ...dto }: TUpdateOrgRoleDTO) =>
|
mutationFn: ({ id, orgId, permissions, ...dto }: TUpdateOrgRoleDTO) =>
|
||||||
apiRequest.patch(`/api/ee/v1/organization/${orgId}/roles/${id}`, {
|
apiRequest.patch(`/api/v1/organization/${orgId}/roles/${id}`, {
|
||||||
...dto,
|
...dto,
|
||||||
permissions: permissions?.length ? packRules(permissions) : []
|
permissions: permissions?.length ? packRules(permissions) : []
|
||||||
}),
|
}),
|
||||||
@@ -92,7 +92,7 @@ export const useDeleteOrgRole = () => {
|
|||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: ({ orgId, id }: TDeleteOrgRoleDTO) =>
|
mutationFn: ({ orgId, id }: TDeleteOrgRoleDTO) =>
|
||||||
apiRequest.delete(`/api/ee/v1/organization/${orgId}/roles/${id}`, {
|
apiRequest.delete(`/api/v1/organization/${orgId}/roles/${id}`, {
|
||||||
data: { orgId }
|
data: { orgId }
|
||||||
}),
|
}),
|
||||||
onSuccess: (_, { orgId }) => {
|
onSuccess: (_, { orgId }) => {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export const roleQueryKeys = {
|
|||||||
const getProjectRoles = async (projectId: string) => {
|
const getProjectRoles = async (projectId: string) => {
|
||||||
const { data } = await apiRequest.get<{
|
const { data } = await apiRequest.get<{
|
||||||
data: { roles: Array<Omit<TProjectRole, "permissions"> & { permissions: unknown }> };
|
data: { roles: Array<Omit<TProjectRole, "permissions"> & { permissions: unknown }> };
|
||||||
}>(`/api/ee/v1/workspace/${projectId}/roles`);
|
}>(`/api/v1/workspace/${projectId}/roles`);
|
||||||
return data.data.roles.map(({ permissions, ...el }) => ({
|
return data.data.roles.map(({ permissions, ...el }) => ({
|
||||||
...el,
|
...el,
|
||||||
permissions: unpackRules(permissions as PackRule<TProjectPermission>[])
|
permissions: unpackRules(permissions as PackRule<TProjectPermission>[])
|
||||||
@@ -65,7 +65,7 @@ export const useGetProjectRoles = (projectId: string) =>
|
|||||||
const getOrgRoles = async (orgId: string) => {
|
const getOrgRoles = async (orgId: string) => {
|
||||||
const { data } = await apiRequest.get<{
|
const { data } = await apiRequest.get<{
|
||||||
data: { roles: Array<Omit<TOrgRole, "permissions"> & { permissions: unknown }> };
|
data: { roles: Array<Omit<TOrgRole, "permissions"> & { permissions: unknown }> };
|
||||||
}>(`/api/ee/v1/organization/${orgId}/roles`);
|
}>(`/api/v1/organization/${orgId}/roles`);
|
||||||
return data.data.roles.map(({ permissions, ...el }) => ({
|
return data.data.roles.map(({ permissions, ...el }) => ({
|
||||||
...el,
|
...el,
|
||||||
permissions: unpackRules(permissions as PackRule<TPermission>[])
|
permissions: unpackRules(permissions as PackRule<TPermission>[])
|
||||||
@@ -85,7 +85,7 @@ const getUserOrgPermissions = async ({ orgId }: TGetUserOrgPermissionsDTO) => {
|
|||||||
const { data } = await apiRequest.get<{
|
const { data } = await apiRequest.get<{
|
||||||
permissions: PackRule<RawRuleOf<MongoAbility<OrgPermissionSet>>>[];
|
permissions: PackRule<RawRuleOf<MongoAbility<OrgPermissionSet>>>[];
|
||||||
membership: OrgUser;
|
membership: OrgUser;
|
||||||
}>(`/api/ee/v1/organization/${orgId}/permissions`);
|
}>(`/api/v1/organization/${orgId}/permissions`);
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
@@ -105,7 +105,7 @@ export const useGetUserOrgPermissions = ({ orgId }: TGetUserOrgPermissionsDTO) =
|
|||||||
const getUserProjectPermissions = async ({ workspaceId }: TGetUserProjectPermissionDTO) => {
|
const getUserProjectPermissions = async ({ workspaceId }: TGetUserProjectPermissionDTO) => {
|
||||||
const { data } = await apiRequest.get<{
|
const { data } = await apiRequest.get<{
|
||||||
data: { permissions: PackRule<RawRuleOf<MongoAbility<OrgPermissionSet>>>[] };
|
data: { permissions: PackRule<RawRuleOf<MongoAbility<OrgPermissionSet>>>[] };
|
||||||
}>(`/api/ee/v1/workspace/${workspaceId}/permissions`, {});
|
}>(`/api/v1/workspace/${workspaceId}/permissions`, {});
|
||||||
|
|
||||||
return data.data.permissions;
|
return data.data.permissions;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export const useCreateSecretApprovalPolicy = () => {
|
|||||||
|
|
||||||
return useMutation<{}, {}, TCreateSecretPolicyDTO>({
|
return useMutation<{}, {}, TCreateSecretPolicyDTO>({
|
||||||
mutationFn: async ({ environment, workspaceId, approvals, approvers, secretPath, name }) => {
|
mutationFn: async ({ environment, workspaceId, approvals, approvers, secretPath, name }) => {
|
||||||
const { data } = await apiRequest.post("/api/ee/v1/secret-approvals", {
|
const { data } = await apiRequest.post("/api/v1/secret-approvals", {
|
||||||
environment,
|
environment,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
approvals,
|
approvals,
|
||||||
@@ -31,7 +31,7 @@ export const useUpdateSecretApprovalPolicy = () => {
|
|||||||
|
|
||||||
return useMutation<{}, {}, TUpdateSecretPolicyDTO>({
|
return useMutation<{}, {}, TUpdateSecretPolicyDTO>({
|
||||||
mutationFn: async ({ id, approvers, approvals, secretPath, name }) => {
|
mutationFn: async ({ id, approvers, approvals, secretPath, name }) => {
|
||||||
const { data } = await apiRequest.patch(`/api/ee/v1/secret-approvals/${id}`, {
|
const { data } = await apiRequest.patch(`/api/v1/secret-approvals/${id}`, {
|
||||||
approvals,
|
approvals,
|
||||||
approvers,
|
approvers,
|
||||||
secretPath,
|
secretPath,
|
||||||
@@ -50,7 +50,7 @@ export const useDeleteSecretApprovalPolicy = () => {
|
|||||||
|
|
||||||
return useMutation<{}, {}, TDeleteSecretPolicyDTO>({
|
return useMutation<{}, {}, TDeleteSecretPolicyDTO>({
|
||||||
mutationFn: async ({ id }) => {
|
mutationFn: async ({ id }) => {
|
||||||
const { data } = await apiRequest.delete(`/api/ee/v1/secret-approvals/${id}`);
|
const { data } = await apiRequest.delete(`/api/v1/secret-approvals/${id}`);
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
onSuccess: (_, { workspaceId }) => {
|
onSuccess: (_, { workspaceId }) => {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export const secretApprovalKeys = {
|
|||||||
|
|
||||||
const fetchApprovalPolicies = async (workspaceId: string) => {
|
const fetchApprovalPolicies = async (workspaceId: string) => {
|
||||||
const { data } = await apiRequest.get<{ approvals: TSecretApprovalPolicy[] }>(
|
const { data } = await apiRequest.get<{ approvals: TSecretApprovalPolicy[] }>(
|
||||||
"/api/ee/v1/secret-approvals",
|
"/api/v1/secret-approvals",
|
||||||
{ params: { workspaceId } }
|
{ params: { workspaceId } }
|
||||||
);
|
);
|
||||||
return data.approvals;
|
return data.approvals;
|
||||||
@@ -49,7 +49,7 @@ const fetchApprovalPolicyOfABoard = async (
|
|||||||
secretPath: string
|
secretPath: string
|
||||||
) => {
|
) => {
|
||||||
const { data } = await apiRequest.get<{ policy: TSecretApprovalPolicy }>(
|
const { data } = await apiRequest.get<{ policy: TSecretApprovalPolicy }>(
|
||||||
"/api/ee/v1/secret-approvals/board",
|
"/api/v1/secret-approvals/board",
|
||||||
{ params: { workspaceId, environment, secretPath } }
|
{ params: { workspaceId, environment, secretPath } }
|
||||||
);
|
);
|
||||||
return data.policy || "";
|
return data.policy || "";
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export const useUpdateSecretApprovalReviewStatus = () => {
|
|||||||
|
|
||||||
return useMutation<{}, {}, TUpdateSecretApprovalReviewStatusDTO>({
|
return useMutation<{}, {}, TUpdateSecretApprovalReviewStatusDTO>({
|
||||||
mutationFn: async ({ id, status }) => {
|
mutationFn: async ({ id, status }) => {
|
||||||
const { data } = await apiRequest.post(`/api/ee/v1/secret-approval-requests/${id}/review`, {
|
const { data } = await apiRequest.post(`/api/v1/secret-approval-requests/${id}/review`, {
|
||||||
status
|
status
|
||||||
});
|
});
|
||||||
return data;
|
return data;
|
||||||
@@ -30,7 +30,7 @@ export const useUpdateSecretApprovalRequestStatus = () => {
|
|||||||
|
|
||||||
return useMutation<{}, {}, TUpdateSecretApprovalRequestStatusDTO>({
|
return useMutation<{}, {}, TUpdateSecretApprovalRequestStatusDTO>({
|
||||||
mutationFn: async ({ id, status }) => {
|
mutationFn: async ({ id, status }) => {
|
||||||
const { data } = await apiRequest.post(`/api/ee/v1/secret-approval-requests/${id}/status`, {
|
const { data } = await apiRequest.post(`/api/v1/secret-approval-requests/${id}/status`, {
|
||||||
status
|
status
|
||||||
});
|
});
|
||||||
return data;
|
return data;
|
||||||
@@ -47,7 +47,7 @@ export const usePerformSecretApprovalRequestMerge = () => {
|
|||||||
|
|
||||||
return useMutation<{}, {}, TPerformSecretApprovalRequestMerge>({
|
return useMutation<{}, {}, TPerformSecretApprovalRequestMerge>({
|
||||||
mutationFn: async ({ id }) => {
|
mutationFn: async ({ id }) => {
|
||||||
const { data } = await apiRequest.post(`/api/ee/v1/secret-approval-requests/${id}/merge`);
|
const { data } = await apiRequest.post(`/api/v1/secret-approval-requests/${id}/merge`);
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
onSuccess: (_, { id, workspaceId }) => {
|
onSuccess: (_, { id, workspaceId }) => {
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ const fetchSecretApprovalRequestList = async ({
|
|||||||
offset
|
offset
|
||||||
}: TGetSecretApprovalRequestList) => {
|
}: TGetSecretApprovalRequestList) => {
|
||||||
const { data } = await apiRequest.get<{ approvals: TSecretApprovalRequest[] }>(
|
const { data } = await apiRequest.get<{ approvals: TSecretApprovalRequest[] }>(
|
||||||
"/api/ee/v1/secret-approval-requests",
|
"/api/v1/secret-approval-requests",
|
||||||
{
|
{
|
||||||
params: {
|
params: {
|
||||||
workspaceId,
|
workspaceId,
|
||||||
@@ -158,7 +158,7 @@ const fetchSecretApprovalRequestDetails = async ({
|
|||||||
id
|
id
|
||||||
}: Omit<TGetSecretApprovalRequestDetails, "decryptKey">) => {
|
}: Omit<TGetSecretApprovalRequestDetails, "decryptKey">) => {
|
||||||
const { data } = await apiRequest.get<{ approval: TSecretApprovalRequest }>(
|
const { data } = await apiRequest.get<{ approval: TSecretApprovalRequest }>(
|
||||||
`/api/ee/v1/secret-approval-requests/${id}`
|
`/api/v1/secret-approval-requests/${id}`
|
||||||
);
|
);
|
||||||
|
|
||||||
return data.approval;
|
return data.approval;
|
||||||
@@ -197,7 +197,7 @@ export const useGetSecretApprovalRequestDetails = ({
|
|||||||
|
|
||||||
const fetchSecretApprovalRequestCount = async ({ workspaceId }: TGetSecretApprovalRequestCount) => {
|
const fetchSecretApprovalRequestCount = async ({ workspaceId }: TGetSecretApprovalRequestCount) => {
|
||||||
const { data } = await apiRequest.get<{ approvals: TSecretApprovalRequestCount }>(
|
const { data } = await apiRequest.get<{ approvals: TSecretApprovalRequestCount }>(
|
||||||
"/api/ee/v1/secret-approval-requests/count",
|
"/api/v1/secret-approval-requests/count",
|
||||||
{ params: { workspaceId } }
|
{ params: { workspaceId } }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export const useCreateSecretRotation = () => {
|
|||||||
|
|
||||||
return useMutation<{}, {}, TCreateSecretRotationDTO>({
|
return useMutation<{}, {}, TCreateSecretRotationDTO>({
|
||||||
mutationFn: async (dto) => {
|
mutationFn: async (dto) => {
|
||||||
const { data } = await apiRequest.post("/api/ee/v1/secret-rotations", dto);
|
const { data } = await apiRequest.post("/api/v1/secret-rotations", dto);
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
onSuccess: (_, { workspaceId }) => {
|
onSuccess: (_, { workspaceId }) => {
|
||||||
@@ -28,7 +28,7 @@ export const useDeleteSecretRotation = () => {
|
|||||||
|
|
||||||
return useMutation<{}, {}, TDeleteSecretRotationDTO>({
|
return useMutation<{}, {}, TDeleteSecretRotationDTO>({
|
||||||
mutationFn: async (dto) => {
|
mutationFn: async (dto) => {
|
||||||
const { data } = await apiRequest.delete(`/api/ee/v1/secret-rotations/${dto.id}`);
|
const { data } = await apiRequest.delete(`/api/v1/secret-rotations/${dto.id}`);
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
onSuccess: (_, { workspaceId }) => {
|
onSuccess: (_, { workspaceId }) => {
|
||||||
@@ -42,7 +42,7 @@ export const useRestartSecretRotation = () => {
|
|||||||
|
|
||||||
return useMutation<{}, {}, TRestartSecretRotationDTO>({
|
return useMutation<{}, {}, TRestartSecretRotationDTO>({
|
||||||
mutationFn: async (dto) => {
|
mutationFn: async (dto) => {
|
||||||
const { data } = await apiRequest.post("/api/ee/v1/secret-rotations/restart", { id: dto.id });
|
const { data } = await apiRequest.post("/api/v1/secret-rotations/restart", { id: dto.id });
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
onSuccess: (_, { workspaceId }) => {
|
onSuccess: (_, { workspaceId }) => {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export const secretRotationKeys = {
|
|||||||
|
|
||||||
const fetchSecretRotationProviders = async ({ workspaceId }: TGetSecretRotationProviders) => {
|
const fetchSecretRotationProviders = async ({ workspaceId }: TGetSecretRotationProviders) => {
|
||||||
const { data } = await apiRequest.get<TSecretRotationProviderList>(
|
const { data } = await apiRequest.get<TSecretRotationProviderList>(
|
||||||
`/api/ee/v1/secret-rotation-providers/${workspaceId}`
|
`/api/v1/secret-rotation-providers/${workspaceId}`
|
||||||
);
|
);
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
@@ -55,7 +55,7 @@ const fetchSecretRotations = async ({
|
|||||||
workspaceId
|
workspaceId
|
||||||
}: Omit<TGetSecretRotationList, "decryptFileKey">) => {
|
}: Omit<TGetSecretRotationList, "decryptFileKey">) => {
|
||||||
const { data } = await apiRequest.get<{ secretRotations: TSecretRotation[] }>(
|
const { data } = await apiRequest.get<{ secretRotations: TSecretRotation[] }>(
|
||||||
"/api/ee/v1/secret-rotations",
|
"/api/v1/secret-rotations",
|
||||||
{ params: { workspaceId } }
|
{ params: { workspaceId } }
|
||||||
);
|
);
|
||||||
return data.secretRotations;
|
return data.secretRotations;
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ const fetchWorkspaceSnaphots = async ({
|
|||||||
offset = 0
|
offset = 0
|
||||||
}: TGetSecretSnapshotsDTO & { offset: number }) => {
|
}: TGetSecretSnapshotsDTO & { offset: number }) => {
|
||||||
const res = await apiRequest.get<{ secretSnapshots: TSecretSnapshot[] }>(
|
const res = await apiRequest.get<{ secretSnapshots: TSecretSnapshot[] }>(
|
||||||
`/api/ee/v1/workspace/${workspaceId}/secret-snapshots`,
|
`/api/v1/workspace/${workspaceId}/secret-snapshots`,
|
||||||
{
|
{
|
||||||
params: {
|
params: {
|
||||||
limit,
|
limit,
|
||||||
@@ -60,7 +60,7 @@ export const useGetWorkspaceSnapshotList = (dto: TGetSecretSnapshotsDTO & { isPa
|
|||||||
|
|
||||||
const fetchSnapshotEncSecrets = async (snapshotId: string) => {
|
const fetchSnapshotEncSecrets = async (snapshotId: string) => {
|
||||||
const res = await apiRequest.get<{ secretSnapshot: TSnapshotData }>(
|
const res = await apiRequest.get<{ secretSnapshot: TSnapshotData }>(
|
||||||
`/api/ee/v1/secret-snapshot/${snapshotId}`
|
`/api/v1/secret-snapshot/${snapshotId}`
|
||||||
);
|
);
|
||||||
return res.data.secretSnapshot;
|
return res.data.secretSnapshot;
|
||||||
};
|
};
|
||||||
@@ -142,7 +142,7 @@ const fetchWorkspaceSecretSnaphotCount = async (
|
|||||||
directory = "/"
|
directory = "/"
|
||||||
) => {
|
) => {
|
||||||
const res = await apiRequest.get<{ count: number }>(
|
const res = await apiRequest.get<{ count: number }>(
|
||||||
`/api/ee/v1/workspace/${workspaceId}/secret-snapshots/count`,
|
`/api/v1/workspace/${workspaceId}/secret-snapshots/count`,
|
||||||
{
|
{
|
||||||
params: {
|
params: {
|
||||||
environment,
|
environment,
|
||||||
@@ -170,7 +170,7 @@ export const usePerformSecretRollback = () => {
|
|||||||
|
|
||||||
return useMutation<{}, {}, TSecretRollbackDTO>({
|
return useMutation<{}, {}, TSecretRollbackDTO>({
|
||||||
mutationFn: async ({ snapshotId }) => {
|
mutationFn: async ({ snapshotId }) => {
|
||||||
const { data } = await apiRequest.post(`/api/ee/v1/secret-snapshot/${snapshotId}/rollback`);
|
const { data } = await apiRequest.post(`/api/v1/secret-snapshot/${snapshotId}/rollback`);
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
onSuccess: (_, { workspaceId, environment, directory }) => {
|
onSuccess: (_, { workspaceId, environment, directory }) => {
|
||||||
|
|||||||
@@ -3,22 +3,20 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|||||||
import { apiRequest } from "@app/config/request";
|
import { apiRequest } from "@app/config/request";
|
||||||
|
|
||||||
const ssoConfigKeys = {
|
const ssoConfigKeys = {
|
||||||
getSSOConfig: (orgId: string) => [{ orgId }, "organization-saml-sso"] as const,
|
getSSOConfig: (orgId: string) => [{ orgId }, "organization-saml-sso"] as const
|
||||||
}
|
};
|
||||||
|
|
||||||
export const useGetSSOConfig = (organizationId: string) => {
|
export const useGetSSOConfig = (organizationId: string) => {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ssoConfigKeys.getSSOConfig(organizationId),
|
queryKey: ssoConfigKeys.getSSOConfig(organizationId),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const { data } = await apiRequest.get(
|
const { data } = await apiRequest.get(`/api/v1/sso/config?organizationId=${organizationId}`);
|
||||||
`/api/v1/sso/config?organizationId=${organizationId}`
|
|
||||||
);
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
enabled: true
|
enabled: true
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export const useCreateSSOConfig = () => {
|
export const useCreateSSOConfig = () => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
@@ -38,18 +36,15 @@ export const useCreateSSOConfig = () => {
|
|||||||
issuer: string;
|
issuer: string;
|
||||||
cert: string;
|
cert: string;
|
||||||
}) => {
|
}) => {
|
||||||
const { data } = await apiRequest.post(
|
const { data } = await apiRequest.post("/api/v1/sso/config", {
|
||||||
"/api/v1/sso/config",
|
organizationId,
|
||||||
{
|
authProvider,
|
||||||
organizationId,
|
isActive,
|
||||||
authProvider,
|
entryPoint,
|
||||||
isActive,
|
issuer,
|
||||||
entryPoint,
|
cert
|
||||||
issuer,
|
});
|
||||||
cert
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
onSuccess(_, dto) {
|
onSuccess(_, dto) {
|
||||||
@@ -76,22 +71,19 @@ export const useUpdateSSOConfig = () => {
|
|||||||
issuer?: string;
|
issuer?: string;
|
||||||
cert?: string;
|
cert?: string;
|
||||||
}) => {
|
}) => {
|
||||||
const { data } = await apiRequest.patch(
|
const { data } = await apiRequest.patch("/api/v1/sso/config", {
|
||||||
"/api/v1/sso/config",
|
organizationId,
|
||||||
{
|
...(authProvider !== undefined ? { authProvider } : {}),
|
||||||
organizationId,
|
...(isActive !== undefined ? { isActive } : {}),
|
||||||
...(authProvider !== undefined ? { authProvider } : {}),
|
...(entryPoint !== undefined ? { entryPoint } : {}),
|
||||||
...(isActive !== undefined ? { isActive } : {}),
|
...(issuer !== undefined ? { issuer } : {}),
|
||||||
...(entryPoint !== undefined ? { entryPoint } : {}),
|
...(cert !== undefined ? { cert } : {})
|
||||||
...(issuer !== undefined ? { issuer } : {}),
|
});
|
||||||
...(cert !== undefined ? { cert } : {})
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
onSuccess(_, dto) {
|
onSuccess(_, dto) {
|
||||||
queryClient.invalidateQueries(ssoConfigKeys.getSSOConfig(dto.organizationId));
|
queryClient.invalidateQueries(ssoConfigKeys.getSSOConfig(dto.organizationId));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user