Merge branch 'main' into snyk-fix-4a9e6187125617ed814113514828d4f5

This commit is contained in:
Maidul Islam
2024-02-16 11:59:31 -05:00
committed by GitHub
203 changed files with 3400 additions and 7125 deletions
+7 -5
View File
@@ -3,16 +3,18 @@
# THIS IS A SAMPLE ENCRYPTION KEY AND SHOULD NEVER BE USED FOR PRODUCTION # THIS IS A SAMPLE ENCRYPTION KEY AND SHOULD NEVER BE USED FOR PRODUCTION
ENCRYPTION_KEY=6c1fe4e407b8911c104518103505b218 ENCRYPTION_KEY=6c1fe4e407b8911c104518103505b218
# Required
DB_CONNECTION_URI=postgres://infisical:infisical@db:5432/infisical
# JWT # JWT
# Required secrets to sign JWT tokens # Required secrets to sign JWT tokens
# THIS IS A SAMPLE AUTH_SECRET KEY AND SHOULD NEVER BE USED FOR PRODUCTION # THIS IS A SAMPLE AUTH_SECRET KEY AND SHOULD NEVER BE USED FOR PRODUCTION
AUTH_SECRET=5lrMXKKWCVocS/uerPsl7V+TX/aaUaI7iDkgl3tSmLE= AUTH_SECRET=5lrMXKKWCVocS/uerPsl7V+TX/aaUaI7iDkgl3tSmLE=
# MongoDB # Postgres creds
# Backend will connect to the MongoDB instance at connection string MONGO_URL which can either be a ref POSTGRES_PASSWORD=infisical
# to the MongoDB container instance or Mongo Cloud POSTGRES_USER=infisical
# Required POSTGRES_DB=infisical
MONGO_URL=mongodb://root:example@mongo:27017/?authSource=admin
# Redis # Redis
REDIS_URL=redis://redis:6379 REDIS_URL=redis://redis:6379
+1
View File
@@ -0,0 +1 @@
DB_CONNECTION_URI=
+4 -4
View File
@@ -19,11 +19,11 @@ infisical:
## @param backend.name Backend name ## @param backend.name Backend name
## ##
name: infisical name: infisical
replicaCount: 2 replicaCount: 3
image: image:
repository: infisical/infisical repository: infisical/staging_infisical
tag: "latest-postgres" tag: "latest"
pullPolicy: IfNotPresent pullPolicy: Always
deploymentAnnotations: deploymentAnnotations:
secrets.infisical.com/auto-reload: "true" secrets.infisical.com/auto-reload: "true"
@@ -0,0 +1,75 @@
name: "Check API For Breaking Changes"
on:
pull_request:
types: [opened, synchronize]
paths:
- "backend/src/server/routes/**"
jobs:
check-be-api-changes:
name: Check API Changes
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout source
uses: actions/checkout@v3
# - name: Setup Node 20
# uses: actions/setup-node@v3
# with:
# node-version: "20"
# uncomment this when testing locally using nektos/act
- uses: KengoTODA/actions-setup-docker-compose@v1
if: ${{ env.ACT }}
name: Install `docker-compose` for local simulations
with:
version: "2.14.2"
- name: 📦Build the latest image
run: docker build --tag infisical-api .
working-directory: backend
- name: Start postgres and redis
run: touch .env && docker-compose -f docker-compose.dev.yml up -d db redis
- name: Start the server
run: |
echo "SECRET_SCANNING_GIT_APP_ID=793712" >> .env
echo "SECRET_SCANNING_PRIVATE_KEY=some-random" >> .env
echo "SECRET_SCANNING_WEBHOOK_SECRET=some-random" >> .env
docker run --name infisical-api -d -p 4000:4000 -e DB_CONNECTION_URI=$DB_CONNECTION_URI -e REDIS_URL=$REDIS_URL -e JWT_AUTH_SECRET=$JWT_AUTH_SECRET --env-file .env --entrypoint '/bin/sh' infisical-api -c "npm run migration:latest && ls && node dist/main.mjs"
env:
REDIS_URL: redis://172.17.0.1:6379
DB_CONNECTION_URI: postgres://infisical:[email protected]:5432/infisical?sslmode=disable
JWT_AUTH_SECRET: something-random
- uses: actions/setup-go@v5
with:
go-version: '1.21.5'
- name: Wait for container to be stable and check logs
run: |
SECONDS=0
HEALTHY=0
while [ $SECONDS -lt 60 ]; do
if docker ps | grep infisical-api | grep -q healthy; then
echo "Container is healthy."
HEALTHY=1
break
fi
echo "Waiting for container to be healthy... ($SECONDS seconds elapsed)"
docker logs infisical-api
sleep 2
SECONDS=$((SECONDS+2))
done
if [ $HEALTHY -ne 1 ]; then
echo "Container did not become healthy in time"
exit 1
fi
- name: Install openapi-diff
run: go install github.com/tufin/oasdiff@latest
- name: Running OpenAPI Spec diff action
run: oasdiff breaking https://app.infisical.com/api/docs/json http://localhost:4000/api/docs/json --fail-on ERR
- name: cleanup
run: |
docker-compose -f "docker-compose.dev.yml" down
docker stop infisical-api
docker remove infisical-api
@@ -1,43 +0,0 @@
name: "Check Backend Pull Request"
on:
pull_request:
types: [opened, synchronize]
paths:
- "backend/**"
- "!backend/README.md"
- "!backend/.*"
- "backend/.eslintrc.js"
jobs:
check-be-pr:
name: Check
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: ☁️ Checkout source
uses: actions/checkout@v3
- name: 🔧 Setup Node 16
uses: actions/setup-node@v3
with:
node-version: "16"
cache: "npm"
cache-dependency-path: backend/package-lock.json
- name: 📦 Install dependencies
run: npm ci --only-production
working-directory: backend
# - name: 🧪 Run tests
# run: npm run test:ci
# working-directory: backend
# - name: 📁 Upload test results
# uses: actions/upload-artifact@v3
# if: always()
# with:
# name: be-test-results
# path: |
# ./backend/reports
# ./backend/coverage
- name: 🏗️ Run build
run: npm run build
working-directory: backend
@@ -0,0 +1,35 @@
name: "Check Backend PR types and lint"
on:
pull_request:
types: [opened, synchronize]
paths:
- "backend/**"
- "!backend/README.md"
- "!backend/.*"
- "backend/.eslintrc.js"
jobs:
check-be-pr:
name: Check TS and Lint
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: ☁️ Checkout source
uses: actions/checkout@v3
- name: 🔧 Setup Node 20
uses: actions/setup-node@v3
with:
node-version: "20"
cache: "npm"
cache-dependency-path: backend/package-lock.json
- name: Install dependencies
run: npm install
working-directory: backend
- name: Run type check
run: npm run type:check
working-directory: backend
- name: Run lint check
run: npm run lint
working-directory: backend
+1 -1
View File
@@ -6,7 +6,7 @@ node_modules
.env.gamma .env.gamma
.env.prod .env.prod
.env.infisical .env.infisical
.env.migration
*~ *~
*.swp *.swp
*.swo *.swo
-1
View File
@@ -104,7 +104,6 @@ ENV NEXT_PUBLIC_INTERCOM_ID=$INTERCOM_ID \
WORKDIR / WORKDIR /
COPY --from=backend-runner /app /backend COPY --from=backend-runner /app /backend
COPY --from=backend-runner /app/dist/services/smtp/templates /backend/dist/templates
COPY --from=frontend-runner /app ./backend/frontend-build COPY --from=frontend-runner /app ./backend/frontend-build
+2 -8
View File
@@ -5,16 +5,10 @@ push:
docker-compose -f docker-compose.yml push docker-compose -f docker-compose.yml push
up-dev: up-dev:
docker-compose -f docker-compose.dev.yml up --build docker compose -f docker-compose.dev.yml up --build
up-pg-dev:
docker compose -f docker-compose.pg.yml up --build
i-dev:
infisical run -- docker-compose -f docker-compose.dev.yml up --build
up-prod: up-prod:
docker-compose -f docker-compose.yml up --build docker-compose -f docker-compose.prod.yml up --build
down: down:
docker-compose down docker-compose down
+18 -16
View File
@@ -33,7 +33,7 @@
<img src="https://img.shields.io/github/commit-activity/m/infisical/infisical" alt="git commit activity" /> <img src="https://img.shields.io/github/commit-activity/m/infisical/infisical" alt="git commit activity" />
</a> </a>
<a href="https://cloudsmith.io/~infisical/repos/"> <a href="https://cloudsmith.io/~infisical/repos/">
<img src="https://img.shields.io/badge/Downloads-2.58M-orange" alt="Cloudsmith downloads" /> <img src="https://img.shields.io/badge/Downloads-6.95M-orange" alt="Cloudsmith downloads" />
</a> </a>
<a href="https://infisical.com/slack"> <a href="https://infisical.com/slack">
<img src="https://img.shields.io/badge/chat-on%20Slack-blueviolet" alt="Slack community channel" /> <img src="https://img.shields.io/badge/chat-on%20Slack-blueviolet" alt="Slack community channel" />
@@ -53,17 +53,19 @@ We're on a mission to make secret management more accessible to everyone, not ju
## Features ## Features
- **[User-friendly dashboard](https://infisical.com/docs/documentation/platform/project)** to manage secrets across projects and environments (e.g. development, production, etc.) - **[User-friendly dashboard](https://infisical.com/docs/documentation/platform/project)** to manage secrets across projects and environments (e.g. development, production, etc.).
- **[Client SDKs](https://infisical.com/docs/sdks/overview)** to fetch secrets for your apps and infrastructure on demand - **[Client SDKs](https://infisical.com/docs/sdks/overview)** to fetch secrets for your apps and infrastructure on demand.
- **[Infisical CLI](https://infisical.com/docs/cli/overview)** to fetch and inject secrets into any framework in local development - **[Infisical CLI](https://infisical.com/docs/cli/overview)** to fetch and inject secrets into any framework in local development and CI/CD.
- **[Native integrations](https://infisical.com/docs/integrations/overview)** with platforms like GitHub, Vercel, Netlify, and more - **[Infisical API](https://infisical.com/docs/api-reference/overview/introduction)** to perform CRUD operation on secrets, users, projects, and any other resource in Infisical.
- [**Automatic Kubernetes deployment secret reloads**](https://infisical.com/docs/documentation/getting-started/kubernetes) - **[Native integrations](https://infisical.com/docs/integrations/overview)** with platforms like [GitHub](https://infisical.com/docs/integrations/cicd/githubactions), [Vercel](https://infisical.com/docs/integrations/cloud/vercel), [AWS](https://infisical.com/docs/integrations/cloud/aws-secret-manager), and tools like [Terraform](https://infisical.com/docs/integrations/frameworks/terraform), [Ansible](https://infisical.com/docs/integrations/platforms/ansible), and more.
- **[Complete control over your data](https://infisical.com/docs/self-hosting/overview)** - host it yourself on any infrastructure - **[Infisical Kubernetes operator](https://infisical.com/docs/documentation/getting-started/kubernetes)** to managed secrets in k8s, automatically reload deployments, and more.
- **[Secret versioning](https://infisical.com/docs/documentation/platform/secret-versioning)** and **[Point-in-Time Recovery]()** to version every secret and project state - **[Infisical Agent](https://infisical.com/docs/infisical-agent/overview)** to inject secrets into your applications without modifying any code logic.
- **[Audit logs](https://infisical.com/docs/documentation/platform/audit-logs)** to record every action taken in a project - **[Self-hosting and on-prem](https://infisical.com/docs/self-hosting/overview)** to get complete control over your data.
- **Role-based Access Controls** per environment - **[Secret versioning](https://infisical.com/docs/documentation/platform/secret-versioning)** and **[Point-in-Time Recovery](https://infisical.com/docs/documentation/platform/pit-recovery)** to version every secret and project state.
- [**Simple on-premise deployments** to AWS, Digital Ocean, and more](https://infisical.com/docs/self-hosting/overview) - **[Audit logs](https://infisical.com/docs/documentation/platform/audit-logs)** to record every action taken in a project.
- [**Secret Scanning and Leak Prevention**](https://infisical.com/docs/cli/scanning-overview) - **[Role-based Access Controls](https://infisical.com/docs/documentation/platform/role-based-access-controls)** to create permission sets on any resource in Infisica and assign those to user or machine identities.
- **[Simple on-premise deployments](https://infisical.com/docs/self-hosting/overview)** to AWS, Digital Ocean, and more.
- **[Secret Scanning and Leak Prevention](https://infisical.com/docs/cli/scanning-overview)** to prevent secrets from leaking to git.
And much more. And much more.
@@ -82,13 +84,13 @@ To set up and run Infisical locally, make sure you have Git and Docker installed
Linux/macOS: Linux/macOS:
```console ```console
git clone https://github.com/Infisical/infisical && cd "$(basename $_ .git)" && cp .env.example .env && docker-compose -f docker-compose.yml up git clone https://github.com/Infisical/infisical && cd "$(basename $_ .git)" && cp .env.example .env && docker-compose -f docker-compose.prod.yml up
``` ```
Windows Command Prompt: Windows Command Prompt:
```console ```console
git clone https://github.com/Infisical/infisical && cd infisical && copy .env.example .env && docker-compose -f docker-compose.yml up git clone https://github.com/Infisical/infisical && cd infisical && copy .env.example .env && docker-compose -f docker-compose.prod.yml up
``` ```
Create an account at `http://localhost:80` Create an account at `http://localhost:80`
@@ -115,9 +117,9 @@ Lean about Infisical's code scanning feature [here](https://infisical.com/docs/c
This repo available under the [MIT expat license](https://github.com/Infisical/infisical/blob/main/LICENSE), with the exception of the `ee` directory which will contain premium enterprise features requiring a Infisical license. This repo available under the [MIT expat license](https://github.com/Infisical/infisical/blob/main/LICENSE), with the exception of the `ee` directory which will contain premium enterprise features requiring a Infisical license.
If you are interested in managed Infisical Cloud of self-hosted Enterprise Offering, take a look at [our website](https://infisical.com/) or [book a meeting with us](https://cal.com/vmatsiiako/infisical-demo): If you are interested in managed Infisical Cloud of self-hosted Enterprise Offering, take a look at [our website](https://infisical.com/) or [book a meeting with us](https://infisical.cal.com/vlad/infisical-demo):
<a href="https://cal.com/vmatsiiako/infisical-demo"><img alt="Schedule a meeting" src="https://cal.com/book-with-cal-dark.svg" /></a> <a href="[https://infisical.cal.com/vlad/infisical-demo](https://infisical.cal.com/vlad/infisical-demo)"><img alt="Schedule a meeting" src="https://cal.com/book-with-cal-dark.svg" /></a>
## Security ## Security
+364 -250
View File
File diff suppressed because it is too large Load Diff
+10 -7
View File
@@ -2,12 +2,12 @@
"name": "backend", "name": "backend",
"version": "1.0.0", "version": "1.0.0",
"description": "", "description": "",
"main": "index.js", "main": "./dist/main.mjs",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"dev": "tsx watch --clear-screen=false ./src/main.ts | pino-pretty --colorize --colorizeObjects --singleLine", "dev": "tsx watch --clear-screen=false ./src/main.ts | pino-pretty --colorize --colorizeObjects --singleLine",
"dev:docker": "nodemon", "dev:docker": "nodemon",
"build": "rimraf dist && tsup && cp -R ./src/lib/validator/disposable_emails.txt ./dist && cp -R ./src/services/smtp/templates ./dist", "build": "tsup",
"start": "node dist/main.mjs", "start": "node dist/main.mjs",
"type:check": "tsc --noEmit", "type:check": "tsc --noEmit",
"lint:fix": "eslint --fix --ext js,ts ./src", "lint:fix": "eslint --fix --ext js,ts ./src",
@@ -44,7 +44,13 @@
"@types/pg": "^8.10.9", "@types/pg": "^8.10.9",
"@types/picomatch": "^2.3.3", "@types/picomatch": "^2.3.3",
"@types/prompt-sync": "^4.2.3", "@types/prompt-sync": "^4.2.3",
"@types/resolve": "^1.20.6",
"@types/uuid": "^9.0.7", "@types/uuid": "^9.0.7",
"@typescript-eslint/eslint-plugin": "^6.20.0",
"@typescript-eslint/parser": "^6.20.0",
"eslint": "^8.56.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-airbnb-typescript": "^17.1.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"eslint-import-resolver-typescript": "^3.6.1", "eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.29.1", "eslint-plugin-import": "^2.29.1",
@@ -55,6 +61,7 @@
"prompt-sync": "^4.2.0", "prompt-sync": "^4.2.0",
"rimraf": "^5.0.5", "rimraf": "^5.0.5",
"ts-node": "^10.9.1", "ts-node": "^10.9.1",
"tsc-alias": "^1.8.8",
"tsconfig-paths": "^4.2.0", "tsconfig-paths": "^4.2.0",
"tsup": "^8.0.1", "tsup": "^8.0.1",
"tsx": "^4.4.0", "tsx": "^4.4.0",
@@ -67,6 +74,7 @@
"@casl/ability": "^6.5.0", "@casl/ability": "^6.5.0",
"@fastify/cookie": "^9.2.0", "@fastify/cookie": "^9.2.0",
"@fastify/cors": "^8.4.1", "@fastify/cors": "^8.4.1",
"@fastify/etag": "^5.1.0",
"@fastify/formbody": "^7.4.0", "@fastify/formbody": "^7.4.0",
"@fastify/helmet": "^11.1.1", "@fastify/helmet": "^11.1.1",
"@fastify/passport": "^2.4.0", "@fastify/passport": "^2.4.0",
@@ -79,8 +87,6 @@
"@octokit/webhooks-types": "^7.3.1", "@octokit/webhooks-types": "^7.3.1",
"@serdnam/pino-cloudwatch-transport": "^1.0.4", "@serdnam/pino-cloudwatch-transport": "^1.0.4",
"@sindresorhus/slugify": "^2.2.1", "@sindresorhus/slugify": "^2.2.1",
"@typescript-eslint/eslint-plugin": "^6.20.0",
"@typescript-eslint/parser": "^6.20.0",
"@ucast/mongo2js": "^1.3.4", "@ucast/mongo2js": "^1.3.4",
"ajv": "^8.12.0", "ajv": "^8.12.0",
"argon2": "^0.31.2", "argon2": "^0.31.2",
@@ -90,9 +96,6 @@
"bcrypt": "^5.1.1", "bcrypt": "^5.1.1",
"bullmq": "^5.1.1", "bullmq": "^5.1.1",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"eslint": "^8.56.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-airbnb-typescript": "^17.1.0",
"fastify": "^4.24.3", "fastify": "^4.24.3",
"fastify-plugin": "^4.5.1", "fastify-plugin": "^4.5.1",
"handlebars": "^4.7.8", "handlebars": "^4.7.8",
+6 -29
View File
@@ -3,13 +3,9 @@ import dotenv from "dotenv";
import path from "path"; import path from "path";
import knex from "knex"; import knex from "knex";
import { writeFileSync } from "fs"; import { writeFileSync } from "fs";
import promptSync from "prompt-sync";
const prompt = promptSync({ sigint: true });
dotenv.config({ dotenv.config({
path: path.join(__dirname, "../.env"), path: path.join(__dirname, "../../.env.migration")
debug: true
}); });
const db = knex({ const db = knex({
@@ -94,17 +90,7 @@ const main = async () => {
.orderBy("table_name") .orderBy("table_name")
).filter((el) => !el.tableName.includes("_migrations")); ).filter((el) => !el.tableName.includes("_migrations"));
console.log("Select a table to generate schema");
console.table(tables);
console.log("all: all tables");
const selectedTables = prompt("Type table numbers comma seperated: ");
const tableNumbers =
selectedTables !== "all" ? selectedTables.split(",").map((el) => Number(el)) : [];
for (let i = 0; i < tables.length; i += 1) { for (let i = 0; i < tables.length; i += 1) {
// skip if not desired table
if (selectedTables !== "all" && !tableNumbers.includes(i)) continue;
const { tableName } = tables[i]; const { tableName } = tables[i];
const columns = await db(tableName).columnInfo(); const columns = await db(tableName).columnInfo();
const columnNames = Object.keys(columns); const columnNames = Object.keys(columns);
@@ -124,16 +110,16 @@ const main = async () => {
if (colInfo.nullable) { if (colInfo.nullable) {
ztype = ztype.concat(".nullable().optional()"); ztype = ztype.concat(".nullable().optional()");
} }
schema = schema.concat(`${!schema ? "\n" : ""} ${columnName}: ${ztype},\n`); schema = schema.concat(
`${!schema ? "\n" : ""} ${columnName}: ${ztype}${colNum === columnNames.length - 1 ? "" : ","}\n`
);
} }
const dashcase = tableName.split("_").join("-"); const dashcase = tableName.split("_").join("-");
const pascalCase = tableName const pascalCase = tableName
.split("_") .split("_")
.reduce( .reduce((prev, curr) => prev + `${curr.at(0)?.toUpperCase()}${curr.slice(1).toLowerCase()}`, "");
(prev, curr) => prev + `${curr.at(0)?.toUpperCase()}${curr.slice(1).toLowerCase()}`,
""
);
writeFileSync( writeFileSync(
path.join(__dirname, "../src/db/schemas", `${dashcase}.ts`), path.join(__dirname, "../src/db/schemas", `${dashcase}.ts`),
`// Code generated by automation script, DO NOT EDIT. `// Code generated by automation script, DO NOT EDIT.
@@ -152,15 +138,6 @@ export type T${pascalCase}Insert = Omit<T${pascalCase}, TImmutableDBKeys>;
export type T${pascalCase}Update = Partial<Omit<T${pascalCase}, TImmutableDBKeys>>; export type T${pascalCase}Update = Partial<Omit<T${pascalCase}, TImmutableDBKeys>>;
` `
); );
// const file = readFileSync(path.join(__dirname, "../src/db/schemas/index.ts"), "utf8");
// if (!file.includes(`export * from "./${dashcase};"`)) {
// appendFileSync(
// path.join(__dirname, "../src/db/schemas/index.ts"),
// `\nexport * from "./${dashcase}";`,
// "utf8"
// );
// }
} }
process.exit(0); process.exit(0);
+2
View File
@@ -51,6 +51,7 @@ declare module "fastify" {
// used for mfa session authentication // used for mfa session authentication
mfa: { mfa: {
userId: string; userId: string;
orgId?: string;
user: TUsers; user: TUsers;
}; };
// identity injection. depending on which kinda of token the information is filled in auth // identity injection. depending on which kinda of token the information is filled in auth
@@ -58,6 +59,7 @@ declare module "fastify" {
permission: { permission: {
type: ActorType; type: ActorType;
id: string; id: string;
orgId?: string;
}; };
// passport data // passport data
passportUser: { passportUser: {
+10 -2
View File
@@ -1,10 +1,18 @@
import knex from "knex"; import knex from "knex";
export type TDbClient = ReturnType<typeof initDbConnection>; export type TDbClient = ReturnType<typeof initDbConnection>;
export const initDbConnection = (dbConnectionUri: string) => { export const initDbConnection = ({ dbConnectionUri, dbRootCert }: { dbConnectionUri: string; dbRootCert?: string }) => {
const db = knex({ const db = knex({
client: "pg", client: "pg",
connection: dbConnectionUri connection: {
connectionString: dbConnectionUri,
ssl: dbRootCert
? {
rejectUnauthorized: true,
ca: Buffer.from(dbRootCert, "base64").toString("ascii")
}
: false
}
}); });
return db; return db;
+2 -2
View File
@@ -5,9 +5,9 @@ import dotenv from "dotenv";
import type { Knex } from "knex"; import type { Knex } from "knex";
import path from "path"; import path from "path";
// Update with your config settings. // Update with your config settings. .
dotenv.config({ dotenv.config({
path: path.join(__dirname, "../../.env"), path: path.join(__dirname, "../../../.env.migration"),
debug: true debug: true
}); });
export default { export default {
@@ -0,0 +1,25 @@
import { Knex } from "knex";
import { TableName } from "../schemas";
export async function up(knex: Knex): Promise<void> {
await knex.schema.alterTable(TableName.Organization, (t) => {
t.boolean("authEnforced").defaultTo(false);
t.index("slug");
});
await knex.schema.alterTable(TableName.SamlConfig, (t) => {
t.datetime("lastUsed");
});
}
export async function down(knex: Knex): Promise<void> {
await knex.schema.alterTable(TableName.Organization, (t) => {
t.dropColumn("authEnforced");
t.dropIndex("slug");
});
await knex.schema.alterTable(TableName.SamlConfig, (t) => {
t.dropColumn("lastUsed");
});
}
+2 -1
View File
@@ -13,7 +13,8 @@ export const OrganizationsSchema = z.object({
customerId: z.string().nullable().optional(), customerId: z.string().nullable().optional(),
slug: z.string(), slug: z.string(),
createdAt: z.date(), createdAt: z.date(),
updatedAt: z.date() updatedAt: z.date(),
authEnforced: z.boolean().default(false).nullable().optional()
}); });
export type TOrganizations = z.infer<typeof OrganizationsSchema>; export type TOrganizations = z.infer<typeof OrganizationsSchema>;
+2 -1
View File
@@ -22,7 +22,8 @@ export const SamlConfigsSchema = z.object({
certTag: z.string().nullable().optional(), certTag: z.string().nullable().optional(),
createdAt: z.date(), createdAt: z.date(),
updatedAt: z.date(), updatedAt: z.date(),
orgId: z.string().uuid() orgId: z.string().uuid(),
lastUsed: z.date().nullable().optional()
}); });
export type TSamlConfigs = z.infer<typeof SamlConfigsSchema>; export type TSamlConfigs = z.infer<typeof SamlConfigsSchema>;
@@ -22,6 +22,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.getOrgPlansTableByBillCycle({ const data = await server.services.license.getOrgPlansTableByBillCycle({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId, orgId: req.params.organizationId,
billingCycle: req.query.billingCycle billingCycle: req.query.billingCycle
}); });
@@ -43,6 +44,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const plan = await server.services.license.getOrgPlan({ const plan = await server.services.license.getOrgPlan({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId orgId: req.params.organizationId
}); });
return { plan }; return { plan };
@@ -85,6 +87,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.startOrgTrial({ const data = await server.services.license.startOrgTrial({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId, orgId: req.params.organizationId,
success_url: req.body.success_url success_url: req.body.success_url
}); });
@@ -106,6 +109,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.createOrganizationPortalSession({ const data = await server.services.license.createOrganizationPortalSession({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId orgId: req.params.organizationId
}); });
return data; return data;
@@ -126,6 +130,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.getOrgBillingInfo({ const data = await server.services.license.getOrgBillingInfo({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId orgId: req.params.organizationId
}); });
return data; return data;
@@ -146,6 +151,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.getOrgPlanTable({ const data = await server.services.license.getOrgPlanTable({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId orgId: req.params.organizationId
}); });
return data; return data;
@@ -166,6 +172,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.getOrgBillingDetails({ const data = await server.services.license.getOrgBillingDetails({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId orgId: req.params.organizationId
}); });
return data; return data;
@@ -190,6 +197,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.updateOrgBillingDetails({ const data = await server.services.license.updateOrgBillingDetails({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId, orgId: req.params.organizationId,
name: req.body.name, name: req.body.name,
email: req.body.email email: req.body.email
@@ -212,6 +220,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.getOrgPmtMethods({ const data = await server.services.license.getOrgPmtMethods({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId orgId: req.params.organizationId
}); });
return data; return data;
@@ -236,6 +245,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.addOrgPmtMethods({ const data = await server.services.license.addOrgPmtMethods({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId, orgId: req.params.organizationId,
success_url: req.body.success_url, success_url: req.body.success_url,
cancel_url: req.body.cancel_url cancel_url: req.body.cancel_url
@@ -261,6 +271,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.delOrgPmtMethods({ const data = await server.services.license.delOrgPmtMethods({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId, orgId: req.params.organizationId,
pmtMethodId: req.params.pmtMethodId pmtMethodId: req.params.pmtMethodId
}); });
@@ -284,6 +295,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.getOrgTaxIds({ const data = await server.services.license.getOrgTaxIds({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId orgId: req.params.organizationId
}); });
return data; return data;
@@ -310,6 +322,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.addOrgTaxId({ const data = await server.services.license.addOrgTaxId({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId, orgId: req.params.organizationId,
type: req.body.type, type: req.body.type,
value: req.body.value value: req.body.value
@@ -335,6 +348,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.delOrgTaxId({ const data = await server.services.license.delOrgTaxId({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId, orgId: req.params.organizationId,
taxId: req.params.taxId taxId: req.params.taxId
}); });
@@ -358,6 +372,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.getOrgTaxInvoices({ const data = await server.services.license.getOrgTaxInvoices({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId orgId: req.params.organizationId
}); });
return data; return data;
@@ -380,6 +395,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.getOrgLicenses({ const data = await server.services.license.getOrgLicenses({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId orgId: req.params.organizationId
}); });
return data; return data;
+17 -5
View File
@@ -26,7 +26,12 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
}, },
onRequest: verifyAuth([AuthMode.JWT]), onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => { handler: async (req) => {
const role = await server.services.orgRole.createRole(req.permission.id, req.params.organizationId, req.body); const role = await server.services.orgRole.createRole(
req.permission.id,
req.params.organizationId,
req.body,
req.permission.orgId
);
return { role }; return { role };
} }
}); });
@@ -57,7 +62,8 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
req.permission.id, req.permission.id,
req.params.organizationId, req.params.organizationId,
req.params.roleId, req.params.roleId,
req.body req.body,
req.permission.orgId
); );
return { role }; return { role };
} }
@@ -82,7 +88,8 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
const role = await server.services.orgRole.deleteRole( const role = await server.services.orgRole.deleteRole(
req.permission.id, req.permission.id,
req.params.organizationId, req.params.organizationId,
req.params.roleId req.params.roleId,
req.permission.orgId
); );
return { role }; return { role };
} }
@@ -107,7 +114,11 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
}, },
onRequest: verifyAuth([AuthMode.JWT]), onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => { handler: async (req) => {
const roles = await server.services.orgRole.listRoles(req.permission.id, req.params.organizationId); const roles = await server.services.orgRole.listRoles(
req.permission.id,
req.params.organizationId,
req.permission.orgId
);
return { data: { roles } }; return { data: { roles } };
} }
}); });
@@ -130,7 +141,8 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
handler: async (req) => { handler: async (req) => {
const { permissions, membership } = await server.services.orgRole.getUserPermission( const { permissions, membership } = await server.services.orgRole.getUserPermission(
req.permission.id, req.permission.id,
req.params.organizationId req.params.organizationId,
req.permission.orgId
); );
return { permissions, membership }; return { permissions, membership };
} }
@@ -30,7 +30,8 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
req.permission.type, req.permission.type,
req.permission.id, req.permission.id,
req.params.projectId, req.params.projectId,
req.body req.body,
req.permission.orgId
); );
return { role }; return { role };
} }
@@ -63,7 +64,8 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
req.permission.id, req.permission.id,
req.params.projectId, req.params.projectId,
req.params.roleId, req.params.roleId,
req.body req.body,
req.permission.orgId
); );
return { role }; return { role };
} }
@@ -89,7 +91,8 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
req.permission.type, req.permission.type,
req.permission.id, req.permission.id,
req.params.projectId, req.params.projectId,
req.params.roleId req.params.roleId,
req.permission.orgId
); );
return { role }; return { role };
} }
@@ -117,7 +120,8 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
const roles = await server.services.projectRole.listRoles( const roles = await server.services.projectRole.listRoles(
req.permission.type, req.permission.type,
req.permission.id, req.permission.id,
req.params.projectId req.params.projectId,
req.permission.orgId
); );
return { data: { roles } }; return { data: { roles } };
} }
@@ -143,7 +147,8 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
handler: async (req) => { handler: async (req) => {
const { permissions, membership } = await server.services.projectRole.getUserPermission( const { permissions, membership } = await server.services.projectRole.getUserPermission(
req.permission.id, req.permission.id,
req.params.projectId req.params.projectId,
req.permission.orgId
); );
return { data: { permissions, membership } }; return { data: { permissions, membership } };
} }
@@ -11,6 +11,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
method: "GET", method: "GET",
url: "/:workspaceId/secret-snapshots", url: "/:workspaceId/secret-snapshots",
schema: { schema: {
description: "Return project secret snapshots ids",
security: [
{
apiKeyAuth: [],
bearerAuth: []
}
],
params: z.object({ params: z.object({
workspaceId: z.string().trim() workspaceId: z.string().trim()
}), }),
@@ -31,6 +38,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const secretSnapshots = await server.services.snapshot.listSnapshots({ const secretSnapshots = await server.services.snapshot.listSnapshots({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId, projectId: req.params.workspaceId,
...req.query ...req.query
}); });
@@ -60,6 +68,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const count = await server.services.snapshot.projectSecretSnapshotCount({ const count = await server.services.snapshot.projectSecretSnapshotCount({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId, projectId: req.params.workspaceId,
environment: req.query.environment, environment: req.query.environment,
path: req.query.path path: req.query.path
@@ -72,6 +81,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
method: "GET", method: "GET",
url: "/:workspaceId/audit-logs", url: "/:workspaceId/audit-logs",
schema: { schema: {
description: "Return audit logs",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({ params: z.object({
workspaceId: z.string().trim() workspaceId: z.string().trim()
}), }),
@@ -112,6 +128,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
handler: async (req) => { handler: async (req) => {
const auditLogs = await server.services.auditLog.listProjectAuditLogs({ const auditLogs = await server.services.auditLog.listProjectAuditLogs({
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId, projectId: req.params.workspaceId,
...req.query, ...req.query,
auditLogActor: req.query.actor, auditLogActor: req.query.actor,
+60 -18
View File
@@ -13,13 +13,12 @@ import { FastifyRequest } from "fastify";
import { z } from "zod"; import { z } from "zod";
import { SamlConfigsSchema } from "@app/db/schemas"; import { SamlConfigsSchema } from "@app/db/schemas";
import { SamlProviders } from "@app/ee/services/saml-config/saml-config-types"; import { SamlProviders, TGetSamlCfgDTO } from "@app/ee/services/saml-config/saml-config-types";
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 { logger } from "@app/lib/logger"; import { logger } from "@app/lib/logger";
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 { getServerCfg } from "@app/services/super-admin/super-admin-service";
type TSAMLConfig = { type TSAMLConfig = {
callbackUrl: string; callbackUrl: string;
@@ -28,6 +27,7 @@ type TSAMLConfig = {
cert: string; cert: string;
audience: string; audience: string;
wantAuthnResponseSigned?: boolean; wantAuthnResponseSigned?: boolean;
disableRequestedAuthnContext?: boolean;
}; };
export const registerSamlRouter = async (server: FastifyZodProvider) => { export const registerSamlRouter = async (server: FastifyZodProvider) => {
@@ -44,17 +44,30 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
// eslint-disable-next-line // eslint-disable-next-line
getSamlOptions: async (req, done) => { getSamlOptions: async (req, done) => {
try { try {
const { ssoIdentifier } = req.params; const { samlConfigId, orgSlug } = req.params;
if (!ssoIdentifier) throw new BadRequestError({ message: "Missing sso identitier" });
const ssoConfig = await server.services.saml.getSaml({ let ssoLookupDetails: TGetSamlCfgDTO;
type: "ssoId",
id: ssoIdentifier if (orgSlug) {
}); ssoLookupDetails = {
if (!ssoConfig) throw new BadRequestError({ message: "SSO config not found" }); type: "orgSlug",
orgSlug
};
} else if (samlConfigId) {
ssoLookupDetails = {
type: "ssoId",
id: samlConfigId
};
} else {
throw new BadRequestError({ message: "Missing sso identitier or org slug" });
}
const ssoConfig = await server.services.saml.getSaml(ssoLookupDetails);
if (!ssoConfig || !ssoConfig.isActive)
throw new BadRequestError({ message: "Failed to authenticate with SAML SSO" });
const samlConfig: TSAMLConfig = { const samlConfig: TSAMLConfig = {
callbackUrl: `${appCfg.SITE_URL}/api/v1/sso/saml2/${ssoIdentifier}`, callbackUrl: `${appCfg.SITE_URL}/api/v1/sso/saml2/${ssoConfig.id}`,
entryPoint: ssoConfig.entryPoint, entryPoint: ssoConfig.entryPoint,
issuer: ssoConfig.issuer, issuer: ssoConfig.issuer,
cert: ssoConfig.cert, cert: ssoConfig.cert,
@@ -64,7 +77,8 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
samlConfig.wantAuthnResponseSigned = false; samlConfig.wantAuthnResponseSigned = false;
} }
if (ssoConfig.authProvider === SamlProviders.AZURE_SAML) { if (ssoConfig.authProvider === SamlProviders.AZURE_SAML) {
if (req.body.RelayState && JSON.parse(req.body.RelayState).spIntiaited) { samlConfig.disableRequestedAuthnContext = true;
if (req.body?.RelayState && JSON.parse(req.body.RelayState).spInitiated) {
samlConfig.audience = `spn:${ssoConfig.issuer}`; samlConfig.audience = `spn:${ssoConfig.issuer}`;
} }
} }
@@ -79,7 +93,6 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
// eslint-disable-next-line // eslint-disable-next-line
async (req, profile, cb) => { async (req, profile, cb) => {
try { try {
const serverCfg = getServerCfg();
if (!profile) throw new BadRequestError({ message: "Missing profile" }); if (!profile) throw new BadRequestError({ message: "Missing profile" });
const { firstName } = profile; const { firstName } = profile;
const email = profile?.email ?? (profile?.emailAddress as string); // emailRippling is added because in Rippling the field `email` reserved const email = profile?.email ?? (profile?.emailAddress as string); // emailRippling is added because in Rippling the field `email` reserved
@@ -92,7 +105,6 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
email, email,
firstName: profile.firstName as string, firstName: profile.firstName as string,
lastName: profile.lastName as string, lastName: profile.lastName as string,
isSignupAllowed: Boolean(serverCfg.allowSignUp),
relayState: (req.body as { RelayState?: string }).RelayState, relayState: (req.body as { RelayState?: string }).RelayState,
authProvider: (req as unknown as FastifyRequest).ssoConfig?.authProvider as string, authProvider: (req as unknown as FastifyRequest).ssoConfig?.authProvider as string,
orgId: (req as unknown as FastifyRequest).ssoConfig?.orgId as string orgId: (req as unknown as FastifyRequest).ssoConfig?.orgId as string
@@ -108,11 +120,11 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
); );
server.route({ server.route({
url: "/redirect/saml2/:ssoIdentifier", url: "/redirect/saml2/organizations/:orgSlug",
method: "GET", method: "GET",
schema: { schema: {
params: z.object({ params: z.object({
ssoIdentifier: z.string().trim() orgSlug: z.string().trim()
}), }),
querystring: z.object({ querystring: z.object({
callback_port: z.string().optional() callback_port: z.string().optional()
@@ -134,11 +146,37 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
}); });
server.route({ server.route({
url: "/saml2/:ssoIdentifier", url: "/redirect/saml2/:samlConfigId",
method: "GET",
schema: {
params: z.object({
samlConfigId: 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/:samlConfigId",
method: "POST", method: "POST",
schema: { schema: {
params: z.object({ params: z.object({
ssoIdentifier: z.string().trim() samlConfigId: z.string().trim()
}) })
}, },
preValidation: passport.authenticate("saml", { preValidation: passport.authenticate("saml", {
@@ -177,7 +215,8 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
isActive: z.boolean(), isActive: z.boolean(),
entryPoint: z.string(), entryPoint: z.string(),
issuer: z.string(), issuer: z.string(),
cert: z.string() cert: z.string(),
lastUsed: z.date().nullable().optional()
}) })
.optional() .optional()
} }
@@ -186,6 +225,7 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
const saml = await server.services.saml.getSaml({ const saml = await server.services.saml.getSaml({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
orgId: req.query.organizationId, orgId: req.query.organizationId,
type: "org" type: "org"
}); });
@@ -214,6 +254,7 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
const saml = await server.services.saml.createSamlCfg({ const saml = await server.services.saml.createSamlCfg({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
orgId: req.body.organizationId, orgId: req.body.organizationId,
...req.body ...req.body
}); });
@@ -244,6 +285,7 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
const saml = await server.services.saml.updateSamlCfg({ const saml = await server.services.saml.updateSamlCfg({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
orgId: req.body.organizationId, orgId: req.body.organizationId,
...req.body ...req.body
}); });
@@ -34,6 +34,7 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi
const approval = await server.services.secretApprovalPolicy.createSecretApprovalPolicy({ const approval = await server.services.secretApprovalPolicy.createSecretApprovalPolicy({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.body.workspaceId, projectId: req.body.workspaceId,
...req.body, ...req.body,
name: req.body.name ?? `${req.body.environment}-${nanoid(3)}` name: req.body.name ?? `${req.body.environment}-${nanoid(3)}`
@@ -71,6 +72,7 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi
const approval = await server.services.secretApprovalPolicy.updateSecretApprovalPolicy({ const approval = await server.services.secretApprovalPolicy.updateSecretApprovalPolicy({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
...req.body, ...req.body,
secretPolicyId: req.params.sapId secretPolicyId: req.params.sapId
}); });
@@ -96,6 +98,7 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi
const approval = await server.services.secretApprovalPolicy.deleteSecretApprovalPolicy({ const approval = await server.services.secretApprovalPolicy.deleteSecretApprovalPolicy({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
secretPolicyId: req.params.sapId secretPolicyId: req.params.sapId
}); });
return { approval }; return { approval };
@@ -120,6 +123,7 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi
const approvals = await server.services.secretApprovalPolicy.getSecretApprovalPolicyByProjectId({ const approvals = await server.services.secretApprovalPolicy.getSecretApprovalPolicyByProjectId({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.query.workspaceId projectId: req.query.workspaceId
}); });
return { approvals }; return { approvals };
@@ -146,6 +150,7 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi
const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({ const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.query.workspaceId, projectId: req.query.workspaceId,
...req.query ...req.query
}); });
@@ -52,6 +52,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
const approvals = await server.services.secretApprovalRequest.getSecretApprovals({ const approvals = await server.services.secretApprovalRequest.getSecretApprovals({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
...req.query, ...req.query,
projectId: req.query.workspaceId projectId: req.query.workspaceId
}); });
@@ -80,6 +81,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
const approvals = await server.services.secretApprovalRequest.requestCount({ const approvals = await server.services.secretApprovalRequest.requestCount({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.query.workspaceId projectId: req.query.workspaceId
}); });
return { approvals }; return { approvals };
@@ -104,6 +106,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
const { approval } = await server.services.secretApprovalRequest.mergeSecretApprovalRequest({ const { approval } = await server.services.secretApprovalRequest.mergeSecretApprovalRequest({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
approvalId: req.params.id approvalId: req.params.id
}); });
return { approval }; return { approval };
@@ -131,6 +134,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
const review = await server.services.secretApprovalRequest.reviewApproval({ const review = await server.services.secretApprovalRequest.reviewApproval({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
approvalId: req.params.id, approvalId: req.params.id,
status: req.body.status status: req.body.status
}); });
@@ -159,6 +163,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
const approval = await server.services.secretApprovalRequest.updateApprovalStatus({ const approval = await server.services.secretApprovalRequest.updateApprovalStatus({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
approvalId: req.params.id, approvalId: req.params.id,
status: req.body.status status: req.body.status
}); });
@@ -266,6 +271,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
const approval = await server.services.secretApprovalRequest.getSecretApprovalDetails({ const approval = await server.services.secretApprovalRequest.getSecretApprovalDetails({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
id: req.params.id id: req.params.id
}); });
return { approval }; return { approval };
@@ -30,6 +30,7 @@ export const registerSecretRotationProviderRouter = async (server: FastifyZodPro
const providers = await server.services.secretRotation.getProviderTemplates({ const providers = await server.services.secretRotation.getProviderTemplates({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId projectId: req.params.workspaceId
}); });
return providers; return providers;
@@ -40,6 +40,7 @@ export const registerSecretRotationRouter = async (server: FastifyZodProvider) =
const secretRotation = await server.services.secretRotation.createRotation({ const secretRotation = await server.services.secretRotation.createRotation({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
...req.body, ...req.body,
projectId: req.body.workspaceId projectId: req.body.workspaceId
}); });
@@ -73,6 +74,7 @@ export const registerSecretRotationRouter = async (server: FastifyZodProvider) =
const secretRotation = await server.services.secretRotation.restartById({ const secretRotation = await server.services.secretRotation.restartById({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
rotationId: req.body.id rotationId: req.body.id
}); });
return { secretRotation }; return { secretRotation };
@@ -123,6 +125,7 @@ export const registerSecretRotationRouter = async (server: FastifyZodProvider) =
const secretRotations = await server.services.secretRotation.getByProjectId({ const secretRotations = await server.services.secretRotation.getByProjectId({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.query.workspaceId projectId: req.query.workspaceId
}); });
return { secretRotations }; return { secretRotations };
@@ -155,6 +158,7 @@ export const registerSecretRotationRouter = async (server: FastifyZodProvider) =
const secretRotation = await server.services.secretRotation.deleteById({ const secretRotation = await server.services.secretRotation.deleteById({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
rotationId: req.params.id rotationId: req.params.id
}); });
return { secretRotation }; return { secretRotation };
@@ -22,6 +22,7 @@ export const registerSecretScanningRouter = async (server: FastifyZodProvider) =
const session = await server.services.secretScanning.createInstallationSession({ const session = await server.services.secretScanning.createInstallationSession({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
orgId: req.body.organizationId orgId: req.body.organizationId
}); });
return session; return session;
@@ -45,6 +46,7 @@ export const registerSecretScanningRouter = async (server: FastifyZodProvider) =
const { installatedApp } = await server.services.secretScanning.linkInstallationToOrg({ const { installatedApp } = await server.services.secretScanning.linkInstallationToOrg({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
...req.body ...req.body
}); });
return installatedApp; return installatedApp;
@@ -65,6 +67,7 @@ export const registerSecretScanningRouter = async (server: FastifyZodProvider) =
const appInstallationCompleted = await server.services.secretScanning.getOrgInstallationStatus({ const appInstallationCompleted = await server.services.secretScanning.getOrgInstallationStatus({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId orgId: req.params.organizationId
}); });
return { appInstallationCompleted }; return { appInstallationCompleted };
@@ -85,6 +88,7 @@ export const registerSecretScanningRouter = async (server: FastifyZodProvider) =
const { risks } = await server.services.secretScanning.getRisksByOrg({ const { risks } = await server.services.secretScanning.getRisksByOrg({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId orgId: req.params.organizationId
}); });
return { risks }; return { risks };
@@ -106,6 +110,7 @@ export const registerSecretScanningRouter = async (server: FastifyZodProvider) =
const { risk } = await server.services.secretScanning.updateRiskStatus({ const { risk } = await server.services.secretScanning.updateRiskStatus({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId, orgId: req.params.organizationId,
riskId: req.params.riskId, riskId: req.params.riskId,
...req.body ...req.body
@@ -27,6 +27,7 @@ export const registerSecretVersionRouter = async (server: FastifyZodProvider) =>
const secretVersions = await server.services.secret.getSecretVersions({ const secretVersions = await server.services.secret.getSecretVersions({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
limit: req.query.limit, limit: req.query.limit,
offset: req.query.offset, offset: req.query.offset,
secretId: req.params.secretId secretId: req.params.secretId
@@ -46,6 +46,7 @@ export const registerSnapshotRouter = async (server: FastifyZodProvider) => {
const secretSnapshot = await server.services.snapshot.getSnapshotData({ const secretSnapshot = await server.services.snapshot.getSnapshotData({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
id: req.params.secretSnapshotId id: req.params.secretSnapshotId
}); });
return { secretSnapshot }; return { secretSnapshot };
@@ -56,6 +57,13 @@ export const registerSnapshotRouter = async (server: FastifyZodProvider) => {
method: "POST", method: "POST",
url: "/:secretSnapshotId/rollback", url: "/:secretSnapshotId/rollback",
schema: { schema: {
description: "Roll back project secrets to those captured in a secret snapshot version.",
security: [
{
apiKeyAuth: [],
bearerAuth: []
}
],
params: z.object({ params: z.object({
secretSnapshotId: z.string().trim() secretSnapshotId: z.string().trim()
}), }),
@@ -70,6 +78,7 @@ export const registerSnapshotRouter = async (server: FastifyZodProvider) => {
const secretSnapshot = await server.services.snapshot.rollbackSnapshot({ const secretSnapshot = await server.services.snapshot.rollbackSnapshot({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
id: req.params.secretSnapshotId id: req.params.secretSnapshotId
}); });
return { secretSnapshot }; return { secretSnapshot };
@@ -24,7 +24,8 @@ export const registerTrustedIpRouter = async (server: FastifyZodProvider) => {
const trustedIps = await server.services.trustedIp.listIpsByProjectId({ const trustedIps = await server.services.trustedIp.listIpsByProjectId({
projectId: req.params.workspaceId, projectId: req.params.workspaceId,
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id actorId: req.permission.id,
actorOrgId: req.permission.orgId
}); });
return { trustedIps }; return { trustedIps };
} }
@@ -54,6 +55,7 @@ export const registerTrustedIpRouter = async (server: FastifyZodProvider) => {
projectId: req.params.workspaceId, projectId: req.params.workspaceId,
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
...req.body ...req.body
}); });
await server.services.auditLog.createAuditLog({ await server.services.auditLog.createAuditLog({
@@ -97,6 +99,7 @@ export const registerTrustedIpRouter = async (server: FastifyZodProvider) => {
projectId: req.params.workspaceId, projectId: req.params.workspaceId,
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
trustedIpId: req.params.trustedIpId, trustedIpId: req.params.trustedIpId,
...req.body ...req.body
}); });
@@ -137,6 +140,7 @@ export const registerTrustedIpRouter = async (server: FastifyZodProvider) => {
projectId: req.params.workspaceId, projectId: req.params.workspaceId,
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
trustedIpId: req.params.trustedIpId trustedIpId: req.params.trustedIpId
}); });
await server.services.auditLog.createAuditLog({ await server.services.auditLog.createAuditLog({
@@ -38,7 +38,8 @@ export const auditLogDALFactory = (db: TDbClient) => {
}) })
) )
.limit(limit) .limit(limit)
.offset(offset); .offset(offset)
.orderBy("createdAt", "desc");
if (startDate) { if (startDate) {
void sqlQuery.where("createdAt", ">=", startDate); void sqlQuery.where("createdAt", ">=", startDate);
} }
@@ -30,10 +30,11 @@ export const auditLogServiceFactory = ({
startDate, startDate,
actor, actor,
actorId, actorId,
actorOrgId,
projectId, projectId,
auditLogActor auditLogActor
}: TListProjectAuditLogDTO) => { }: TListProjectAuditLogDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.AuditLogs); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.AuditLogs);
const auditLogs = await auditLogDAL.find({ const auditLogs = await auditLogDAL.find({
startDate, startDate,
@@ -44,7 +44,7 @@ type TLicenseServiceFactoryDep = {
export type TLicenseServiceFactory = ReturnType<typeof licenseServiceFactory>; export type TLicenseServiceFactory = ReturnType<typeof licenseServiceFactory>;
const LICENSE_SERVER_CLOUD_LOGIN = "/api/auth/v1/license-server-login"; const LICENSE_SERVER_CLOUD_LOGIN = "/api/auth/v1/license-server-login";
const LICENSE_SERVER_ON_PREM_LOGIN = "/api/auth/v1/licence-login"; const LICENSE_SERVER_ON_PREM_LOGIN = "/api/auth/v1/license-login";
const FEATURE_CACHE_KEY = (orgId: string, projectId?: string) => `${orgId}-${projectId || ""}`; const FEATURE_CACHE_KEY = (orgId: string, projectId?: string) => `${orgId}-${projectId || ""}`;
export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }: TLicenseServiceFactoryDep) => { export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }: TLicenseServiceFactoryDep) => {
@@ -92,7 +92,7 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
// else it would reach catch statement // else it would reach catch statement
isValidLicense = true; isValidLicense = true;
} catch (error) { } catch (error) {
logger.error(`init-license: encountered an error when init license [error]`, error); logger.error(error, `init-license: encountered an error when init license`);
} }
}; };
@@ -175,8 +175,14 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
}; };
// below all are api calls // below all are api calls
const getOrgPlansTableByBillCycle = async ({ orgId, actor, actorId, billingCycle }: TOrgPlansTableDTO) => { const getOrgPlansTableByBillCycle = async ({
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); orgId,
actor,
actorId,
actorOrgId,
billingCycle
}: TOrgPlansTableDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const { data } = await licenseServerCloudApi.request.get( const { data } = await licenseServerCloudApi.request.get(
`/api/license-server/v1/cloud-products?billing-cycle=${billingCycle}` `/api/license-server/v1/cloud-products?billing-cycle=${billingCycle}`
@@ -184,15 +190,15 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return data; return data;
}; };
const getOrgPlan = async ({ orgId, actor, actorId, projectId }: TOrgPlanDTO) => { const getOrgPlan = async ({ orgId, actor, actorId, actorOrgId, projectId }: TOrgPlanDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const plan = await getPlan(orgId, projectId); const plan = await getPlan(orgId, projectId);
return plan; return plan;
}; };
const startOrgTrial = async ({ orgId, actorId, actor, success_url }: TStartOrgTrialDTO) => { const startOrgTrial = async ({ orgId, actorId, actor, actorOrgId, success_url }: TStartOrgTrialDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Billing); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Billing);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Billing); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Billing);
@@ -213,8 +219,8 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return { url }; return { url };
}; };
const createOrganizationPortalSession = async ({ orgId, actorId, actor }: TCreateOrgPortalSession) => { const createOrganizationPortalSession = async ({ orgId, actorId, actor, actorOrgId }: TCreateOrgPortalSession) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Billing); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Billing);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Billing); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Billing);
@@ -260,8 +266,8 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return { url }; return { url };
}; };
const getOrgBillingInfo = async ({ orgId, actor, actorId }: TGetOrgBillInfoDTO) => { const getOrgBillingInfo = async ({ orgId, actor, actorId, actorOrgId }: TGetOrgBillInfoDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId); const organization = await orgDAL.findOrgById(orgId);
@@ -277,8 +283,8 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
}; };
// returns org current plan feature table // returns org current plan feature table
const getOrgPlanTable = async ({ orgId, actor, actorId }: TGetOrgBillInfoDTO) => { const getOrgPlanTable = async ({ orgId, actor, actorId, actorOrgId }: TGetOrgBillInfoDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId); const organization = await orgDAL.findOrgById(orgId);
@@ -293,8 +299,8 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return data; return data;
}; };
const getOrgBillingDetails = async ({ orgId, actor, actorId }: TGetOrgBillInfoDTO) => { const getOrgBillingDetails = async ({ orgId, actor, actorId, actorOrgId }: TGetOrgBillInfoDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId); const organization = await orgDAL.findOrgById(orgId);
@@ -310,8 +316,15 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return data; return data;
}; };
const updateOrgBillingDetails = async ({ actorId, actor, orgId, name, email }: TUpdateOrgBillingDetailsDTO) => { const updateOrgBillingDetails = async ({
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); actorId,
actor,
actorOrgId,
orgId,
name,
email
}: TUpdateOrgBillingDetailsDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId); const organization = await orgDAL.findOrgById(orgId);
@@ -330,8 +343,8 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return data; return data;
}; };
const getOrgPmtMethods = async ({ orgId, actor, actorId }: TOrgPmtMethodsDTO) => { const getOrgPmtMethods = async ({ orgId, actor, actorId, actorOrgId }: TOrgPmtMethodsDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId); const organization = await orgDAL.findOrgById(orgId);
@@ -349,8 +362,15 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return pmtMethods; return pmtMethods;
}; };
const addOrgPmtMethods = async ({ orgId, actor, actorId, success_url, cancel_url }: TAddOrgPmtMethodDTO) => { const addOrgPmtMethods = async ({
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); orgId,
actor,
actorId,
actorOrgId,
success_url,
cancel_url
}: TAddOrgPmtMethodDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId); const organization = await orgDAL.findOrgById(orgId);
@@ -371,8 +391,8 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return { url }; return { url };
}; };
const delOrgPmtMethods = async ({ actorId, actor, orgId, pmtMethodId }: TDelOrgPmtMethodDTO) => { const delOrgPmtMethods = async ({ actorId, actor, actorOrgId, orgId, pmtMethodId }: TDelOrgPmtMethodDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId); const organization = await orgDAL.findOrgById(orgId);
@@ -388,8 +408,8 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return data; return data;
}; };
const getOrgTaxIds = async ({ orgId, actor, actorId }: TGetOrgTaxIdDTO) => { const getOrgTaxIds = async ({ orgId, actor, actorId, actorOrgId }: TGetOrgTaxIdDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId); const organization = await orgDAL.findOrgById(orgId);
@@ -406,8 +426,8 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return taxIds; return taxIds;
}; };
const addOrgTaxId = async ({ actorId, actor, orgId, type, value }: TAddOrgTaxIdDTO) => { const addOrgTaxId = async ({ actorId, actor, actorOrgId, orgId, type, value }: TAddOrgTaxIdDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId); const organization = await orgDAL.findOrgById(orgId);
@@ -427,8 +447,8 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return data; return data;
}; };
const delOrgTaxId = async ({ orgId, actor, actorId, taxId }: TDelOrgTaxIdDTO) => { const delOrgTaxId = async ({ orgId, actor, actorId, actorOrgId, taxId }: TDelOrgTaxIdDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId); const organization = await orgDAL.findOrgById(orgId);
@@ -444,8 +464,8 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return data; return data;
}; };
const getOrgTaxInvoices = async ({ actorId, actor, orgId }: TOrgInvoiceDTO) => { const getOrgTaxInvoices = async ({ actorId, actor, actorOrgId, orgId }: TOrgInvoiceDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId); const organization = await orgDAL.findOrgById(orgId);
@@ -461,8 +481,8 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return invoices; return invoices;
}; };
const getOrgLicenses = async ({ orgId, actor, actorId }: TOrgLicensesDTO) => { const getOrgLicenses = async ({ orgId, actor, actorId, actorOrgId }: TOrgLicensesDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId); const organization = await orgDAL.findOrgById(orgId);
@@ -10,8 +10,10 @@ export const permissionDALFactory = (db: TDbClient) => {
try { try {
const membership = await db(TableName.OrgMembership) const membership = await db(TableName.OrgMembership)
.leftJoin(TableName.OrgRoles, `${TableName.OrgMembership}.roleId`, `${TableName.OrgRoles}.id`) .leftJoin(TableName.OrgRoles, `${TableName.OrgMembership}.roleId`, `${TableName.OrgRoles}.id`)
.join(TableName.Organization, `${TableName.OrgMembership}.orgId`, `${TableName.Organization}.id`)
.where("userId", userId) .where("userId", userId)
.where(`${TableName.OrgMembership}.orgId`, orgId) .where(`${TableName.OrgMembership}.orgId`, orgId)
.select(db.ref("authEnforced").withSchema(TableName.Organization).as("orgAuthEnforced"))
.select("permissions") .select("permissions")
.select(selectAllTableCols(TableName.OrgMembership)) .select(selectAllTableCols(TableName.OrgMembership))
.first(); .first();
@@ -26,9 +28,11 @@ export const permissionDALFactory = (db: TDbClient) => {
try { try {
const membership = await db(TableName.IdentityOrgMembership) const membership = await db(TableName.IdentityOrgMembership)
.leftJoin(TableName.OrgRoles, `${TableName.IdentityOrgMembership}.roleId`, `${TableName.OrgRoles}.id`) .leftJoin(TableName.OrgRoles, `${TableName.IdentityOrgMembership}.roleId`, `${TableName.OrgRoles}.id`)
.join(TableName.Organization, `${TableName.IdentityOrgMembership}.orgId`, `${TableName.Organization}.id`)
.where("identityId", identityId) .where("identityId", identityId)
.where(`${TableName.IdentityOrgMembership}.orgId`, orgId) .where(`${TableName.IdentityOrgMembership}.orgId`, orgId)
.select(selectAllTableCols(TableName.IdentityOrgMembership)) .select(selectAllTableCols(TableName.IdentityOrgMembership))
.select(db.ref("authEnforced").withSchema(TableName.Organization).as("orgAuthEnforced"))
.select("permissions") .select("permissions")
.first(); .first();
return membership; return membership;
@@ -41,9 +45,15 @@ export const permissionDALFactory = (db: TDbClient) => {
try { try {
const membership = await db(TableName.ProjectMembership) const membership = await db(TableName.ProjectMembership)
.leftJoin(TableName.ProjectRoles, `${TableName.ProjectMembership}.roleId`, `${TableName.ProjectRoles}.id`) .leftJoin(TableName.ProjectRoles, `${TableName.ProjectMembership}.roleId`, `${TableName.ProjectRoles}.id`)
.join(TableName.Project, `${TableName.ProjectMembership}.projectId`, `${TableName.Project}.id`)
.join(TableName.Organization, `${TableName.Project}.orgId`, `${TableName.Organization}.id`)
.where("userId", userId) .where("userId", userId)
.where(`${TableName.ProjectMembership}.projectId`, projectId) .where(`${TableName.ProjectMembership}.projectId`, projectId)
.select(selectAllTableCols(TableName.ProjectMembership)) .select(selectAllTableCols(TableName.ProjectMembership))
.select(
db.ref("authEnforced").withSchema(TableName.Organization).as("orgAuthEnforced"),
db.ref("orgId").withSchema(TableName.Project)
)
.select("permissions") .select("permissions")
.first(); .first();
@@ -94,12 +94,15 @@ export const permissionServiceFactory = ({
/* /*
* Get user permission in an organization * Get user permission in an organization
* */ * */
const getUserOrgPermission = async (userId: string, orgId: string) => { const getUserOrgPermission = async (userId: string, orgId: string, userOrgId?: string) => {
const membership = await permissionDAL.getOrgPermission(userId, orgId); const membership = await permissionDAL.getOrgPermission(userId, orgId);
if (!membership) throw new UnauthorizedError({ name: "User not in org" }); if (!membership) throw new UnauthorizedError({ name: "User not in org" });
if (membership.role === OrgMembershipRole.Custom && !membership.permissions) { if (membership.role === OrgMembershipRole.Custom && !membership.permissions) {
throw new BadRequestError({ name: "Custom permission not found" }); throw new BadRequestError({ name: "Custom permission not found" });
} }
if (membership.orgAuthEnforced && membership.orgId !== userOrgId) {
throw new BadRequestError({ name: "Cannot access org-scoped resource" });
}
return { permission: buildOrgPermission(membership.role, membership.permissions), membership }; return { permission: buildOrgPermission(membership.role, membership.permissions), membership };
}; };
@@ -112,10 +115,10 @@ export const permissionServiceFactory = ({
return { permission: buildOrgPermission(membership.role, membership.permissions), membership }; return { permission: buildOrgPermission(membership.role, membership.permissions), membership };
}; };
const getOrgPermission = async (type: ActorType, id: string, orgId: string) => { const getOrgPermission = async (type: ActorType, id: string, orgId: string, actorOrgId?: string) => {
switch (type) { switch (type) {
case ActorType.USER: case ActorType.USER:
return getUserOrgPermission(id, orgId); return getUserOrgPermission(id, orgId, actorOrgId);
case ActorType.IDENTITY: case ActorType.IDENTITY:
return getIdentityOrgPermission(id, orgId); return getIdentityOrgPermission(id, orgId);
default: default:
@@ -142,12 +145,17 @@ export const permissionServiceFactory = ({
}; };
// user permission for a project in an organization // user permission for a project in an organization
const getUserProjectPermission = async (userId: string, projectId: string) => { const getUserProjectPermission = async (userId: string, projectId: string, userOrgId?: string) => {
const membership = await permissionDAL.getProjectPermission(userId, projectId); const membership = await permissionDAL.getProjectPermission(userId, projectId);
if (!membership) throw new UnauthorizedError({ name: "User not in project" }); if (!membership) throw new UnauthorizedError({ name: "User not in project" });
if (membership.role === ProjectMembershipRole.Custom && !membership.permissions) { if (membership.role === ProjectMembershipRole.Custom && !membership.permissions) {
throw new BadRequestError({ name: "Custom permission not found" }); throw new BadRequestError({ name: "Custom permission not found" });
} }
if (membership.orgAuthEnforced && membership.orgId !== userOrgId) {
throw new BadRequestError({ name: "Cannot access org-scoped resource" });
}
return { return {
permission: buildProjectPermission(membership.role, membership.permissions), permission: buildProjectPermission(membership.role, membership.permissions),
membership membership
@@ -160,6 +168,7 @@ export const permissionServiceFactory = ({
if (membership.role === ProjectMembershipRole.Custom && !membership.permissions) { if (membership.role === ProjectMembershipRole.Custom && !membership.permissions) {
throw new BadRequestError({ name: "Custom permission not found" }); throw new BadRequestError({ name: "Custom permission not found" });
} }
return { return {
permission: buildProjectPermission(membership.role, membership.permissions), permission: buildProjectPermission(membership.role, membership.permissions),
membership membership
@@ -184,6 +193,8 @@ export const permissionServiceFactory = ({
: { : {
permission: MongoAbility<ProjectPermissionSet, MongoQuery>; permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
membership: (T extends ActorType.USER ? TProjectMemberships : TIdentityProjectMemberships) & { membership: (T extends ActorType.USER ? TProjectMemberships : TIdentityProjectMemberships) & {
orgAuthEnforced: boolean;
orgId: string;
permissions?: unknown; permissions?: unknown;
}; };
}; };
@@ -191,11 +202,12 @@ export const permissionServiceFactory = ({
const getProjectPermission = async <T extends ActorType>( const getProjectPermission = async <T extends ActorType>(
type: T, type: T,
id: string, id: string,
projectId: string projectId: string,
actorOrgId?: string
): Promise<TProjectPermissionRT<T>> => { ): Promise<TProjectPermissionRT<T>> => {
switch (type) { switch (type) {
case ActorType.USER: case ActorType.USER:
return getUserProjectPermission(id, projectId) as Promise<TProjectPermissionRT<T>>; return getUserProjectPermission(id, projectId, actorOrgId) as Promise<TProjectPermissionRT<T>>;
case ActorType.SERVICE: case ActorType.SERVICE:
return getServiceTokenProjectPermission(id, projectId) as Promise<TProjectPermissionRT<T>>; return getServiceTokenProjectPermission(id, projectId) as Promise<TProjectPermissionRT<T>>;
case ActorType.IDENTITY: case ActorType.IDENTITY:
@@ -1,10 +1,31 @@
import { TDbClient } from "@app/db"; import { TDbClient } from "@app/db";
import { TableName } from "@app/db/schemas"; import { TableName } from "@app/db/schemas";
import { DatabaseError } from "@app/lib/errors";
import { ormify } from "@app/lib/knex"; import { ormify } from "@app/lib/knex";
export type TSamlConfigDALFactory = ReturnType<typeof samlConfigDALFactory>; export type TSamlConfigDALFactory = ReturnType<typeof samlConfigDALFactory>;
export const samlConfigDALFactory = (db: TDbClient) => { export const samlConfigDALFactory = (db: TDbClient) => {
const samlCfgOrm = ormify(db, TableName.SamlConfig); const samlCfgOrm = ormify(db, TableName.SamlConfig);
return samlCfgOrm;
const findEnforceableSamlCfg = async (orgId: string) => {
try {
const samlCfg = await db(TableName.SamlConfig)
.where({
orgId,
isActive: true
})
.whereNotNull("lastUsed")
.first();
return samlCfg;
} catch (error) {
throw new DatabaseError({ error, name: "Find org by id" });
}
};
return {
...samlCfgOrm,
findEnforceableSamlCfg
};
}; };
@@ -18,7 +18,7 @@ import {
infisicalSymmetricEncypt infisicalSymmetricEncypt
} from "@app/lib/crypto/encryption"; } from "@app/lib/crypto/encryption";
import { BadRequestError } from "@app/lib/errors"; import { BadRequestError } from "@app/lib/errors";
import { AuthTokenType } from "@app/services/auth/auth-type"; import { AuthMethod, AuthTokenType } from "@app/services/auth/auth-type";
import { TOrgBotDALFactory } from "@app/services/org/org-bot-dal"; import { TOrgBotDALFactory } from "@app/services/org/org-bot-dal";
import { TOrgDALFactory } from "@app/services/org/org-dal"; import { TOrgDALFactory } from "@app/services/org/org-dal";
import { TUserDALFactory } from "@app/services/user/user-dal"; import { TUserDALFactory } from "@app/services/user/user-dal";
@@ -27,18 +27,15 @@ import { TLicenseServiceFactory } from "../license/license-service";
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission"; import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
import { TPermissionServiceFactory } from "../permission/permission-service"; import { TPermissionServiceFactory } from "../permission/permission-service";
import { TSamlConfigDALFactory } from "./saml-config-dal"; import { TSamlConfigDALFactory } from "./saml-config-dal";
import { import { TCreateSamlCfgDTO, TGetSamlCfgDTO, TSamlLoginDTO, TUpdateSamlCfgDTO } from "./saml-config-types";
SamlProviders,
TCreateSamlCfgDTO,
TGetSamlCfgDTO,
TSamlLoginDTO,
TUpdateSamlCfgDTO
} from "./saml-config-types";
type TSamlConfigServiceFactoryDep = { type TSamlConfigServiceFactoryDep = {
samlConfigDAL: TSamlConfigDALFactory; samlConfigDAL: TSamlConfigDALFactory;
userDAL: Pick<TUserDALFactory, "create" | "findUserByEmail" | "transaction" | "updateById">; userDAL: Pick<TUserDALFactory, "create" | "findUserByEmail" | "transaction" | "updateById">;
orgDAL: Pick<TOrgDALFactory, "createMembership" | "updateMembershipById" | "findMembership" | "findOrgById">; orgDAL: Pick<
TOrgDALFactory,
"createMembership" | "updateMembershipById" | "findMembership" | "findOrgById" | "findOne" | "updateById"
>;
orgBotDAL: Pick<TOrgBotDALFactory, "findOne" | "create" | "transaction">; orgBotDAL: Pick<TOrgBotDALFactory, "findOne" | "create" | "transaction">;
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">; permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
licenseService: Pick<TLicenseServiceFactory, "getPlan">; licenseService: Pick<TLicenseServiceFactory, "getPlan">;
@@ -57,6 +54,7 @@ export const samlConfigServiceFactory = ({
const createSamlCfg = async ({ const createSamlCfg = async ({
cert, cert,
actor, actor,
actorOrgId,
orgId, orgId,
issuer, issuer,
actorId, actorId,
@@ -64,7 +62,7 @@ export const samlConfigServiceFactory = ({
entryPoint, entryPoint,
authProvider authProvider
}: TCreateSamlCfgDTO) => { }: TCreateSamlCfgDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Sso); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Sso);
const plan = await licenseService.getPlan(orgId); const plan = await licenseService.getPlan(orgId);
@@ -140,12 +138,14 @@ export const samlConfigServiceFactory = ({
certIV, certIV,
certTag certTag
}); });
return samlConfig; return samlConfig;
}; };
const updateSamlCfg = async ({ const updateSamlCfg = async ({
orgId, orgId,
actor, actor,
actorOrgId,
cert, cert,
actorId, actorId,
issuer, issuer,
@@ -153,7 +153,7 @@ export const samlConfigServiceFactory = ({
entryPoint, entryPoint,
authProvider authProvider
}: TUpdateSamlCfgDTO) => { }: TUpdateSamlCfgDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Sso); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Sso);
const plan = await licenseService.getPlan(orgId); const plan = await licenseService.getPlan(orgId);
if (!plan.samlSSO) if (!plan.samlSSO)
@@ -162,7 +162,7 @@ export const samlConfigServiceFactory = ({
"Failed to update SAML SSO configuration due to plan restriction. Upgrade plan to update SSO configuration." "Failed to update SAML SSO configuration due to plan restriction. Upgrade plan to update SSO configuration."
}); });
const updateQuery: TSamlConfigsUpdate = { authProvider, isActive }; const updateQuery: TSamlConfigsUpdate = { authProvider, isActive, lastUsed: null };
const orgBot = await orgBotDAL.findOne({ orgId }); const orgBot = await orgBotDAL.findOne({ orgId });
if (!orgBot) throw new BadRequestError({ message: "Org bot not found", name: "OrgBotNotFound" }); if (!orgBot) throw new BadRequestError({ message: "Org bot not found", name: "OrgBotNotFound" });
const key = infisicalSymmetricDecrypt({ const key = infisicalSymmetricDecrypt({
@@ -195,6 +195,8 @@ export const samlConfigServiceFactory = ({
updateQuery.certTag = certTag; updateQuery.certTag = certTag;
} }
const [ssoConfig] = await samlConfigDAL.update({ orgId }, updateQuery); const [ssoConfig] = await samlConfigDAL.update({ orgId }, updateQuery);
await orgDAL.updateById(orgId, { authEnforced: false });
return ssoConfig; return ssoConfig;
}; };
@@ -203,6 +205,10 @@ export const samlConfigServiceFactory = ({
if (dto.type === "org") { if (dto.type === "org") {
ssoConfig = await samlConfigDAL.findOne({ orgId: dto.orgId }); ssoConfig = await samlConfigDAL.findOne({ orgId: dto.orgId });
if (!ssoConfig) return; if (!ssoConfig) return;
} else if (dto.type === "orgSlug") {
const org = await orgDAL.findOne({ slug: dto.orgSlug });
if (!org) return;
ssoConfig = await samlConfigDAL.findOne({ orgId: org.id });
} else if (dto.type === "ssoId") { } else if (dto.type === "ssoId") {
// TODO: // TODO:
// We made this change because saml config ids were not moved over during the migration // We made this change because saml config ids were not moved over during the migration
@@ -227,7 +233,12 @@ export const samlConfigServiceFactory = ({
// when dto is type id means it's internally used // when dto is type id means it's internally used
if (dto.type === "org") { if (dto.type === "org") {
const { permission } = await permissionService.getOrgPermission(dto.actor, dto.actorId, ssoConfig.orgId); const { permission } = await permissionService.getOrgPermission(
dto.actor,
dto.actorId,
ssoConfig.orgId,
dto.actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Sso); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Sso);
} }
const { const {
@@ -284,35 +295,20 @@ export const samlConfigServiceFactory = ({
isActive: ssoConfig.isActive, isActive: ssoConfig.isActive,
entryPoint, entryPoint,
issuer, issuer,
cert cert,
lastUsed: ssoConfig.lastUsed
}; };
}; };
const samlLogin = async ({ const samlLogin = async ({ firstName, email, lastName, authProvider, orgId, relayState }: TSamlLoginDTO) => {
firstName,
email,
lastName,
authProvider,
orgId,
relayState,
isSignupAllowed
}: TSamlLoginDTO) => {
const appCfg = getConfig(); const appCfg = getConfig();
let user = await userDAL.findUserByEmail(email); 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); const organization = await orgDAL.findOrgById(orgId);
if (!organization) throw new BadRequestError({ message: "Org not found" }); if (!organization) throw new BadRequestError({ message: "Org not found" });
if (user) { if (user) {
const hasSamlEnabled = (user.authMethods || []).some((method) =>
Object.values(SamlProviders).includes(method as SamlProviders)
);
await userDAL.transaction(async (tx) => { 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 }); const [orgMembership] = await orgDAL.findMembership({ userId: user.id, orgId }, { tx });
if (!orgMembership) { if (!orgMembership) {
await orgDAL.createMembership( await orgDAL.createMembership(
@@ -342,7 +338,7 @@ export const samlConfigServiceFactory = ({
email, email,
firstName, firstName,
lastName, lastName,
authMethods: [authProvider] authMethods: [AuthMethod.EMAIL]
}, },
tx tx
); );
@@ -378,6 +374,9 @@ export const samlConfigServiceFactory = ({
expiresIn: appCfg.JWT_PROVIDER_AUTH_LIFETIME expiresIn: appCfg.JWT_PROVIDER_AUTH_LIFETIME
} }
); );
await samlConfigDAL.update({ orgId }, { lastUsed: new Date() });
return { isUserCompleted, providerAuthToken }; return { isUserCompleted, providerAuthToken };
}; };
@@ -25,7 +25,11 @@ export type TUpdateSamlCfgDTO = Partial<{
TOrgPermission; TOrgPermission;
export type TGetSamlCfgDTO = export type TGetSamlCfgDTO =
| { type: "org"; orgId: string; actor: ActorType; actorId: string } | { type: "org"; orgId: string; actor: ActorType; actorId: string; actorOrgId?: string }
| {
type: "orgSlug";
orgSlug: string;
}
| { | {
type: "ssoId"; type: "ssoId";
id: string; id: string;
@@ -37,7 +41,6 @@ export type TSamlLoginDTO = {
lastName?: string; lastName?: string;
authProvider: string; authProvider: string;
orgId: string; orgId: string;
isSignupAllowed: boolean;
// saml thingy // saml thingy
relayState?: string; relayState?: string;
}; };
@@ -44,6 +44,7 @@ export const secretApprovalPolicyServiceFactory = ({
name, name,
actor, actor,
actorId, actorId,
actorOrgId,
approvals, approvals,
approvers, approvers,
projectId, projectId,
@@ -53,7 +54,7 @@ export const secretApprovalPolicyServiceFactory = ({
if (approvals > approvers.length) if (approvals > approvers.length)
throw new BadRequestError({ message: "Approvals cannot be greater than approvers" }); throw new BadRequestError({ message: "Approvals cannot be greater than approvers" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create, ProjectPermissionActions.Create,
ProjectPermissionSub.SecretApproval ProjectPermissionSub.SecretApproval
@@ -96,13 +97,19 @@ export const secretApprovalPolicyServiceFactory = ({
name, name,
actorId, actorId,
actor, actor,
actorOrgId,
approvals, approvals,
secretPolicyId secretPolicyId
}: TUpdateSapDTO) => { }: TUpdateSapDTO) => {
const secretApprovalPolicy = await secretApprovalPolicyDAL.findById(secretPolicyId); const secretApprovalPolicy = await secretApprovalPolicyDAL.findById(secretPolicyId);
if (!secretApprovalPolicy) throw new BadRequestError({ message: "Secret approval policy not found" }); if (!secretApprovalPolicy) throw new BadRequestError({ message: "Secret approval policy not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, secretApprovalPolicy.projectId); const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
secretApprovalPolicy.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SecretApproval); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SecretApproval);
const updatedSap = await secretApprovalPolicyDAL.transaction(async (tx) => { const updatedSap = await secretApprovalPolicyDAL.transaction(async (tx) => {
@@ -145,11 +152,16 @@ export const secretApprovalPolicyServiceFactory = ({
}; };
}; };
const deleteSecretApprovalPolicy = async ({ secretPolicyId, actor, actorId }: TDeleteSapDTO) => { const deleteSecretApprovalPolicy = async ({ secretPolicyId, actor, actorId, actorOrgId }: TDeleteSapDTO) => {
const sapPolicy = await secretApprovalPolicyDAL.findById(secretPolicyId); const sapPolicy = await secretApprovalPolicyDAL.findById(secretPolicyId);
if (!sapPolicy) throw new BadRequestError({ message: "Secret approval policy not found" }); if (!sapPolicy) throw new BadRequestError({ message: "Secret approval policy not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, sapPolicy.projectId); const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
sapPolicy.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Delete, ProjectPermissionActions.Delete,
ProjectPermissionSub.SecretApproval ProjectPermissionSub.SecretApproval
@@ -159,8 +171,8 @@ export const secretApprovalPolicyServiceFactory = ({
return sapPolicy; return sapPolicy;
}; };
const getSecretApprovalPolicyByProjectId = async ({ actorId, actor, projectId }: TListSapDTO) => { const getSecretApprovalPolicyByProjectId = async ({ actorId, actor, actorOrgId, projectId }: TListSapDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval);
const sapPolicies = await secretApprovalPolicyDAL.find({ projectId }); const sapPolicies = await secretApprovalPolicyDAL.find({ projectId });
@@ -188,10 +200,11 @@ export const secretApprovalPolicyServiceFactory = ({
projectId, projectId,
actor, actor,
actorId, actorId,
actorOrgId,
environment, environment,
secretPath secretPath
}: TGetBoardSapDTO) => { }: TGetBoardSapDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read, ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { secretPath, environment }) subject(ProjectPermissionSub.Secrets, { secretPath, environment })
@@ -73,10 +73,15 @@ export const secretApprovalRequestServiceFactory = ({
secretVersionDAL, secretVersionDAL,
secretQueueService secretQueueService
}: TSecretApprovalRequestServiceFactoryDep) => { }: TSecretApprovalRequestServiceFactoryDep) => {
const requestCount = async ({ projectId, actor, actorId }: TApprovalRequestCountDTO) => { const requestCount = async ({ projectId, actor, actorId, actorOrgId }: TApprovalRequestCountDTO) => {
if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" }); if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" });
const { membership } = await permissionService.getProjectPermission(actor as ActorType.USER, actorId, projectId); const { membership } = await permissionService.getProjectPermission(
actor as ActorType.USER,
actorId,
projectId,
actorOrgId
);
const count = await secretApprovalRequestDAL.findProjectRequestCount(projectId, membership.id); const count = await secretApprovalRequestDAL.findProjectRequestCount(projectId, membership.id);
return count; return count;
@@ -86,6 +91,7 @@ export const secretApprovalRequestServiceFactory = ({
projectId, projectId,
actorId, actorId,
actor, actor,
actorOrgId,
status, status,
environment, environment,
committer, committer,
@@ -94,7 +100,7 @@ export const secretApprovalRequestServiceFactory = ({
}: TListApprovalsDTO) => { }: TListApprovalsDTO) => {
if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" }); if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" });
const { membership } = await permissionService.getProjectPermission(actor, actorId, projectId); const { membership } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
const approvals = await secretApprovalRequestDAL.findByProjectId({ const approvals = await secretApprovalRequestDAL.findByProjectId({
projectId, projectId,
committer, committer,
@@ -107,7 +113,7 @@ export const secretApprovalRequestServiceFactory = ({
return approvals; return approvals;
}; };
const getSecretApprovalDetails = async ({ actor, actorId, id }: TSecretApprovalDetailsDTO) => { const getSecretApprovalDetails = async ({ actor, actorId, actorOrgId, id }: TSecretApprovalDetailsDTO) => {
if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" }); if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" });
const secretApprovalRequest = await secretApprovalRequestDAL.findById(id); const secretApprovalRequest = await secretApprovalRequestDAL.findById(id);
@@ -117,7 +123,8 @@ export const secretApprovalRequestServiceFactory = ({
const { membership } = await permissionService.getProjectPermission( const { membership } = await permissionService.getProjectPermission(
actor, actor,
actorId, actorId,
secretApprovalRequest.projectId secretApprovalRequest.projectId,
actorOrgId
); );
if ( if (
membership.role !== ProjectMembershipRole.Admin && membership.role !== ProjectMembershipRole.Admin &&
@@ -134,7 +141,7 @@ export const secretApprovalRequestServiceFactory = ({
return { ...secretApprovalRequest, secretPath: secretPath?.[0]?.path || "/", commits: secrets }; return { ...secretApprovalRequest, secretPath: secretPath?.[0]?.path || "/", commits: secrets };
}; };
const reviewApproval = async ({ approvalId, actor, status, actorId }: TReviewRequestDTO) => { const reviewApproval = async ({ approvalId, actor, status, actorId, actorOrgId }: TReviewRequestDTO) => {
const secretApprovalRequest = await secretApprovalRequestDAL.findById(approvalId); const secretApprovalRequest = await secretApprovalRequestDAL.findById(approvalId);
if (!secretApprovalRequest) throw new BadRequestError({ message: "Secret approval request not found" }); if (!secretApprovalRequest) throw new BadRequestError({ message: "Secret approval request not found" });
if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" }); if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" });
@@ -143,7 +150,8 @@ export const secretApprovalRequestServiceFactory = ({
const { membership } = await permissionService.getProjectPermission( const { membership } = await permissionService.getProjectPermission(
ActorType.USER, ActorType.USER,
actorId, actorId,
secretApprovalRequest.projectId secretApprovalRequest.projectId,
actorOrgId
); );
if ( if (
membership.role !== ProjectMembershipRole.Admin && membership.role !== ProjectMembershipRole.Admin &&
@@ -175,7 +183,7 @@ export const secretApprovalRequestServiceFactory = ({
return reviewStatus; return reviewStatus;
}; };
const updateApprovalStatus = async ({ actorId, status, approvalId, actor }: TStatusChangeDTO) => { const updateApprovalStatus = async ({ actorId, status, approvalId, actor, actorOrgId }: TStatusChangeDTO) => {
const secretApprovalRequest = await secretApprovalRequestDAL.findById(approvalId); const secretApprovalRequest = await secretApprovalRequestDAL.findById(approvalId);
if (!secretApprovalRequest) throw new BadRequestError({ message: "Secret approval request not found" }); if (!secretApprovalRequest) throw new BadRequestError({ message: "Secret approval request not found" });
if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" }); if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" });
@@ -184,7 +192,8 @@ export const secretApprovalRequestServiceFactory = ({
const { membership } = await permissionService.getProjectPermission( const { membership } = await permissionService.getProjectPermission(
ActorType.USER, ActorType.USER,
actorId, actorId,
secretApprovalRequest.projectId secretApprovalRequest.projectId,
actorOrgId
); );
if ( if (
membership.role !== ProjectMembershipRole.Admin && membership.role !== ProjectMembershipRole.Admin &&
@@ -207,13 +216,18 @@ export const secretApprovalRequestServiceFactory = ({
return { ...secretApprovalRequest, ...updatedRequest }; return { ...secretApprovalRequest, ...updatedRequest };
}; };
const mergeSecretApprovalRequest = async ({ approvalId, actor, actorId }: TMergeSecretApprovalRequestDTO) => { const mergeSecretApprovalRequest = async ({
approvalId,
actor,
actorId,
actorOrgId
}: TMergeSecretApprovalRequestDTO) => {
const secretApprovalRequest = await secretApprovalRequestDAL.findById(approvalId); const secretApprovalRequest = await secretApprovalRequestDAL.findById(approvalId);
if (!secretApprovalRequest) throw new BadRequestError({ message: "Secret approval request not found" }); if (!secretApprovalRequest) throw new BadRequestError({ message: "Secret approval request not found" });
if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" }); if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" });
const { policy, folderId, projectId } = secretApprovalRequest; const { policy, folderId, projectId } = secretApprovalRequest;
const { membership } = await permissionService.getProjectPermission(ActorType.USER, actorId, projectId); const { membership } = await permissionService.getProjectPermission(ActorType.USER, actorId, projectId, actorOrgId);
if ( if (
membership.role !== ProjectMembershipRole.Admin && membership.role !== ProjectMembershipRole.Admin &&
secretApprovalRequest.committerId !== membership.id && secretApprovalRequest.committerId !== membership.id &&
@@ -401,6 +415,7 @@ export const secretApprovalRequestServiceFactory = ({
data, data,
actorId, actorId,
actor, actor,
actorOrgId,
policy, policy,
projectId, projectId,
secretPath, secretPath,
@@ -408,7 +423,12 @@ export const secretApprovalRequestServiceFactory = ({
}: TGenerateSecretApprovalRequestDTO) => { }: TGenerateSecretApprovalRequestDTO) => {
if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" }); if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" });
const { permission, membership } = await permissionService.getProjectPermission(actor, actorId, projectId); const { permission, membership } = await permissionService.getProjectPermission(
actor,
actorId,
projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read, ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath }) subject(ProjectPermissionSub.Secrets, { environment, secretPath })
@@ -14,13 +14,7 @@ import { ProjectPermissionActions, ProjectPermissionSub } from "../permission/pr
import { TSecretRotationDALFactory } from "./secret-rotation-dal"; import { TSecretRotationDALFactory } from "./secret-rotation-dal";
import { TSecretRotationQueueFactory } from "./secret-rotation-queue"; import { TSecretRotationQueueFactory } from "./secret-rotation-queue";
import { TSecretRotationEncData } from "./secret-rotation-queue/secret-rotation-queue-types"; import { TSecretRotationEncData } from "./secret-rotation-queue/secret-rotation-queue-types";
import { import { TCreateSecretRotationDTO, TDeleteDTO, TListByProjectIdDTO, TRestartDTO } from "./secret-rotation-types";
TCreateSecretRotationDTO,
TDeleteDTO,
TGetByIdDTO,
TListByProjectIdDTO,
TRestartDTO
} from "./secret-rotation-types";
import { rotationTemplates } from "./templates"; import { rotationTemplates } from "./templates";
type TSecretRotationServiceFactoryDep = { type TSecretRotationServiceFactoryDep = {
@@ -45,8 +39,8 @@ export const secretRotationServiceFactory = ({
folderDAL, folderDAL,
secretDAL secretDAL
}: TSecretRotationServiceFactoryDep) => { }: TSecretRotationServiceFactoryDep) => {
const getProviderTemplates = async ({ actor, actorId, projectId }: TProjectPermission) => { const getProviderTemplates = async ({ actor, actorId, actorOrgId, projectId }: TProjectPermission) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRotation); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRotation);
return { return {
@@ -59,6 +53,7 @@ export const secretRotationServiceFactory = ({
projectId, projectId,
actorId, actorId,
actor, actor,
actorOrgId,
inputs, inputs,
outputs, outputs,
interval, interval,
@@ -66,7 +61,7 @@ export const secretRotationServiceFactory = ({
secretPath, secretPath,
environment environment
}: TCreateSecretRotationDTO) => { }: TCreateSecretRotationDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create, ProjectPermissionActions.Create,
ProjectPermissionSub.SecretRotation ProjectPermissionSub.SecretRotation
@@ -144,23 +139,14 @@ export const secretRotationServiceFactory = ({
return secretRotation; return secretRotation;
}; };
const getById = async ({ rotationId, actor, actorId }: TGetByIdDTO) => { const getByProjectId = async ({ actorId, projectId, actor, actorOrgId }: TListByProjectIdDTO) => {
const [doc] = await secretRotationDAL.find({ id: rotationId }); const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
if (!doc) throw new BadRequestError({ message: "Rotation not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, doc.projectId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRotation);
return doc;
};
const getByProjectId = async ({ actorId, projectId, actor }: TListByProjectIdDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRotation); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRotation);
const doc = await secretRotationDAL.find({ projectId }); const doc = await secretRotationDAL.find({ projectId });
return doc; return doc;
}; };
const restartById = async ({ actor, actorId, rotationId }: TRestartDTO) => { const restartById = async ({ actor, actorId, actorOrgId, rotationId }: TRestartDTO) => {
const doc = await secretRotationDAL.findById(rotationId); const doc = await secretRotationDAL.findById(rotationId);
if (!doc) throw new BadRequestError({ message: "Rotation not found" }); if (!doc) throw new BadRequestError({ message: "Rotation not found" });
@@ -171,18 +157,18 @@ export const secretRotationServiceFactory = ({
message: "Failed to add secret rotation due to plan restriction. Upgrade plan to add secret rotation." message: "Failed to add secret rotation due to plan restriction. Upgrade plan to add secret rotation."
}); });
const { permission } = await permissionService.getProjectPermission(actor, actorId, doc.projectId); const { permission } = await permissionService.getProjectPermission(actor, actorId, doc.projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SecretRotation); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SecretRotation);
await secretRotationQueue.removeFromQueue(doc.id, doc.interval); await secretRotationQueue.removeFromQueue(doc.id, doc.interval);
await secretRotationQueue.addToQueue(doc.id, doc.interval); await secretRotationQueue.addToQueue(doc.id, doc.interval);
return doc; return doc;
}; };
const deleteById = async ({ actor, actorId, rotationId }: TDeleteDTO) => { const deleteById = async ({ actor, actorId, actorOrgId, rotationId }: TDeleteDTO) => {
const doc = await secretRotationDAL.findById(rotationId); const doc = await secretRotationDAL.findById(rotationId);
if (!doc) throw new BadRequestError({ message: "Rotation not found" }); if (!doc) throw new BadRequestError({ message: "Rotation not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, doc.projectId); const { permission } = await permissionService.getProjectPermission(actor, actorId, doc.projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Delete, ProjectPermissionActions.Delete,
ProjectPermissionSub.SecretRotation ProjectPermissionSub.SecretRotation
@@ -197,7 +183,6 @@ export const secretRotationServiceFactory = ({
return { return {
getProviderTemplates, getProviderTemplates,
getById,
getByProjectId, getByProjectId,
createRotation, createRotation,
restartById, restartById,
@@ -18,7 +18,3 @@ export type TDeleteDTO = {
export type TRestartDTO = { export type TRestartDTO = {
rotationId: string; rotationId: string;
} & Omit<TProjectPermission, "projectId">; } & Omit<TProjectPermission, "projectId">;
export type TGetByIdDTO = {
rotationId: string;
} & Omit<TProjectPermission, "projectId">;
@@ -39,8 +39,8 @@ export const secretScanningServiceFactory = ({
permissionService, permissionService,
secretScanningQueue secretScanningQueue
}: TSecretScanningServiceFactoryDep) => { }: TSecretScanningServiceFactoryDep) => {
const createInstallationSession = async ({ actor, orgId, actorId }: TInstallAppSessionDTO) => { const createInstallationSession = async ({ actor, orgId, actorId, actorOrgId }: TInstallAppSessionDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.SecretScanning); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.SecretScanning);
const sessionId = crypto.randomBytes(16).toString("hex"); const sessionId = crypto.randomBytes(16).toString("hex");
@@ -48,11 +48,17 @@ export const secretScanningServiceFactory = ({
return { sessionId }; return { sessionId };
}; };
const linkInstallationToOrg = async ({ sessionId, actorId, installationId, actor }: TLinkInstallSessionDTO) => { const linkInstallationToOrg = async ({
sessionId,
actorId,
installationId,
actor,
actorOrgId
}: TLinkInstallSessionDTO) => {
const session = await gitAppInstallSessionDAL.findOne({ sessionId }); const session = await gitAppInstallSessionDAL.findOne({ sessionId });
if (!session) throw new UnauthorizedError({ message: "Session not found" }); if (!session) throw new UnauthorizedError({ message: "Session not found" });
const { permission } = await permissionService.getOrgPermission(actor, actorId, session.orgId); const { permission } = await permissionService.getOrgPermission(actor, actorId, session.orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.SecretScanning); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.SecretScanning);
const installatedApp = await gitAppOrgDAL.transaction(async (tx) => { const installatedApp = await gitAppOrgDAL.transaction(async (tx) => {
await gitAppInstallSessionDAL.deleteById(session.id, tx); await gitAppInstallSessionDAL.deleteById(session.id, tx);
@@ -83,23 +89,23 @@ export const secretScanningServiceFactory = ({
return { installatedApp }; return { installatedApp };
}; };
const getOrgInstallationStatus = async ({ actorId, orgId, actor }: TGetOrgInstallStatusDTO) => { const getOrgInstallationStatus = async ({ actorId, orgId, actor, actorOrgId }: TGetOrgInstallStatusDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.SecretScanning); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.SecretScanning);
const appInstallation = await gitAppOrgDAL.findOne({ orgId }); const appInstallation = await gitAppOrgDAL.findOne({ orgId });
return Boolean(appInstallation); return Boolean(appInstallation);
}; };
const getRisksByOrg = async ({ actor, orgId, actorId }: TGetOrgRisksDTO) => { const getRisksByOrg = async ({ actor, orgId, actorId, actorOrgId }: TGetOrgRisksDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.SecretScanning); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.SecretScanning);
const risks = await secretScanningDAL.find({ orgId }, { sort: [["createdAt", "desc"]] }); const risks = await secretScanningDAL.find({ orgId }, { sort: [["createdAt", "desc"]] });
return { risks }; return { risks };
}; };
const updateRiskStatus = async ({ actorId, orgId, actor, riskId, status }: TUpdateRiskStatusDTO) => { const updateRiskStatus = async ({ actorId, orgId, actor, actorOrgId, riskId, status }: TUpdateRiskStatusDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.SecretScanning); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.SecretScanning);
const isRiskResolved = Boolean( const isRiskResolved = Boolean(
@@ -58,9 +58,10 @@ export const secretSnapshotServiceFactory = ({
projectId, projectId,
actorId, actorId,
actor, actor,
actorOrgId,
path path
}: TProjectSnapshotCountDTO) => { }: TProjectSnapshotCountDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
const folder = await folderDAL.findBySecretPath(projectId, environment, path); const folder = await folderDAL.findBySecretPath(projectId, environment, path);
@@ -75,11 +76,12 @@ export const secretSnapshotServiceFactory = ({
projectId, projectId,
actorId, actorId,
actor, actor,
actorOrgId,
path, path,
limit = 20, limit = 20,
offset = 0 offset = 0
}: TProjectSnapshotListDTO) => { }: TProjectSnapshotListDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
const folder = await folderDAL.findBySecretPath(projectId, environment, path); const folder = await folderDAL.findBySecretPath(projectId, environment, path);
@@ -89,10 +91,10 @@ export const secretSnapshotServiceFactory = ({
return snapshots; return snapshots;
}; };
const getSnapshotData = async ({ actorId, actor, id }: TGetSnapshotDataDTO) => { const getSnapshotData = async ({ actorId, actor, actorOrgId, id }: TGetSnapshotDataDTO) => {
const snapshot = await snapshotDAL.findSecretSnapshotDataById(id); const snapshot = await snapshotDAL.findSecretSnapshotDataById(id);
if (!snapshot) throw new BadRequestError({ message: "Snapshot not found" }); if (!snapshot) throw new BadRequestError({ message: "Snapshot not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, snapshot.projectId); const { permission } = await permissionService.getProjectPermission(actor, actorId, snapshot.projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
return snapshot; return snapshot;
}; };
@@ -143,11 +145,11 @@ export const secretSnapshotServiceFactory = ({
} }
}; };
const rollbackSnapshot = async ({ id: snapshotId, actor, actorId }: TRollbackSnapshotDTO) => { const rollbackSnapshot = async ({ id: snapshotId, actor, actorId, actorOrgId }: TRollbackSnapshotDTO) => {
const snapshot = await snapshotDAL.findById(snapshotId); const snapshot = await snapshotDAL.findById(snapshotId);
if (!snapshot) throw new BadRequestError({ message: "Snapshot not found" }); if (!snapshot) throw new BadRequestError({ message: "Snapshot not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, snapshot.projectId); const { permission } = await permissionService.getProjectPermission(actor, actorId, snapshot.projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create, ProjectPermissionActions.Create,
ProjectPermissionSub.SecretRollback ProjectPermissionSub.SecretRollback
@@ -26,8 +26,8 @@ export const trustedIpServiceFactory = ({
licenseService, licenseService,
projectDAL projectDAL
}: TTrustedIpServiceFactoryDep) => { }: TTrustedIpServiceFactoryDep) => {
const listIpsByProjectId = async ({ projectId, actor, actorId }: TProjectPermission) => { const listIpsByProjectId = async ({ projectId, actor, actorId, actorOrgId }: TProjectPermission) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.IpAllowList); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.IpAllowList);
const trustedIps = await trustedIpDAL.find({ const trustedIps = await trustedIpDAL.find({
projectId projectId
@@ -35,8 +35,16 @@ export const trustedIpServiceFactory = ({
return trustedIps; return trustedIps;
}; };
const addProjectIp = async ({ projectId, actorId, actor, ipAddress: ip, comment, isActive }: TCreateIpDTO) => { const addProjectIp = async ({
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); projectId,
actorId,
actor,
actorOrgId,
ipAddress: ip,
comment,
isActive
}: TCreateIpDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList);
const project = await projectDAL.findById(projectId); const project = await projectDAL.findById(projectId);
@@ -65,8 +73,16 @@ export const trustedIpServiceFactory = ({
return { trustedIp, project }; // for audit log return { trustedIp, project }; // for audit log
}; };
const updateProjectIp = async ({ projectId, actorId, actor, ipAddress: ip, comment, trustedIpId }: TUpdateIpDTO) => { const updateProjectIp = async ({
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); projectId,
actorId,
actor,
actorOrgId,
ipAddress: ip,
comment,
trustedIpId
}: TUpdateIpDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList);
const project = await projectDAL.findById(projectId); const project = await projectDAL.findById(projectId);
@@ -97,8 +113,8 @@ export const trustedIpServiceFactory = ({
return { trustedIp, project }; // for audit log return { trustedIp, project }; // for audit log
}; };
const deleteProjectIp = async ({ projectId, actorId, actor, trustedIpId }: TDeleteIpDTO) => { const deleteProjectIp = async ({ projectId, actorId, actor, actorOrgId, trustedIpId }: TDeleteIpDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList);
const project = await projectDAL.findById(projectId); const project = await projectDAL.findById(projectId);
+4 -2
View File
@@ -15,9 +15,11 @@ const envSchema = z
PORT: z.coerce.number().default(4000), PORT: z.coerce.number().default(4000),
REDIS_URL: zpStr(z.string()), REDIS_URL: zpStr(z.string()),
HOST: zpStr(z.string().default("localhost")), HOST: zpStr(z.string().default("localhost")),
DB_CONNECTION_URI: zpStr(z.string().describe("Postgres database conntection string")), DB_CONNECTION_URI: zpStr(z.string().describe("Postgres database connection string")),
DB_ROOT_CERT: zpStr(z.string().describe("Postgres database base64-encoded CA cert").optional()),
NODE_ENV: z.enum(["development", "test", "production"]).default("production"), NODE_ENV: z.enum(["development", "test", "production"]).default("production"),
SALT_ROUNDS: z.coerce.number().default(10), SALT_ROUNDS: z.coerce.number().default(10),
INITIAL_ORGANIZATION_NAME: zpStr(z.string().optional()),
// TODO(akhilmhdh): will be changed to one // TODO(akhilmhdh): will be changed to one
ENCRYPTION_KEY: zpStr(z.string().optional()), ENCRYPTION_KEY: zpStr(z.string().optional()),
ROOT_ENCRYPTION_KEY: zpStr(z.string().optional()), ROOT_ENCRYPTION_KEY: zpStr(z.string().optional()),
@@ -93,7 +95,7 @@ const envSchema = z
SECRET_SCANNING_GIT_APP_ID: zpStr(z.string().optional()), SECRET_SCANNING_GIT_APP_ID: zpStr(z.string().optional()),
SECRET_SCANNING_PRIVATE_KEY: zpStr(z.string().optional()), SECRET_SCANNING_PRIVATE_KEY: zpStr(z.string().optional()),
// LICENCE // LICENCE
LICENSE_SERVER_URL: zpStr(z.string().optional()), LICENSE_SERVER_URL: zpStr(z.string().optional().default("https://portal.infisical.com")),
LICENSE_SERVER_KEY: zpStr(z.string().optional()), LICENSE_SERVER_KEY: zpStr(z.string().optional()),
LICENSE_KEY: zpStr(z.string().optional()), LICENSE_KEY: zpStr(z.string().optional()),
STANDALONE_MODE: z STANDALONE_MODE: z
+2
View File
@@ -4,12 +4,14 @@ export type TOrgPermission = {
actor: ActorType; actor: ActorType;
actorId: string; actorId: string;
orgId: string; orgId: string;
actorOrgId?: string;
}; };
export type TProjectPermission = { export type TProjectPermission = {
actor: ActorType; actor: ActorType;
actorId: string; actorId: string;
projectId: string; projectId: string;
actorOrgId?: string;
}; };
export type RequiredKeys<T> = { export type RequiredKeys<T> = {
+6 -2
View File
@@ -12,7 +12,11 @@ dotenv.config();
const run = async () => { const run = async () => {
const logger = await initLogger(); const logger = await initLogger();
const appCfg = initEnvConfig(logger); const appCfg = initEnvConfig(logger);
const db = initDbConnection(appCfg.DB_CONNECTION_URI); const db = initDbConnection({
dbConnectionUri: appCfg.DB_CONNECTION_URI,
dbRootCert: appCfg.DB_ROOT_CERT
});
const smtp = smtpServiceFactory(formatSmtpConfig()); const smtp = smtpServiceFactory(formatSmtpConfig());
const queue = queueServiceFactory(appCfg.REDIS_URL); const queue = queueServiceFactory(appCfg.REDIS_URL);
@@ -36,7 +40,7 @@ const run = async () => {
port: appCfg.PORT, port: appCfg.PORT,
host: appCfg.HOST, host: appCfg.HOST,
listenTextResolver: (address) => { listenTextResolver: (address) => {
bootstrap(); void bootstrap();
return address; return address;
} }
}); });
+6 -3
View File
@@ -5,6 +5,7 @@ import type { FastifyCookieOptions } from "@fastify/cookie";
import cookie from "@fastify/cookie"; import cookie from "@fastify/cookie";
import type { FastifyCorsOptions } from "@fastify/cors"; import type { FastifyCorsOptions } from "@fastify/cors";
import cors from "@fastify/cors"; import cors from "@fastify/cors";
import fastifyEtag from "@fastify/etag";
import fastifyFormBody from "@fastify/formbody"; import fastifyFormBody from "@fastify/formbody";
import helmet from "@fastify/helmet"; import helmet from "@fastify/helmet";
import type { FastifyRateLimitOptions } from "@fastify/rate-limit"; import type { FastifyRateLimitOptions } from "@fastify/rate-limit";
@@ -13,11 +14,10 @@ import fasitfy from "fastify";
import { Knex } from "knex"; import { Knex } from "knex";
import { Logger } from "pino"; import { Logger } from "pino";
import { getConfig } from "@app/lib/config/env";
import { TQueueServiceFactory } from "@app/queue"; import { TQueueServiceFactory } from "@app/queue";
import { TSmtpService } from "@app/services/smtp/smtp-service"; import { TSmtpService } from "@app/services/smtp/smtp-service";
import { getConfig } from "@lib/config/env";
import { globalRateLimiterCfg } from "./config/rateLimiter"; import { globalRateLimiterCfg } from "./config/rateLimiter";
import { fastifyErrHandler } from "./plugins/error-handler"; import { fastifyErrHandler } from "./plugins/error-handler";
import { registerExternalNextjs } from "./plugins/external-nextjs"; import { registerExternalNextjs } from "./plugins/external-nextjs";
@@ -39,6 +39,7 @@ export const main = async ({ db, smtp, logger, queue }: TMain) => {
const server = fasitfy({ const server = fasitfy({
logger, logger,
trustProxy: true, trustProxy: true,
connectionTimeout: 30 * 1000,
ignoreTrailingSlash: true ignoreTrailingSlash: true
}).withTypeProvider<ZodTypeProvider>(); }).withTypeProvider<ZodTypeProvider>();
@@ -50,6 +51,8 @@ export const main = async ({ db, smtp, logger, queue }: TMain) => {
secret: appCfg.COOKIE_SECRET_SIGN_KEY secret: appCfg.COOKIE_SECRET_SIGN_KEY
}); });
await server.register(fastifyEtag);
await server.register<FastifyCorsOptions>(cors, { await server.register<FastifyCorsOptions>(cors, {
credentials: true, credentials: true,
origin: appCfg.SITE_URL || true origin: appCfg.SITE_URL || true
@@ -72,7 +75,7 @@ export const main = async ({ db, smtp, logger, queue }: TMain) => {
if (appCfg.isProductionMode) { if (appCfg.isProductionMode) {
await server.register(registerExternalNextjs, { await server.register(registerExternalNextjs, {
standaloneMode: appCfg.STANDALONE_MODE, standaloneMode: appCfg.STANDALONE_MODE,
dir: path.join(__dirname, "../"), dir: path.join(__dirname, "../../"),
port: appCfg.PORT port: appCfg.PORT
}); });
} }
+2 -2
View File
@@ -12,9 +12,9 @@ type BootstrapOpt = {
db: Knex; db: Knex;
}; };
const bootstrapCb = () => { const bootstrapCb = async () => {
const appCfg = getConfig(); const appCfg = getConfig();
const serverCfg = getServerCfg(); const serverCfg = await getServerCfg();
if (!serverCfg.initialized) { if (!serverCfg.initialized) {
console.info(`Welcome to Infisical console.info(`Welcome to Infisical
@@ -10,6 +10,7 @@ import { TIdentityAccessTokenJwtPayload } from "@app/services/identity-access-to
export type TAuthMode = export type TAuthMode =
| { | {
orgId?: string;
authMode: AuthMode.JWT; authMode: AuthMode.JWT;
actor: ActorType.USER; actor: ActorType.USER;
userId: string; userId: string;
@@ -21,6 +22,7 @@ export type TAuthMode =
actor: ActorType.USER; actor: ActorType.USER;
userId: string; userId: string;
user: TUsers; user: TUsers;
orgId?: string;
} }
| { | {
authMode: AuthMode.SERVICE_TOKEN; authMode: AuthMode.SERVICE_TOKEN;
@@ -82,8 +84,8 @@ export const injectIdentity = fp(async (server: FastifyZodProvider) => {
switch (authMode) { switch (authMode) {
case AuthMode.JWT: { case AuthMode.JWT: {
const { user, tokenVersionId } = await server.services.authToken.fnValidateJwtIdentity(token); const { user, tokenVersionId, orgId } = await server.services.authToken.fnValidateJwtIdentity(token);
req.auth = { authMode: AuthMode.JWT, user, userId: user.id, tokenVersionId, actor }; req.auth = { authMode: AuthMode.JWT, user, userId: user.id, tokenVersionId, actor, orgId };
break; break;
} }
case AuthMode.IDENTITY_ACCESS_TOKEN: { case AuthMode.IDENTITY_ACCESS_TOKEN: {
@@ -9,7 +9,7 @@ export const injectPermission = fp(async (server) => {
if (!req.auth) return; if (!req.auth) return;
if (req.auth.actor === ActorType.USER) { if (req.auth.actor === ActorType.USER) {
req.permission = { type: ActorType.USER, id: req.auth.userId }; req.permission = { type: ActorType.USER, id: req.auth.userId, orgId: req.auth?.orgId };
} else if (req.auth.actor === ActorType.IDENTITY) { } else if (req.auth.actor === ActorType.IDENTITY) {
req.permission = { type: ActorType.IDENTITY, id: req.auth.identityId }; req.permission = { type: ActorType.IDENTITY, id: req.auth.identityId };
} else if (req.auth.actor === ActorType.SERVICE) { } else if (req.auth.actor === ActorType.SERVICE) {
@@ -45,6 +45,9 @@ export const registerExternalNextjs = async (
server.route({ server.route({
method: ["GET", "PUT", "PATCH", "POST", "DELETE"], method: ["GET", "PUT", "PATCH", "POST", "DELETE"],
url: "/*", url: "/*",
schema: {
hide: true
},
handler: (req, res) => handler: (req, res) =>
nextApp nextApp
.getRequestHandler()(req.raw, res.raw) .getRequestHandler()(req.raw, res.raw)
+5 -4
View File
@@ -25,13 +25,13 @@ export const fastifySwagger = fp(async (fastify) => {
], ],
components: { components: {
securitySchemes: { securitySchemes: {
bearer: { bearerAuth: {
type: "http", type: "http",
scheme: "bearer", scheme: "bearer",
bearerFormat: "JWT", bearerFormat: "JWT",
description: "A service token in Infisical" description: "An access token in Infisical"
}, },
apiKey: { apiKeyAuth: {
type: "apiKey", type: "apiKey",
in: "header", in: "header",
name: "X-API-Key", name: "X-API-Key",
@@ -43,6 +43,7 @@ export const fastifySwagger = fp(async (fastify) => {
}); });
await fastify.register(swaggerUI, { await fastify.register(swaggerUI, {
routePrefix: "/docs" routePrefix: "/api/docs",
prefix: "/api/docs"
}); });
}); });
+2 -2
View File
@@ -513,9 +513,9 @@ export const registerRoutes = async (
}) })
} }
}, },
handler: () => { handler: async () => {
const cfg = getConfig(); const cfg = getConfig();
const serverCfg = getServerCfg(); const serverCfg = await getServerCfg();
return { return {
date: new Date(), date: new Date(),
message: "Ok" as const, message: "Ok" as const,
+7 -5
View File
@@ -20,8 +20,8 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
}) })
} }
}, },
handler: () => { handler: async () => {
const config = getServerCfg(); const config = await getServerCfg();
return { config }; return { config };
} }
}); });
@@ -72,13 +72,14 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
200: z.object({ 200: z.object({
message: z.string(), message: z.string(),
user: UsersSchema, user: UsersSchema,
token: z.string() token: z.string(),
new: z.string()
}) })
} }
}, },
handler: async (req, res) => { handler: async (req, res) => {
const appCfg = getConfig(); const appCfg = getConfig();
const serverCfg = getServerCfg(); const serverCfg = await getServerCfg();
if (serverCfg.initialized) if (serverCfg.initialized)
throw new UnauthorizedError({ name: "Admin sign up", message: "Admin has been created" }); throw new UnauthorizedError({ name: "Admin sign up", message: "Admin has been created" });
const { user, token } = await server.services.superAdmin.adminSignUp({ const { user, token } = await server.services.superAdmin.adminSignUp({
@@ -107,7 +108,8 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
return { return {
message: "Successfully set up admin account", message: "Successfully set up admin account",
user: user.user, user: user.user,
token: token.access token: token.access,
new: "123"
}; };
} }
}); });
+2 -1
View File
@@ -88,7 +88,8 @@ export const registerAuthRoutes = async (server: FastifyZodProvider) => {
authTokenType: AuthTokenType.ACCESS_TOKEN, authTokenType: AuthTokenType.ACCESS_TOKEN,
userId: decodedToken.userId, userId: decodedToken.userId,
tokenVersionId: tokenVersion.id, tokenVersionId: tokenVersion.id,
accessVersion: tokenVersion.accessVersion accessVersion: tokenVersion.accessVersion,
organizationId: decodedToken.organizationId
}, },
appCfg.AUTH_SECRET, appCfg.AUTH_SECRET,
{ expiresIn: appCfg.JWT_AUTH_LIFETIME } { expiresIn: appCfg.JWT_AUTH_LIFETIME }
@@ -29,6 +29,7 @@ export const registerProjectBotRouter = async (server: FastifyZodProvider) => {
const bot = await server.services.projectBot.findBotByProjectId({ const bot = await server.services.projectBot.findBotByProjectId({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.params.projectId projectId: req.params.projectId
}); });
return { bot }; return { bot };
@@ -68,6 +69,7 @@ export const registerProjectBotRouter = async (server: FastifyZodProvider) => {
const bot = await server.services.projectBot.setBotActiveState({ const bot = await server.services.projectBot.setBotActiveState({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
botId: req.params.botId, botId: req.params.botId,
botKey: req.body.botKey, botKey: req.body.botKey,
isActive: req.body.isActive isActive: req.body.isActive
@@ -5,6 +5,7 @@ export const registerIdentityAccessTokenRouter = async (server: FastifyZodProvid
url: "/token/renew", url: "/token/renew",
method: "POST", method: "POST",
schema: { schema: {
description: "Renew access token",
body: z.object({ body: z.object({
accessToken: z.string().trim() accessToken: z.string().trim()
}), }),
@@ -11,6 +11,12 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
url: "/", url: "/",
onRequest: verifyAuth([AuthMode.JWT]), onRequest: verifyAuth([AuthMode.JWT]),
schema: { schema: {
description: "Create identity",
security: [
{
bearerAuth: []
}
],
body: z.object({ body: z.object({
name: z.string().trim(), name: z.string().trim(),
organizationId: z.string().trim(), organizationId: z.string().trim(),
@@ -26,6 +32,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
const identity = await server.services.identity.createIdentity({ const identity = await server.services.identity.createIdentity({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
...req.body, ...req.body,
orgId: req.body.organizationId orgId: req.body.organizationId
}); });
@@ -51,6 +58,12 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
url: "/:identityId", url: "/:identityId",
onRequest: verifyAuth([AuthMode.JWT]), onRequest: verifyAuth([AuthMode.JWT]),
schema: { schema: {
description: "Update identity",
security: [
{
bearerAuth: []
}
],
params: z.object({ params: z.object({
identityId: z.string() identityId: z.string()
}), }),
@@ -68,6 +81,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
const identity = await server.services.identity.updateIdentity({ const identity = await server.services.identity.updateIdentity({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
id: req.params.identityId, id: req.params.identityId,
...req.body ...req.body
}); });
@@ -93,6 +107,12 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
url: "/:identityId", url: "/:identityId",
onRequest: verifyAuth([AuthMode.JWT]), onRequest: verifyAuth([AuthMode.JWT]),
schema: { schema: {
description: "Delete identity",
security: [
{
bearerAuth: []
}
],
params: z.object({ params: z.object({
identityId: z.string() identityId: z.string()
}), }),
@@ -106,6 +126,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
const identity = await server.services.identity.deleteIdentity({ const identity = await server.services.identity.deleteIdentity({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
id: req.params.identityId id: req.params.identityId
}); });
@@ -24,6 +24,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
url: "/universal-auth/login", url: "/universal-auth/login",
method: "POST", method: "POST",
schema: { schema: {
description: "Login with Universal Auth",
body: z.object({ body: z.object({
clientId: z.string().trim(), clientId: z.string().trim(),
clientSecret: z.string().trim() clientSecret: z.string().trim()
@@ -67,6 +68,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
method: "POST", method: "POST",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: { schema: {
description: "Attach Universal Auth configuration onto identity",
security: [
{
bearerAuth: []
}
],
params: z.object({ params: z.object({
identityId: z.string().trim() identityId: z.string().trim()
}), }),
@@ -112,6 +119,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
const identityUniversalAuth = await server.services.identityUa.attachUa({ const identityUniversalAuth = await server.services.identityUa.attachUa({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
...req.body, ...req.body,
identityId: req.params.identityId identityId: req.params.identityId
}); });
@@ -140,6 +148,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
method: "PATCH", method: "PATCH",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: { schema: {
description: "Update Universal Auth configuration on identity",
security: [
{
bearerAuth: []
}
],
params: z.object({ params: z.object({
identityId: z.string() identityId: z.string()
}), }),
@@ -178,6 +192,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
const identityUniversalAuth = await server.services.identityUa.updateUa({ const identityUniversalAuth = await server.services.identityUa.updateUa({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
...req.body, ...req.body,
identityId: req.params.identityId identityId: req.params.identityId
}); });
@@ -207,6 +222,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
method: "GET", method: "GET",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: { schema: {
description: "Retrieve Universal Auth configuration on identity",
security: [
{
bearerAuth: []
}
],
params: z.object({ params: z.object({
identityId: z.string() identityId: z.string()
}), }),
@@ -220,6 +241,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
const identityUniversalAuth = await server.services.identityUa.getIdentityUa({ const identityUniversalAuth = await server.services.identityUa.getIdentityUa({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId identityId: req.params.identityId
}); });
@@ -243,6 +265,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
method: "POST", method: "POST",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: { schema: {
description: "Create Universal Auth Client Secret for identity",
security: [
{
bearerAuth: []
}
],
params: z.object({ params: z.object({
identityId: z.string() identityId: z.string()
}), }),
@@ -262,6 +290,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
const { clientSecret, clientSecretData, orgId } = await server.services.identityUa.createUaClientSecret({ const { clientSecret, clientSecretData, orgId } = await server.services.identityUa.createUaClientSecret({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId, identityId: req.params.identityId,
...req.body ...req.body
}); });
@@ -287,6 +316,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
method: "GET", method: "GET",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: { schema: {
description: "List Universal Auth Client Secrets for identity",
security: [
{
bearerAuth: []
}
],
params: z.object({ params: z.object({
identityId: z.string() identityId: z.string()
}), }),
@@ -300,6 +335,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
const { clientSecrets: clientSecretData, orgId } = await server.services.identityUa.getUaClientSecrets({ const { clientSecrets: clientSecretData, orgId } = await server.services.identityUa.getUaClientSecrets({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId identityId: req.params.identityId
}); });
@@ -322,6 +358,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
method: "POST", method: "POST",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: { schema: {
description: "Revoke Universal Auth Client Secrets for identity",
security: [
{
bearerAuth: []
}
],
params: z.object({ params: z.object({
identityId: z.string(), identityId: z.string(),
clientSecretId: z.string() clientSecretId: z.string()
@@ -336,6 +378,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
const clientSecretData = await server.services.identityUa.revokeUaClientSecret({ const clientSecretData = await server.services.identityUa.revokeUaClientSecret({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId, identityId: req.params.identityId,
clientSecretId: req.params.clientSecretId clientSecretId: req.params.clientSecretId
}); });
@@ -53,6 +53,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const integrationAuth = await server.services.integrationAuth.getIntegrationAuth({ const integrationAuth = await server.services.integrationAuth.getIntegrationAuth({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId id: req.params.integrationAuthId
}); });
return { integrationAuth }; return { integrationAuth };
@@ -78,6 +79,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const integrationAuth = await server.services.integrationAuth.deleteIntegrationAuths({ const integrationAuth = await server.services.integrationAuth.deleteIntegrationAuths({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
integration: req.query.integration, integration: req.query.integration,
projectId: req.query.projectId projectId: req.query.projectId
}); });
@@ -115,6 +117,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const integrationAuth = await server.services.integrationAuth.deleteIntegrationAuthById({ const integrationAuth = await server.services.integrationAuth.deleteIntegrationAuthById({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId id: req.params.integrationAuthId
}); });
@@ -154,6 +157,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const integrationAuth = await server.services.integrationAuth.oauthExchange({ const integrationAuth = await server.services.integrationAuth.oauthExchange({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.body.workspaceId, projectId: req.body.workspaceId,
...req.body ...req.body
}); });
@@ -196,6 +200,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const integrationAuth = await server.services.integrationAuth.saveIntegrationToken({ const integrationAuth = await server.services.integrationAuth.saveIntegrationToken({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.body.workspaceId, projectId: req.body.workspaceId,
...req.body ...req.body
}); });
@@ -242,6 +247,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const apps = await server.services.integrationAuth.getIntegrationApps({ const apps = await server.services.integrationAuth.getIntegrationApps({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId, id: req.params.integrationAuthId,
...req.query ...req.query
}); });
@@ -272,6 +278,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const teams = await server.services.integrationAuth.getIntegrationAuthTeams({ const teams = await server.services.integrationAuth.getIntegrationAuthTeams({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId id: req.params.integrationAuthId
}); });
return { teams }; return { teams };
@@ -299,6 +306,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const branches = await server.services.integrationAuth.getVercelBranches({ const branches = await server.services.integrationAuth.getVercelBranches({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId, id: req.params.integrationAuthId,
appId: req.query.appId appId: req.query.appId
}); });
@@ -327,6 +335,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const groups = await server.services.integrationAuth.getChecklyGroups({ const groups = await server.services.integrationAuth.getChecklyGroups({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId, id: req.params.integrationAuthId,
accountId: req.query.accountId accountId: req.query.accountId
}); });
@@ -352,6 +361,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const orgs = await server.services.integrationAuth.getQoveryOrgs({ const orgs = await server.services.integrationAuth.getQoveryOrgs({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId id: req.params.integrationAuthId
}); });
return { orgs }; return { orgs };
@@ -379,6 +389,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const projects = await server.services.integrationAuth.getQoveryProjects({ const projects = await server.services.integrationAuth.getQoveryProjects({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId, id: req.params.integrationAuthId,
orgId: req.query.orgId orgId: req.query.orgId
}); });
@@ -407,6 +418,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const environments = await server.services.integrationAuth.getQoveryEnvs({ const environments = await server.services.integrationAuth.getQoveryEnvs({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId, id: req.params.integrationAuthId,
projectId: req.query.projectId projectId: req.query.projectId
}); });
@@ -435,6 +447,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const apps = await server.services.integrationAuth.getQoveryApps({ const apps = await server.services.integrationAuth.getQoveryApps({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId, id: req.params.integrationAuthId,
environmentId: req.query.environmentId environmentId: req.query.environmentId
}); });
@@ -463,6 +476,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const containers = await server.services.integrationAuth.getQoveryContainers({ const containers = await server.services.integrationAuth.getQoveryContainers({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId, id: req.params.integrationAuthId,
environmentId: req.query.environmentId environmentId: req.query.environmentId
}); });
@@ -491,6 +505,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const jobs = await server.services.integrationAuth.getQoveryJobs({ const jobs = await server.services.integrationAuth.getQoveryJobs({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId, id: req.params.integrationAuthId,
environmentId: req.query.environmentId environmentId: req.query.environmentId
}); });
@@ -519,6 +534,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const environments = await server.services.integrationAuth.getRailwayEnvironments({ const environments = await server.services.integrationAuth.getRailwayEnvironments({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId, id: req.params.integrationAuthId,
appId: req.query.appId appId: req.query.appId
}); });
@@ -547,6 +563,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const services = await server.services.integrationAuth.getRailwayServices({ const services = await server.services.integrationAuth.getRailwayServices({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId, id: req.params.integrationAuthId,
appId: req.query.appId appId: req.query.appId
}); });
@@ -582,6 +599,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const workspaces = await server.services.integrationAuth.getBitbucketWorkspaces({ const workspaces = await server.services.integrationAuth.getBitbucketWorkspaces({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId id: req.params.integrationAuthId
}); });
return { workspaces }; return { workspaces };
@@ -614,6 +632,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const secretGroups = await server.services.integrationAuth.getNorthFlankSecretGroups({ const secretGroups = await server.services.integrationAuth.getNorthFlankSecretGroups({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId, id: req.params.integrationAuthId,
appId: req.query.appId appId: req.query.appId
}); });
@@ -647,6 +666,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const buildConfigs = await server.services.integrationAuth.getTeamcityBuildConfigs({ const buildConfigs = await server.services.integrationAuth.getTeamcityBuildConfigs({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId, id: req.params.integrationAuthId,
appId: req.query.appId appId: req.query.appId
}); });
@@ -50,6 +50,7 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => {
const { integration, integrationAuth } = 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,
actorOrgId: req.permission.orgId,
...req.body ...req.body
}); });
await server.services.auditLog.createAuditLog({ await server.services.auditLog.createAuditLog({
@@ -107,6 +108,7 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => {
const integration = await server.services.integration.updateIntegration({ const integration = await server.services.integration.updateIntegration({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationId, id: req.params.integrationId,
...req.body ...req.body
}); });
@@ -132,6 +134,7 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => {
const integration = await server.services.integration.deleteIntegration({ const integration = await server.services.integration.deleteIntegration({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationId id: req.params.integrationId
}); });
@@ -26,7 +26,8 @@ export const registerInviteOrgRouter = async (server: FastifyZodProvider) => {
const completeInviteLink = await server.services.org.inviteUserToOrganization({ const completeInviteLink = await server.services.org.inviteUserToOrganization({
orgId: req.body.organizationId, orgId: req.body.organizationId,
userId: req.permission.id, userId: req.permission.id,
inviteeEmail: req.body.inviteeEmail inviteeEmail: req.body.inviteeEmail,
actorOrgId: req.permission.orgId
}); });
return { return {
@@ -37,7 +37,11 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
}, },
onRequest: verifyAuth([AuthMode.JWT]), onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => { handler: async (req) => {
const organization = await server.services.org.findOrganizationById(req.permission.id, req.params.organizationId); const organization = await server.services.org.findOrganizationById(
req.permission.id,
req.params.organizationId,
req.permission.orgId
);
return { organization }; return { organization };
} }
}); });
@@ -68,17 +72,29 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
}, },
onRequest: verifyAuth([AuthMode.JWT]), onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => { handler: async (req) => {
const users = await server.services.org.findAllOrgMembers(req.permission.id, req.params.organizationId); const users = await server.services.org.findAllOrgMembers(
req.permission.id,
req.params.organizationId,
req.permission.orgId
);
return { users }; return { users };
} }
}); });
server.route({ server.route({
method: "PATCH", method: "PATCH",
url: "/:organizationId/name", url: "/:organizationId",
schema: { schema: {
params: z.object({ organizationId: z.string().trim() }), params: z.object({ organizationId: z.string().trim() }),
body: z.object({ name: z.string().trim() }), body: z.object({
name: z.string().trim().optional(),
slug: z
.string()
.trim()
.regex(/^[a-zA-Z0-9-]+$/, "Name must only contain alphanumeric characters or hyphens")
.optional(),
authEnforced: z.boolean().optional()
}),
response: { response: {
200: z.object({ 200: z.object({
message: z.string(), message: z.string(),
@@ -88,11 +104,14 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
}, },
onRequest: verifyAuth([AuthMode.JWT]), onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => { handler: async (req) => {
const organization = await server.services.org.updateOrgName( const organization = await server.services.org.updateOrg({
req.permission.id, actor: req.permission.type,
req.params.organizationId, actorId: req.permission.id,
req.body.name actorOrgId: req.permission.orgId,
); orgId: req.params.organizationId,
data: req.body
});
return { return {
message: "Successfully changed organization name", message: "Successfully changed organization name",
organization organization
@@ -115,7 +134,8 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
handler: async (req) => { handler: async (req) => {
const incidentContactsOrg = await req.server.services.org.findIncidentContacts( const incidentContactsOrg = await req.server.services.org.findIncidentContacts(
req.permission.id, req.permission.id,
req.params.organizationId req.params.organizationId,
req.permission.orgId
); );
return { incidentContactsOrg }; return { incidentContactsOrg };
} }
@@ -138,7 +158,8 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
const incidentContactsOrg = await req.server.services.org.createIncidentContact( const incidentContactsOrg = await req.server.services.org.createIncidentContact(
req.permission.id, req.permission.id,
req.params.organizationId, req.params.organizationId,
req.body.email req.body.email,
req.permission.orgId
); );
return { incidentContactsOrg }; return { incidentContactsOrg };
} }
@@ -160,7 +181,8 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
const incidentContactsOrg = await req.server.services.org.deleteIncidentContact( const incidentContactsOrg = await req.server.services.org.deleteIncidentContact(
req.permission.id, req.permission.id,
req.params.organizationId, req.params.organizationId,
req.params.incidentContactId req.params.incidentContactId,
req.permission.orgId
); );
return { incidentContactsOrg }; return { incidentContactsOrg };
} }
@@ -10,6 +10,13 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
url: "/:workspaceId/environments", url: "/:workspaceId/environments",
method: "POST", method: "POST",
schema: { schema: {
description: "Create environment",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({ params: z.object({
workspaceId: z.string().trim() workspaceId: z.string().trim()
}), }),
@@ -30,6 +37,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
const environment = await server.services.projectEnv.createEnvironment({ const environment = await server.services.projectEnv.createEnvironment({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId, projectId: req.params.workspaceId,
...req.body ...req.body
}); });
@@ -57,6 +65,13 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
url: "/:workspaceId/environments/:id", url: "/:workspaceId/environments/:id",
method: "PATCH", method: "PATCH",
schema: { schema: {
description: "Update environment",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({ params: z.object({
workspaceId: z.string().trim(), workspaceId: z.string().trim(),
id: z.string().trim() id: z.string().trim()
@@ -79,6 +94,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
const { environment, old } = 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,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId, projectId: req.params.workspaceId,
id: req.params.id, id: req.params.id,
...req.body ...req.body
@@ -112,6 +128,13 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
url: "/:workspaceId/environments/:id", url: "/:workspaceId/environments/:id",
method: "DELETE", method: "DELETE",
schema: { schema: {
description: "Delete environment",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({ params: z.object({
workspaceId: z.string().trim(), workspaceId: z.string().trim(),
id: z.string().trim() id: z.string().trim()
@@ -129,6 +152,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
const environment = await server.services.projectEnv.deleteEnvironment({ const environment = await server.services.projectEnv.deleteEnvironment({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId, projectId: req.params.workspaceId,
id: req.params.id id: req.params.id
}); });
@@ -30,6 +30,7 @@ export const registerProjectKeyRouter = async (server: FastifyZodProvider) => {
projectId: req.params.workspaceId, projectId: req.params.workspaceId,
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
nonce: req.body.key.nonce, nonce: req.body.key.nonce,
receiverId: req.body.key.userId, receiverId: req.body.key.userId,
encryptedKey: req.body.key.encryptedKey encryptedKey: req.body.key.encryptedKey
@@ -10,6 +10,13 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
url: "/:workspaceId/memberships", url: "/:workspaceId/memberships",
method: "GET", method: "GET",
schema: { schema: {
description: "Return project user memberships",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({ params: z.object({
workspaceId: z.string().trim() workspaceId: z.string().trim()
}), }),
@@ -35,6 +42,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
const memberships = await server.services.projectMembership.getProjectMemberships({ const memberships = await server.services.projectMembership.getProjectMemberships({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId projectId: req.params.workspaceId
}); });
return { memberships }; return { memberships };
@@ -70,6 +78,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
const data = await server.services.projectMembership.addUsersToProject({ const data = await server.services.projectMembership.addUsersToProject({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId, projectId: req.params.workspaceId,
members: req.body.members members: req.body.members
}); });
@@ -94,6 +103,13 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
url: "/:workspaceId/memberships/:membershipId", url: "/:workspaceId/memberships/:membershipId",
method: "PATCH", method: "PATCH",
schema: { schema: {
description: "Update project user membership",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({ params: z.object({
workspaceId: z.string().trim(), workspaceId: z.string().trim(),
membershipId: z.string().trim() membershipId: z.string().trim()
@@ -112,6 +128,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
const membership = await server.services.projectMembership.updateProjectMembership({ const membership = await server.services.projectMembership.updateProjectMembership({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId, projectId: req.params.workspaceId,
membershipId: req.params.membershipId, membershipId: req.params.membershipId,
role: req.body.role role: req.body.role
@@ -138,6 +155,13 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
url: "/:workspaceId/memberships/:membershipId", url: "/:workspaceId/memberships/:membershipId",
method: "DELETE", method: "DELETE",
schema: { schema: {
description: "Delete project user membership",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({ params: z.object({
workspaceId: z.string().trim(), workspaceId: z.string().trim(),
membershipId: z.string().trim() membershipId: z.string().trim()
@@ -153,6 +177,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
const membership = await server.services.projectMembership.deleteProjectMembership({ const membership = await server.services.projectMembership.deleteProjectMembership({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId, projectId: req.params.workspaceId,
membershipId: req.params.membershipId membershipId: req.params.membershipId
}); });
+12 -1
View File
@@ -46,6 +46,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const publicKeys = await server.services.projectKey.getProjectPublicKeys({ const publicKeys = await server.services.projectKey.getProjectPublicKeys({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId projectId: req.params.workspaceId
}); });
return { publicKeys }; return { publicKeys };
@@ -81,7 +82,8 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const users = await server.services.projectMembership.getProjectMemberships({ const users = await server.services.projectMembership.getProjectMemberships({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
projectId: req.params.workspaceId projectId: req.params.workspaceId,
actorOrgId: req.permission.orgId
}); });
return { users }; return { users };
} }
@@ -122,6 +124,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const workspace = await server.services.project.getAProject({ const workspace = await server.services.project.getAProject({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId projectId: req.params.workspaceId
}); });
return { workspace }; return { workspace };
@@ -148,6 +151,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
orgId: req.body.organizationId, orgId: req.body.organizationId,
actorOrgId: req.permission.orgId,
workspaceName: req.body.workspaceName workspaceName: req.body.workspaceName
}); });
return { workspace }; return { workspace };
@@ -172,6 +176,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const workspace = await server.services.project.deleteProject({ const workspace = await server.services.project.deleteProject({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId projectId: req.params.workspaceId
}); });
return { workspace }; return { workspace };
@@ -200,6 +205,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const workspace = await server.services.project.updateName({ const workspace = await server.services.project.updateName({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId, projectId: req.params.workspaceId,
name: req.body.name name: req.body.name
}); });
@@ -232,6 +238,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const workspace = await server.services.project.toggleAutoCapitalization({ const workspace = await server.services.project.toggleAutoCapitalization({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId, projectId: req.params.workspaceId,
autoCapitalization: req.body.autoCapitalization autoCapitalization: req.body.autoCapitalization
}); });
@@ -264,6 +271,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const { invitee, latestKey } = await server.services.projectMembership.inviteUserToProject({ const { invitee, latestKey } = await server.services.projectMembership.inviteUserToProject({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId, projectId: req.params.workspaceId,
email: req.body.email email: req.body.email
}); });
@@ -309,6 +317,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const integrations = await server.services.integration.listIntegrationByProject({ const integrations = await server.services.integration.listIntegrationByProject({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId projectId: req.params.workspaceId
}); });
return { integrations }; return { integrations };
@@ -333,6 +342,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const authorizations = await server.services.integrationAuth.listIntegrationAuthByProjectId({ const authorizations = await server.services.integrationAuth.listIntegrationAuthByProjectId({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId projectId: req.params.workspaceId
}); });
return { authorizations }; return { authorizations };
@@ -357,6 +367,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const serviceTokenData = await server.services.serviceToken.getProjectServiceTokens({ const serviceTokenData = await server.services.serviceToken.getProjectServiceTokens({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId projectId: req.params.workspaceId
}); });
return { serviceTokenData }; return { serviceTokenData };
@@ -11,6 +11,13 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
url: "/", url: "/",
method: "POST", method: "POST",
schema: { schema: {
description: "Create folders",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
body: z.object({ body: z.object({
workspaceId: z.string().trim(), workspaceId: z.string().trim(),
environment: z.string().trim(), environment: z.string().trim(),
@@ -31,6 +38,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
const folder = await server.services.folder.createFolder({ const folder = await server.services.folder.createFolder({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
...req.body, ...req.body,
projectId: req.body.workspaceId, projectId: req.body.workspaceId,
path path
@@ -56,6 +64,13 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
url: "/:folderId", url: "/:folderId",
method: "PATCH", method: "PATCH",
schema: { schema: {
description: "Update folder",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({ params: z.object({
// old way this was name // old way this was name
folderId: z.string() folderId: z.string()
@@ -80,6 +95,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
const { folder, old } = 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,
actorOrgId: req.permission.orgId,
...req.body, ...req.body,
projectId: req.body.workspaceId, projectId: req.body.workspaceId,
id: req.params.folderId, id: req.params.folderId,
@@ -107,6 +123,13 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
url: "/:folderId", url: "/:folderId",
method: "DELETE", method: "DELETE",
schema: { schema: {
description: "Delete a folder",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({ params: z.object({
folderId: z.string() folderId: z.string()
}), }),
@@ -129,6 +152,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
const folder = await server.services.folder.deleteFolder({ const folder = await server.services.folder.deleteFolder({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
...req.body, ...req.body,
projectId: req.body.workspaceId, projectId: req.body.workspaceId,
id: req.params.folderId, id: req.params.folderId,
@@ -155,6 +179,13 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
url: "/", url: "/",
method: "GET", method: "GET",
schema: { schema: {
description: "Get folders",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
querystring: z.object({ querystring: z.object({
workspaceId: z.string().trim(), workspaceId: z.string().trim(),
environment: z.string().trim(), environment: z.string().trim(),
@@ -174,6 +205,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
const folders = await server.services.folder.getFolders({ const folders = await server.services.folder.getFolders({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
...req.query, ...req.query,
projectId: req.query.workspaceId, projectId: req.query.workspaceId,
path path
@@ -11,6 +11,13 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
url: "/", url: "/",
method: "POST", method: "POST",
schema: { schema: {
description: "Create secret imports",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
body: z.object({ body: z.object({
workspaceId: z.string().trim(), workspaceId: z.string().trim(),
environment: z.string().trim(), environment: z.string().trim(),
@@ -36,6 +43,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
const secretImport = await server.services.secretImport.createImport({ const secretImport = await server.services.secretImport.createImport({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
...req.body, ...req.body,
projectId: req.body.workspaceId, projectId: req.body.workspaceId,
data: req.body.import data: req.body.import
@@ -64,6 +72,13 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
url: "/:secretImportId", url: "/:secretImportId",
method: "PATCH", method: "PATCH",
schema: { schema: {
description: "Update secret imports",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({ params: z.object({
secretImportId: z.string().trim() secretImportId: z.string().trim()
}), }),
@@ -97,6 +112,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
const secretImport = await server.services.secretImport.updateImport({ const secretImport = await server.services.secretImport.updateImport({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.secretImportId, id: req.params.secretImportId,
...req.body, ...req.body,
projectId: req.body.workspaceId, projectId: req.body.workspaceId,
@@ -126,6 +142,13 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
url: "/:secretImportId", url: "/:secretImportId",
method: "DELETE", method: "DELETE",
schema: { schema: {
description: "Delete secret imports",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({ params: z.object({
secretImportId: z.string().trim() secretImportId: z.string().trim()
}), }),
@@ -150,6 +173,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
const secretImport = await server.services.secretImport.deleteImport({ const secretImport = await server.services.secretImport.deleteImport({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.secretImportId, id: req.params.secretImportId,
...req.body, ...req.body,
projectId: req.body.workspaceId projectId: req.body.workspaceId
@@ -178,6 +202,13 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
url: "/", url: "/",
method: "GET", method: "GET",
schema: { schema: {
description: "Get secret imports",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
querystring: z.object({ querystring: z.object({
workspaceId: z.string().trim(), workspaceId: z.string().trim(),
environment: z.string().trim(), environment: z.string().trim(),
@@ -201,6 +232,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
const secretImports = await server.services.secretImport.getImports({ const secretImports = await server.services.secretImport.getImports({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
...req.query, ...req.query,
projectId: req.query.workspaceId projectId: req.query.workspaceId
}); });
@@ -253,6 +285,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
const importedSecrets = await server.services.secretImport.getSecretsFromImports({ const importedSecrets = await server.services.secretImport.getSecretsFromImports({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
...req.query, ...req.query,
projectId: req.query.workspaceId projectId: req.query.workspaceId
}); });
@@ -23,6 +23,7 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => {
const workspaceTags = await server.services.secretTag.getProjectTags({ const workspaceTags = await server.services.secretTag.getProjectTags({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.params.projectId projectId: req.params.projectId
}); });
return { workspaceTags }; return { workspaceTags };
@@ -52,6 +53,7 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => {
const workspaceTag = await server.services.secretTag.createTag({ const workspaceTag = await server.services.secretTag.createTag({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.params.projectId, projectId: req.params.projectId,
...req.body ...req.body
}); });
@@ -78,6 +80,7 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => {
const workspaceTag = await server.services.secretTag.deleteTag({ const workspaceTag = await server.services.secretTag.deleteTag({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
id: req.params.tagId id: req.params.tagId
}); });
return { workspaceTag }; return { workspaceTag };
+3 -3
View File
@@ -42,7 +42,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
async (req, _accessToken, _refreshToken, profile, cb) => { async (req, _accessToken, _refreshToken, profile, cb) => {
try { try {
const email = profile?.emails?.[0]?.value; const email = profile?.emails?.[0]?.value;
const serverCfg = getServerCfg(); const serverCfg = await getServerCfg();
if (!email) if (!email)
throw new BadRequestError({ throw new BadRequestError({
message: "Email not found", message: "Email not found",
@@ -84,7 +84,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
try { try {
const ghEmails = await fetchGithubEmails(accessToken); const ghEmails = await fetchGithubEmails(accessToken);
const { email } = ghEmails.filter((gitHubEmail) => gitHubEmail.primary)[0]; const { email } = ghEmails.filter((gitHubEmail) => gitHubEmail.primary)[0];
const serverCfg = getServerCfg(); const serverCfg = await getServerCfg();
const { isUserCompleted, providerAuthToken } = await server.services.login.oauth2Login({ const { isUserCompleted, providerAuthToken } = await server.services.login.oauth2Login({
email, email,
firstName: profile.displayName, firstName: profile.displayName,
@@ -120,7 +120,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
async (req: any, _accessToken: string, _refreshToken: string, profile: any, cb: any) => { async (req: any, _accessToken: string, _refreshToken: string, profile: any, cb: any) => {
try { try {
const email = profile.emails[0].value; const email = profile.emails[0].value;
const serverCfg = getServerCfg(); const serverCfg = await getServerCfg();
const { isUserCompleted, providerAuthToken } = await server.services.login.oauth2Login({ const { isUserCompleted, providerAuthToken } = await server.services.login.oauth2Login({
email, email,
firstName: profile.displayName, firstName: profile.displayName,
@@ -47,6 +47,7 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => {
const webhook = await server.services.webhook.createWebhook({ const webhook = await server.services.webhook.createWebhook({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.body.workspaceId, projectId: req.body.workspaceId,
...req.body ...req.body
}); });
@@ -92,6 +93,7 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => {
const webhook = await server.services.webhook.updateWebhook({ const webhook = await server.services.webhook.updateWebhook({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
id: req.params.webhookId, id: req.params.webhookId,
isDisabled: req.body.isDisabled isDisabled: req.body.isDisabled
}); });
@@ -128,6 +130,7 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => {
const webhook = await server.services.webhook.deleteWebhook({ const webhook = await server.services.webhook.deleteWebhook({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
id: req.params.webhookId id: req.params.webhookId
}); });
@@ -169,6 +172,7 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => {
const webhook = await server.services.webhook.testWebhook({ const webhook = await server.services.webhook.testWebhook({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
id: req.params.webhookId id: req.params.webhookId
}); });
return { message: "Successfully tested webhook", webhook }; return { message: "Successfully tested webhook", webhook };
@@ -200,6 +204,7 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => {
const webhooks = await server.services.webhook.listWebhooks({ const webhooks = await server.services.webhook.listWebhooks({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
...req.query, ...req.query,
projectId: req.query.workspaceId projectId: req.query.workspaceId
}); });
@@ -10,6 +10,13 @@ export const registerIdentityOrgRouter = async (server: FastifyZodProvider) => {
url: "/:orgId/identity-memberships", url: "/:orgId/identity-memberships",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: { schema: {
description: "Return organization identity memberships",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({ params: z.object({
orgId: z.string().trim() orgId: z.string().trim()
}), }),
@@ -34,6 +41,7 @@ export const registerIdentityOrgRouter = async (server: FastifyZodProvider) => {
const identityMemberships = await server.services.identity.listOrgIdentities({ const identityMemberships = await server.services.identity.listOrgIdentities({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
orgId: req.params.orgId orgId: req.params.orgId
}); });
return { identityMemberships }; return { identityMemberships };
@@ -32,6 +32,7 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
const identityMembership = await server.services.identityProject.createProjectIdentity({ const identityMembership = await server.services.identityProject.createProjectIdentity({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId, identityId: req.params.identityId,
projectId: req.params.projectId, projectId: req.params.projectId,
role: req.body.role role: req.body.role
@@ -45,6 +46,12 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
url: "/:projectId/identity-memberships/:identityId", url: "/:projectId/identity-memberships/:identityId",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: { schema: {
description: "Update project identity memberships",
security: [
{
bearerAuth: []
}
],
params: z.object({ params: z.object({
projectId: z.string().trim(), projectId: z.string().trim(),
identityId: z.string().trim() identityId: z.string().trim()
@@ -62,6 +69,7 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
const identityMembership = await server.services.identityProject.updateProjectIdentity({ const identityMembership = await server.services.identityProject.updateProjectIdentity({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId, identityId: req.params.identityId,
projectId: req.params.projectId, projectId: req.params.projectId,
role: req.body.role role: req.body.role
@@ -75,6 +83,12 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
url: "/:projectId/identity-memberships/:identityId", url: "/:projectId/identity-memberships/:identityId",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: { schema: {
description: "Delete project identity memberships",
security: [
{
bearerAuth: []
}
],
params: z.object({ params: z.object({
projectId: z.string().trim(), projectId: z.string().trim(),
identityId: z.string().trim() identityId: z.string().trim()
@@ -89,6 +103,7 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
const identityMembership = await server.services.identityProject.deleteProjectIdentity({ const identityMembership = await server.services.identityProject.deleteProjectIdentity({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId, identityId: req.params.identityId,
projectId: req.params.projectId projectId: req.params.projectId
}); });
@@ -101,6 +116,12 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
url: "/:projectId/identity-memberships", url: "/:projectId/identity-memberships",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: { schema: {
description: "Return project identity memberships",
security: [
{
bearerAuth: []
}
],
params: z.object({ params: z.object({
projectId: z.string().trim() projectId: z.string().trim()
}), }),
@@ -125,6 +146,7 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
const identityMemberships = await server.services.identityProject.listProjectIdentities({ const identityMemberships = await server.services.identityProject.listProjectIdentities({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.params.projectId projectId: req.params.projectId
}); });
return { identityMemberships }; return { identityMemberships };
+2 -1
View File
@@ -26,7 +26,7 @@ export const registerMfaRouter = async (server: FastifyZodProvider) => {
const user = await server.store.user.findById(decodedToken.userId); const user = await server.store.user.findById(decodedToken.userId);
if (!user) throw new Error("User not found"); if (!user) throw new Error("User not found");
req.mfa = { userId: user.id, user }; req.mfa = { userId: user.id, user, orgId: decodedToken.organizationId };
}); });
server.route({ server.route({
@@ -75,6 +75,7 @@ export const registerMfaRouter = async (server: FastifyZodProvider) => {
userAgent, userAgent,
ip: req.realIp, ip: req.realIp,
userId: req.mfa.userId, userId: req.mfa.userId,
orgId: req.mfa.orgId,
mfaToken: req.body.mfaToken mfaToken: req.body.mfaToken
}); });
@@ -9,6 +9,13 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
method: "GET", method: "GET",
url: "/:organizationId/memberships", url: "/:organizationId/memberships",
schema: { schema: {
description: "Return organization user memberships",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({ params: z.object({
organizationId: z.string().trim() organizationId: z.string().trim()
}), }),
@@ -33,7 +40,11 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
handler: async (req) => { handler: async (req) => {
if (req.auth.actor !== ActorType.USER) return; if (req.auth.actor !== ActorType.USER) return;
const users = await server.services.org.findAllOrgMembers(req.permission.id, req.params.organizationId); const users = await server.services.org.findAllOrgMembers(
req.permission.id,
req.params.organizationId,
req.permission.orgId
);
return { users }; return { users };
} }
}); });
@@ -42,6 +53,13 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
method: "GET", method: "GET",
url: "/:organizationId/workspaces", url: "/:organizationId/workspaces",
schema: { schema: {
description: "Return projects in organization that user is part of",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({ params: z.object({
organizationId: z.string().trim() organizationId: z.string().trim()
}), }),
@@ -68,6 +86,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
const workspaces = await server.services.org.findAllWorkspaces({ const workspaces = await server.services.org.findAllWorkspaces({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId orgId: req.params.organizationId
}); });
@@ -79,6 +98,13 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
method: "PATCH", method: "PATCH",
url: "/:organizationId/memberships/:membershipId", url: "/:organizationId/memberships/:membershipId",
schema: { schema: {
description: "Update organization user memberships",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({ organizationId: z.string().trim(), membershipId: z.string().trim() }), params: z.object({ organizationId: z.string().trim(), membershipId: z.string().trim() }),
body: z.object({ body: z.object({
role: z.string().trim() role: z.string().trim()
@@ -97,7 +123,8 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
userId: req.permission.id, userId: req.permission.id,
role: req.body.role, role: req.body.role,
orgId: req.params.organizationId, orgId: req.params.organizationId,
membershipId: req.params.membershipId membershipId: req.params.membershipId,
actorOrgId: req.permission.orgId
}); });
return { membership }; return { membership };
} }
@@ -107,6 +134,13 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
method: "DELETE", method: "DELETE",
url: "/:organizationId/memberships/:membershipId", url: "/:organizationId/memberships/:membershipId",
schema: { schema: {
description: "Delete organization user memberships",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({ organizationId: z.string().trim(), membershipId: z.string().trim() }), params: z.object({ organizationId: z.string().trim(), membershipId: z.string().trim() }),
response: { response: {
200: z.object({ 200: z.object({
@@ -121,7 +155,8 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
const membership = await server.services.org.deleteOrgMembership({ const membership = await server.services.org.deleteOrgMembership({
userId: req.permission.id, userId: req.permission.id,
orgId: req.params.organizationId, orgId: req.params.organizationId,
membershipId: req.params.membershipId membershipId: req.params.membershipId,
actorOrgId: req.permission.orgId
}); });
return { membership }; return { membership };
} }
@@ -172,7 +207,8 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
const organization = await server.services.org.deleteOrganizationById( const organization = await server.services.org.deleteOrganizationById(
req.permission.id, req.permission.id,
req.params.organizationId req.params.organizationId,
req.permission.orgId
); );
return { organization }; return { organization };
} }
@@ -10,6 +10,12 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
url: "/:workspaceId/encrypted-key", url: "/:workspaceId/encrypted-key",
method: "GET", method: "GET",
schema: { schema: {
description: "Return encrypted project key",
security: [
{
apiKeyAuth: []
}
],
params: z.object({ params: z.object({
workspaceId: z.string().trim() workspaceId: z.string().trim()
}), }),
@@ -28,7 +34,8 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const key = await server.services.projectKey.getLatestProjectKey({ const key = await server.services.projectKey.getLatestProjectKey({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
projectId: req.params.workspaceId projectId: req.params.workspaceId,
actorOrgId: req.permission.orgId
}); });
await server.services.auditLog.createAuditLog({ await server.services.auditLog.createAuditLog({
@@ -21,6 +21,12 @@ export const registerServiceTokenRouter = async (server: FastifyZodProvider) =>
method: "GET", method: "GET",
onRequest: verifyAuth([AuthMode.SERVICE_TOKEN]), onRequest: verifyAuth([AuthMode.SERVICE_TOKEN]),
schema: { schema: {
description: "Return Infisical Token data",
security: [
{
bearerAuth: []
}
],
response: { response: {
200: ServiceTokensSchema.merge( 200: ServiceTokensSchema.merge(
z.object({ z.object({
@@ -92,6 +98,7 @@ export const registerServiceTokenRouter = async (server: FastifyZodProvider) =>
const { serviceToken, token } = await server.services.serviceToken.createServiceToken({ const { serviceToken, token } = await server.services.serviceToken.createServiceToken({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
...req.body, ...req.body,
projectId: req.body.workspaceId projectId: req.body.workspaceId
}); });
@@ -129,6 +136,7 @@ export const registerServiceTokenRouter = async (server: FastifyZodProvider) =>
const serviceTokenData = await server.services.serviceToken.deleteServiceToken({ const serviceTokenData = await server.services.serviceToken.deleteServiceToken({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.serviceTokenId id: req.params.serviceTokenId
}); });
@@ -71,6 +71,12 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
method: "GET", method: "GET",
url: "/me/organizations", url: "/me/organizations",
schema: { schema: {
description: "Return organizations that current user is part of",
security: [
{
apiKeyAuth: []
}
],
response: { response: {
200: z.object({ 200: z.object({
organizations: OrganizationsSchema.array() organizations: OrganizationsSchema.array()
@@ -179,6 +185,12 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
method: "GET", method: "GET",
url: "/me", url: "/me",
schema: { schema: {
description: "Retrieve the current user on the request",
security: [
{
apiKeyAuth: []
}
],
response: { response: {
200: z.object({ 200: z.object({
user: UsersSchema.merge(UserEncryptionKeysSchema.omit({ verifier: true })) user: UsersSchema.merge(UserEncryptionKeysSchema.omit({ verifier: true }))
@@ -21,7 +21,8 @@ export const registerSecretBlindIndexRouter = async (server: FastifyZodProvider)
const count = await server.services.secretBlindIndex.getSecretBlindIndexStatus({ const count = await server.services.secretBlindIndex.getSecretBlindIndexStatus({
projectId: req.params.projectId, projectId: req.params.projectId,
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type actor: req.permission.type,
actorOrgId: req.permission.orgId
}); });
return count === 0; return count === 0;
} }
@@ -52,7 +53,8 @@ export const registerSecretBlindIndexRouter = async (server: FastifyZodProvider)
const secrets = await server.services.secretBlindIndex.getProjectSecrets({ const secrets = await server.services.secretBlindIndex.getProjectSecrets({
projectId: req.params.projectId, projectId: req.params.projectId,
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type actor: req.permission.type,
actorOrgId: req.permission.orgId
}); });
return { secrets }; return { secrets };
} }
@@ -85,7 +87,8 @@ export const registerSecretBlindIndexRouter = async (server: FastifyZodProvider)
projectId: req.params.projectId, projectId: req.params.projectId,
secretsToUpdate: req.body.secretsToUpdate, secretsToUpdate: req.body.secretsToUpdate,
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type actor: req.permission.type,
actorOrgId: req.permission.orgId
}); });
return { message: "Successfully named workspace secrets" }; return { message: "Successfully named workspace secrets" };
} }
+98 -21
View File
@@ -13,6 +13,7 @@ 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 { BadRequestError } from "@app/lib/errors"; import { BadRequestError } from "@app/lib/errors";
import { removeTrailingSlash } from "@app/lib/fn"; import { removeTrailingSlash } from "@app/lib/fn";
import { getUserAgentType } from "@app/server/plugins/audit-log";
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";
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types"; import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
@@ -37,6 +38,13 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
url: "/raw", url: "/raw",
method: "GET", method: "GET",
schema: { schema: {
description: "List secrets",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
querystring: z.object({ querystring: z.object({
workspaceId: z.string().trim().optional(), workspaceId: z.string().trim().optional(),
environment: z.string().trim().optional(), environment: z.string().trim().optional(),
@@ -80,6 +88,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const { secrets, imports } = await server.services.secret.getSecretsRaw({ const { secrets, imports } = await server.services.secret.getSecretsRaw({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
environment, environment,
projectId: workspaceId, projectId: workspaceId,
path: secretPath, path: secretPath,
@@ -107,6 +116,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
workspaceId, workspaceId,
environment, environment,
secretPath: req.query.secretPath, secretPath: req.query.secretPath,
channel: getUserAgentType(req.headers["user-agent"]),
...req.auditLogInfo ...req.auditLogInfo
} }
}); });
@@ -118,6 +128,13 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
url: "/raw/:secretName", url: "/raw/:secretName",
method: "GET", method: "GET",
schema: { schema: {
description: "Get a secret by name",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({ params: z.object({
secretName: z.string().trim() secretName: z.string().trim()
}), }),
@@ -156,6 +173,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secret = await server.services.secret.getSecretByNameRaw({ const secret = await server.services.secret.getSecretByNameRaw({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
environment, environment,
projectId: workspaceId, projectId: workspaceId,
path: secretPath, path: secretPath,
@@ -188,6 +206,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
workspaceId, workspaceId,
environment, environment,
secretPath: req.query.secretPath, secretPath: req.query.secretPath,
channel: getUserAgentType(req.headers["user-agent"]),
...req.auditLogInfo ...req.auditLogInfo
} }
}); });
@@ -199,6 +218,13 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
url: "/raw/:secretName", url: "/raw/:secretName",
method: "POST", method: "POST",
schema: { schema: {
description: "Create secret",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({ params: z.object({
secretName: z.string().trim() secretName: z.string().trim()
}), }),
@@ -222,6 +248,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secret = await server.services.secret.createSecretRaw({ const secret = await server.services.secret.createSecretRaw({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
environment: req.body.environment, environment: req.body.environment,
projectId: req.body.workspaceId, projectId: req.body.workspaceId,
secretPath: req.body.secretPath, secretPath: req.body.secretPath,
@@ -255,7 +282,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
workspaceId: req.body.workspaceId, workspaceId: req.body.workspaceId,
environment: req.body.environment, environment: req.body.environment,
secretPath: req.body.secretPath, secretPath: req.body.secretPath,
channel: getUserAgentType(req.headers["user-agent"]),
...req.auditLogInfo ...req.auditLogInfo
} }
}); });
@@ -268,6 +295,13 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
url: "/raw/:secretName", url: "/raw/:secretName",
method: "PATCH", method: "PATCH",
schema: { schema: {
description: "Update secret",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({ params: z.object({
secretName: z.string().trim() secretName: z.string().trim()
}), }),
@@ -290,6 +324,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secret = await server.services.secret.updateSecretRaw({ const secret = await server.services.secret.updateSecretRaw({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
environment: req.body.environment, environment: req.body.environment,
projectId: req.body.workspaceId, projectId: req.body.workspaceId,
secretPath: req.body.secretPath, secretPath: req.body.secretPath,
@@ -322,7 +357,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
workspaceId: req.body.workspaceId, workspaceId: req.body.workspaceId,
environment: req.body.environment, environment: req.body.environment,
secretPath: req.body.secretPath, secretPath: req.body.secretPath,
channel: getUserAgentType(req.headers["user-agent"]),
...req.auditLogInfo ...req.auditLogInfo
} }
}); });
@@ -334,6 +369,13 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
url: "/raw/:secretName", url: "/raw/:secretName",
method: "DELETE", method: "DELETE",
schema: { schema: {
description: "Delete secret",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({ params: z.object({
secretName: z.string().trim() secretName: z.string().trim()
}), }),
@@ -354,6 +396,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secret = await server.services.secret.deleteSecretRaw({ const secret = await server.services.secret.deleteSecretRaw({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
environment: req.body.environment, environment: req.body.environment,
projectId: req.body.workspaceId, projectId: req.body.workspaceId,
secretPath: req.body.secretPath, secretPath: req.body.secretPath,
@@ -384,7 +427,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
workspaceId: req.body.workspaceId, workspaceId: req.body.workspaceId,
environment: req.body.environment, environment: req.body.environment,
secretPath: req.body.secretPath, secretPath: req.body.secretPath,
channel: getUserAgentType(req.headers["user-agent"]),
...req.auditLogInfo ...req.auditLogInfo
} }
}); });
@@ -448,6 +491,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const { secrets, imports } = await server.services.secret.getSecrets({ const { secrets, imports } = await server.services.secret.getSecrets({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
environment: req.query.environment, environment: req.query.environment,
projectId: req.query.workspaceId, projectId: req.query.workspaceId,
path: req.query.secretPath, path: req.query.secretPath,
@@ -467,18 +511,33 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
} }
}); });
server.services.telemetry.sendPostHogEvents({ // TODO: Move to telemetry plugin
event: PostHogEventTypes.SecretPulled, let shouldRecordK8Event = false;
distinctId: getDistinctId(req), if (req.headers["user-agent"] === "k8-operatoer") {
properties: { const randomNumber = Math.random();
numberOfSecrets: secrets.length, if (randomNumber > 0.95) {
workspaceId: req.query.workspaceId, shouldRecordK8Event = true;
environment: req.query.environment,
secretPath: req.query.secretPath,
...req.auditLogInfo
} }
}); }
const shouldCapture =
req.query.workspaceId !== "650e71fbae3e6c8572f436d4" &&
(req.headers["user-agent"] !== "k8-operator" || shouldRecordK8Event);
const approximateNumberTotalSecrets = secrets.length * 20;
if (shouldCapture) {
server.services.telemetry.sendPostHogEvents({
event: PostHogEventTypes.SecretPulled,
distinctId: getDistinctId(req),
properties: {
numberOfSecrets: shouldRecordK8Event ? approximateNumberTotalSecrets : secrets.length,
workspaceId: req.query.workspaceId,
environment: req.query.environment,
secretPath: req.query.secretPath,
channel: getUserAgentType(req.headers["user-agent"]),
...req.auditLogInfo
}
});
}
return { secrets, imports }; return { secrets, imports };
} }
@@ -518,6 +577,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secret = await server.services.secret.getSecretByName({ const secret = await server.services.secret.getSecretByName({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
environment: req.query.environment, environment: req.query.environment,
projectId: req.query.workspaceId, projectId: req.query.workspaceId,
path: req.query.secretPath, path: req.query.secretPath,
@@ -550,7 +610,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
workspaceId: req.query.workspaceId, workspaceId: req.query.workspaceId,
environment: req.query.environment, environment: req.query.environment,
secretPath: req.query.secretPath, secretPath: req.query.secretPath,
channel: getUserAgentType(req.headers["user-agent"]),
...req.auditLogInfo ...req.auditLogInfo
} }
}); });
@@ -628,6 +688,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({ const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
secretPath, secretPath,
environment, environment,
projectId, projectId,
@@ -670,6 +731,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secret = await server.services.secret.createSecret({ const secret = await server.services.secret.createSecret({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
path: secretPath, path: secretPath,
type, type,
environment: req.body.environment, environment: req.body.environment,
@@ -711,7 +773,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
workspaceId: req.body.workspaceId, workspaceId: req.body.workspaceId,
environment: req.body.environment, environment: req.body.environment,
secretPath: req.body.secretPath, secretPath: req.body.secretPath,
channel: getUserAgentType(req.headers["user-agent"]),
...req.auditLogInfo ...req.auditLogInfo
} }
}); });
@@ -793,6 +855,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({ const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
secretPath, secretPath,
environment, environment,
projectId projectId
@@ -801,6 +864,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({ const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
secretPath, secretPath,
environment, environment,
projectId, projectId,
@@ -845,6 +909,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secret = await server.services.secret.updateSecret({ const secret = await server.services.secret.updateSecret({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
path: secretPath, path: secretPath,
type, type,
environment, environment,
@@ -890,7 +955,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
workspaceId: req.body.workspaceId, workspaceId: req.body.workspaceId,
environment: req.body.environment, environment: req.body.environment,
secretPath: req.body.secretPath, secretPath: req.body.secretPath,
channel: getUserAgentType(req.headers["user-agent"]),
...req.auditLogInfo ...req.auditLogInfo
} }
}); });
@@ -934,6 +999,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({ const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
secretPath, secretPath,
environment, environment,
projectId projectId
@@ -942,6 +1008,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({ const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
secretPath, secretPath,
environment, environment,
projectId, projectId,
@@ -974,6 +1041,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secret = await server.services.secret.deleteSecret({ const secret = await server.services.secret.deleteSecret({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
path: secretPath, path: secretPath,
type, type,
environment, environment,
@@ -1005,7 +1073,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
workspaceId: req.body.workspaceId, workspaceId: req.body.workspaceId,
environment: req.body.environment, environment: req.body.environment,
secretPath: req.body.secretPath, secretPath: req.body.secretPath,
channel: getUserAgentType(req.headers["user-agent"]),
...req.auditLogInfo ...req.auditLogInfo
} }
}); });
@@ -1056,6 +1124,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({ const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
secretPath, secretPath,
environment, environment,
projectId projectId
@@ -1064,6 +1133,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({ const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
secretPath, secretPath,
environment, environment,
projectId, projectId,
@@ -1092,6 +1162,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secrets = await server.services.secret.createManySecret({ const secrets = await server.services.secret.createManySecret({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
path: secretPath, path: secretPath,
environment, environment,
projectId, projectId,
@@ -1123,7 +1194,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
workspaceId: req.body.workspaceId, workspaceId: req.body.workspaceId,
environment: req.body.environment, environment: req.body.environment,
secretPath: req.body.secretPath, secretPath: req.body.secretPath,
channel: getUserAgentType(req.headers["user-agent"]),
...req.auditLogInfo ...req.auditLogInfo
} }
}); });
@@ -1174,6 +1245,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({ const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
secretPath, secretPath,
environment, environment,
projectId projectId
@@ -1182,6 +1254,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({ const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
secretPath, secretPath,
environment, environment,
projectId, projectId,
@@ -1209,6 +1282,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secrets = await server.services.secret.updateManySecret({ const secrets = await server.services.secret.updateManySecret({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
path: secretPath, path: secretPath,
environment, environment,
projectId, projectId,
@@ -1240,7 +1314,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
workspaceId: req.body.workspaceId, workspaceId: req.body.workspaceId,
environment: req.body.environment, environment: req.body.environment,
secretPath: req.body.secretPath, secretPath: req.body.secretPath,
channel: getUserAgentType(req.headers["user-agent"]),
...req.auditLogInfo ...req.auditLogInfo
} }
}); });
@@ -1280,6 +1354,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({ const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
secretPath, secretPath,
environment, environment,
projectId projectId
@@ -1288,6 +1363,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({ const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
secretPath, secretPath,
environment, environment,
projectId, projectId,
@@ -1314,6 +1390,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secrets = await server.services.secret.deleteManySecret({ const secrets = await server.services.secret.deleteManySecret({
actorId: req.permission.id, actorId: req.permission.id,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId,
path: req.body.secretPath, path: req.body.secretPath,
environment, environment,
projectId, projectId,
@@ -1345,7 +1422,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
workspaceId: req.body.workspaceId, workspaceId: req.body.workspaceId,
environment: req.body.environment, environment: req.body.environment,
secretPath: req.body.secretPath, secretPath: req.body.secretPath,
channel: getUserAgentType(req.headers["user-agent"]),
...req.auditLogInfo ...req.auditLogInfo
} }
}); });
+15 -3
View File
@@ -108,7 +108,7 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => {
} }
}); });
await res.setCookie("jid", refreshToken, { void res.setCookie("jid", refreshToken, {
httpOnly: true, httpOnly: true,
path: "/", path: "/",
sameSite: "strict", sameSite: "strict",
@@ -156,10 +156,22 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => {
const { user, accessToken, refreshToken } = await server.services.signup.completeAccountInvite({ const { user, accessToken, refreshToken } = await server.services.signup.completeAccountInvite({
...req.body, ...req.body,
ip: req.realIp, ip: req.realIp,
userAgent userAgent,
authorization: req.headers.authorization as string
}); });
await res.setCookie("jid", refreshToken, { void server.services.telemetry.sendLoopsEvent(user.email, user.firstName || "", user.lastName || "");
void server.services.telemetry.sendPostHogEvents({
event: PostHogEventTypes.UserSignedUp,
distinctId: user.email,
properties: {
email: user.email,
attributionSource: "Team Invite"
}
});
void res.setCookie("jid", refreshToken, {
httpOnly: true, httpOnly: true,
path: "/", path: "/",
sameSite: "strict", sameSite: "strict",
@@ -141,7 +141,7 @@ export const tokenServiceFactory = ({ tokenDAL, userDAL }: TAuthTokenServiceFact
const user = await userDAL.findById(session.userId); const user = await userDAL.findById(session.userId);
if (!user || !user.isAccepted) throw new UnauthorizedError({ name: "Token user not found" }); if (!user || !user.isAccepted) throw new UnauthorizedError({ name: "Token user not found" });
return { user, tokenVersionId: token.tokenVersionId }; return { user, tokenVersionId: token.tokenVersionId, orgId: token.organizationId };
}; };
return { return {
+6
View File
@@ -12,6 +12,12 @@ export const validateProviderAuthToken = (providerToken: string, email: string)
if (decodedToken.authTokenType !== AuthTokenType.PROVIDER_TOKEN) throw new UnauthorizedError(); if (decodedToken.authTokenType !== AuthTokenType.PROVIDER_TOKEN) throw new UnauthorizedError();
if (decodedToken.email !== email) throw new Error("Invalid auth credentials"); if (decodedToken.email !== email) throw new Error("Invalid auth credentials");
if (decodedToken.organizationId) {
return { orgId: decodedToken.organizationId };
}
return {};
}; };
export const validateSignUpAuthorization = (token: string, userId: string, validate = true) => { export const validateSignUpAuthorization = (token: string, userId: string, validate = true) => {
+63 -12
View File
@@ -56,7 +56,7 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
* Private * Private
* Send mfa code via email * Send mfa code via email
* */ * */
const sendUserMfaCode = async (userId: string, email: string) => { const sendUserMfaCode = async ({ userId, email }: { userId: string; email: string }) => {
const code = await tokenService.createTokenForUser({ const code = await tokenService.createTokenForUser({
type: TokenType.TOKEN_EMAIL_MFA, type: TokenType.TOKEN_EMAIL_MFA,
userId userId
@@ -76,7 +76,17 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
* Check user device and send mail if new device * Check user device and send mail if new device
* generate the auth and refresh token. fn shared by mfa verification and login verification with mfa disabled * generate the auth and refresh token. fn shared by mfa verification and login verification with mfa disabled
*/ */
const generateUserTokens = async (user: TUsers, ip: string, userAgent: string) => { const generateUserTokens = async ({
user,
ip,
userAgent,
organizationId
}: {
user: TUsers;
ip: string;
userAgent: string;
organizationId?: string;
}) => {
const cfg = getConfig(); const cfg = getConfig();
await updateUserDeviceSession(user, ip, userAgent); await updateUserDeviceSession(user, ip, userAgent);
const tokenSession = await tokenService.getUserTokenSession({ const tokenSession = await tokenService.getUserTokenSession({
@@ -90,7 +100,8 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
authTokenType: AuthTokenType.ACCESS_TOKEN, authTokenType: AuthTokenType.ACCESS_TOKEN,
userId: user.id, userId: user.id,
tokenVersionId: tokenSession.id, tokenVersionId: tokenSession.id,
accessVersion: tokenSession.accessVersion accessVersion: tokenSession.accessVersion,
organizationId
}, },
cfg.AUTH_SECRET, cfg.AUTH_SECRET,
{ expiresIn: cfg.JWT_AUTH_LIFETIME } { expiresIn: cfg.JWT_AUTH_LIFETIME }
@@ -101,7 +112,8 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
authTokenType: AuthTokenType.REFRESH_TOKEN, authTokenType: AuthTokenType.REFRESH_TOKEN,
userId: user.id, userId: user.id,
tokenVersionId: tokenSession.id, tokenVersionId: tokenSession.id,
refreshVersion: tokenSession.refreshVersion refreshVersion: tokenSession.refreshVersion,
organizationId
}, },
cfg.AUTH_SECRET, cfg.AUTH_SECRET,
{ expiresIn: cfg.JWT_REFRESH_LIFETIME } { expiresIn: cfg.JWT_REFRESH_LIFETIME }
@@ -149,8 +161,14 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
if (!userEnc) throw new Error("Failed to find user"); if (!userEnc) throw new Error("Failed to find user");
const cfg = getConfig(); const cfg = getConfig();
let organizationId;
if (!userEnc.authMethods?.includes(AuthMethod.EMAIL)) { if (!userEnc.authMethods?.includes(AuthMethod.EMAIL)) {
validateProviderAuthToken(providerAuthToken as string, email); const { orgId } = validateProviderAuthToken(providerAuthToken as string, email);
organizationId = orgId;
} else if (providerAuthToken) {
// SAML SSO
const { orgId } = validateProviderAuthToken(providerAuthToken, email);
organizationId = orgId;
} }
if (!userEnc.serverPrivateKey || !userEnc.clientPublicKey) throw new Error("Failed to authenticate. Try again?"); if (!userEnc.serverPrivateKey || !userEnc.clientPublicKey) throw new Error("Failed to authenticate. Try again?");
@@ -169,15 +187,36 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
}); });
// send multi factor auth token if they it enabled // send multi factor auth token if they it enabled
if (userEnc.isMfaEnabled) { if (userEnc.isMfaEnabled) {
const mfaToken = jwt.sign({ authTokenType: AuthTokenType.MFA_TOKEN, userId: userEnc.userId }, cfg.AUTH_SECRET, { const mfaToken = jwt.sign(
expiresIn: cfg.JWT_MFA_LIFETIME {
authTokenType: AuthTokenType.MFA_TOKEN,
userId: userEnc.userId,
organizationId
},
cfg.AUTH_SECRET,
{
expiresIn: cfg.JWT_MFA_LIFETIME
}
);
await sendUserMfaCode({
userId: userEnc.userId,
email: userEnc.email
}); });
await sendUserMfaCode(userEnc.userId, userEnc.email);
return { isMfaEnabled: true, token: mfaToken } as const; return { isMfaEnabled: true, token: mfaToken } as const;
} }
const token = await generateUserTokens({ ...userEnc, id: userEnc.userId }, ip, userAgent); const token = await generateUserTokens({
user: {
...userEnc,
id: userEnc.userId
},
ip,
userAgent,
organizationId
});
return { token, isMfaEnabled: false, user: userEnc } as const; return { token, isMfaEnabled: false, user: userEnc } as const;
}; };
@@ -188,14 +227,17 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
const resendMfaToken = async (userId: string) => { const resendMfaToken = async (userId: string) => {
const user = await userDAL.findById(userId); const user = await userDAL.findById(userId);
if (!user) return; if (!user) return;
await sendUserMfaCode(user.id, user.email); await sendUserMfaCode({
userId: user.id,
email: user.email
});
}; };
/* /*
* Multi factor authentication verification of code * Multi factor authentication verification of code
* Third step of login in which user completes with mfa * Third step of login in which user completes with mfa
* */ * */
const verifyMfaToken = async ({ userId, mfaToken, ip, userAgent }: TVerifyMfaTokenDTO) => { const verifyMfaToken = async ({ userId, mfaToken, ip, userAgent, orgId }: TVerifyMfaTokenDTO) => {
await tokenService.validateTokenForUser({ await tokenService.validateTokenForUser({
type: TokenType.TOKEN_EMAIL_MFA, type: TokenType.TOKEN_EMAIL_MFA,
userId, userId,
@@ -204,7 +246,16 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
const userEnc = await userDAL.findUserEncKeyByUserId(userId); const userEnc = await userDAL.findUserEncKeyByUserId(userId);
if (!userEnc) throw new Error("Failed to authenticate user"); if (!userEnc) throw new Error("Failed to authenticate user");
const token = await generateUserTokens({ ...userEnc, id: userEnc.userId }, ip, userAgent); const token = await generateUserTokens({
user: {
...userEnc,
id: userEnc.userId
},
ip,
userAgent,
organizationId: orgId
});
return { token, user: userEnc }; return { token, user: userEnc };
}; };
/* /*
@@ -19,6 +19,7 @@ export type TVerifyMfaTokenDTO = {
mfaToken: string; mfaToken: string;
ip: string; ip: string;
userAgent: string; userAgent: string;
orgId?: string;
}; };
export type TOauthLoginDTO = { export type TOauthLoginDTO = {
@@ -120,8 +120,10 @@ export const authSignupServiceFactory = ({
throw new Error("Failed to complete account for complete user"); throw new Error("Failed to complete account for complete user");
} }
let organizationId;
if (providerAuthToken) { if (providerAuthToken) {
validateProviderAuthToken(providerAuthToken, user.email); const { orgId } = validateProviderAuthToken(providerAuthToken, user.email);
organizationId = orgId;
} else { } else {
validateSignUpAuthorization(authorization, user.id); validateSignUpAuthorization(authorization, user.id);
} }
@@ -147,11 +149,7 @@ export const authSignupServiceFactory = ({
return { info: us, key: userEncKey }; return { info: us, key: userEncKey };
}); });
const hasSamlEnabled = user?.authMethods?.some((authMethod) => if (!organizationId) {
[AuthMethod.OKTA_SAML, AuthMethod.AZURE_SAML, AuthMethod.JUMPCLOUD_SAML].includes(authMethod as AuthMethod)
);
if (!hasSamlEnabled) {
await orgService.createOrganization(user.id, user.email, organizationName); await orgService.createOrganization(user.id, user.email, organizationName);
} }
@@ -175,7 +173,8 @@ export const authSignupServiceFactory = ({
authTokenType: AuthTokenType.ACCESS_TOKEN, authTokenType: AuthTokenType.ACCESS_TOKEN,
userId: updateduser.info.id, userId: updateduser.info.id,
tokenVersionId: tokenSession.id, tokenVersionId: tokenSession.id,
accessVersion: tokenSession.accessVersion accessVersion: tokenSession.accessVersion,
organizationId
}, },
appCfg.AUTH_SECRET, appCfg.AUTH_SECRET,
{ expiresIn: appCfg.JWT_AUTH_LIFETIME } { expiresIn: appCfg.JWT_AUTH_LIFETIME }
@@ -186,7 +185,8 @@ export const authSignupServiceFactory = ({
authTokenType: AuthTokenType.REFRESH_TOKEN, authTokenType: AuthTokenType.REFRESH_TOKEN,
userId: updateduser.info.id, userId: updateduser.info.id,
tokenVersionId: tokenSession.id, tokenVersionId: tokenSession.id,
refreshVersion: tokenSession.refreshVersion refreshVersion: tokenSession.refreshVersion,
organizationId
}, },
appCfg.AUTH_SECRET, appCfg.AUTH_SECRET,
{ expiresIn: appCfg.JWT_REFRESH_LIFETIME } { expiresIn: appCfg.JWT_REFRESH_LIFETIME }
@@ -212,13 +212,16 @@ export const authSignupServiceFactory = ({
protectedKeyTag, protectedKeyTag,
encryptedPrivateKey, encryptedPrivateKey,
encryptedPrivateKeyIV, encryptedPrivateKeyIV,
encryptedPrivateKeyTag encryptedPrivateKeyTag,
authorization
}: TCompleteAccountInviteDTO) => { }: TCompleteAccountInviteDTO) => {
const user = await userDAL.findUserByEmail(email); const user = await userDAL.findUserByEmail(email);
if (!user || (user && user.isAccepted)) { if (!user || (user && user.isAccepted)) {
throw new Error("Failed to complete account for complete user"); throw new Error("Failed to complete account for complete user");
} }
validateSignUpAuthorization(authorization, user.id);
const [orgMembership] = await orgDAL.findMembership({ const [orgMembership] = await orgDAL.findMembership({
inviteEmail: email, inviteEmail: email,
status: OrgMembershipStatus.Invited status: OrgMembershipStatus.Invited
@@ -34,4 +34,5 @@ export type TCompleteAccountInviteDTO = {
verifier: string; verifier: string;
ip: string; ip: string;
userAgent: string; userAgent: string;
authorization: string;
}; };
+4
View File
@@ -39,11 +39,13 @@ export type AuthModeJwtTokenPayload = {
userId: string; userId: string;
tokenVersionId: string; tokenVersionId: string;
accessVersion: number; accessVersion: number;
organizationId?: string;
}; };
export type AuthModeMfaJwtTokenPayload = { export type AuthModeMfaJwtTokenPayload = {
authTokenType: AuthTokenType.MFA_TOKEN; authTokenType: AuthTokenType.MFA_TOKEN;
userId: string; userId: string;
organizationId?: string;
}; };
export type AuthModeRefreshJwtTokenPayload = { export type AuthModeRefreshJwtTokenPayload = {
@@ -51,11 +53,13 @@ export type AuthModeRefreshJwtTokenPayload = {
userId: string; userId: string;
tokenVersionId: string; tokenVersionId: string;
refreshVersion: number; refreshVersion: number;
organizationId?: string;
}; };
export type AuthModeProviderJwtTokenPayload = { export type AuthModeProviderJwtTokenPayload = {
authTokenType: AuthTokenType.PROVIDER_TOKEN; authTokenType: AuthTokenType.PROVIDER_TOKEN;
email: string; email: string;
organizationId?: string;
}; };
export type AuthModeProviderSignUpTokenPayload = { export type AuthModeProviderSignUpTokenPayload = {
@@ -35,12 +35,12 @@ export const identityAccessTokenServiceFactory = ({
} }
// ttl check // ttl check
if (accessTokenTTL > 0) { if (Number(accessTokenTTL) > 0) {
const currentDate = new Date(); const currentDate = new Date();
if (accessTokenLastRenewedAt) { if (accessTokenLastRenewedAt) {
// access token has been renewed // access token has been renewed
const accessTokenRenewed = new Date(accessTokenLastRenewedAt); const accessTokenRenewed = new Date(accessTokenLastRenewedAt);
const ttlInMilliseconds = accessTokenTTL * 1000; const ttlInMilliseconds = Number(accessTokenTTL) * 1000;
const expirationDate = new Date(accessTokenRenewed.getTime() + ttlInMilliseconds); const expirationDate = new Date(accessTokenRenewed.getTime() + ttlInMilliseconds);
if (currentDate > expirationDate) if (currentDate > expirationDate)
@@ -50,7 +50,7 @@ export const identityAccessTokenServiceFactory = ({
} else { } else {
// access token has never been renewed // access token has never been renewed
const accessTokenCreated = new Date(accessTokenCreatedAt); const accessTokenCreated = new Date(accessTokenCreatedAt);
const ttlInMilliseconds = accessTokenTTL * 1000; const ttlInMilliseconds = Number(accessTokenTTL) * 1000;
const expirationDate = new Date(accessTokenCreated.getTime() + ttlInMilliseconds); const expirationDate = new Date(accessTokenCreated.getTime() + ttlInMilliseconds);
if (currentDate > expirationDate) if (currentDate > expirationDate)
@@ -61,9 +61,9 @@ export const identityAccessTokenServiceFactory = ({
} }
// max ttl checks // max ttl checks
if (accessTokenMaxTTL > 0) { if (Number(accessTokenMaxTTL) > 0) {
const accessTokenCreated = new Date(accessTokenCreatedAt); const accessTokenCreated = new Date(accessTokenCreatedAt);
const ttlInMilliseconds = accessTokenMaxTTL * 1000; const ttlInMilliseconds = Number(accessTokenMaxTTL) * 1000;
const currentDate = new Date(); const currentDate = new Date();
const expirationDate = new Date(accessTokenCreated.getTime() + ttlInMilliseconds); const expirationDate = new Date(accessTokenCreated.getTime() + ttlInMilliseconds);
@@ -72,7 +72,7 @@ export const identityAccessTokenServiceFactory = ({
message: "Failed to renew MI access token due to Max TTL expiration" message: "Failed to renew MI access token due to Max TTL expiration"
}); });
const extendToDate = new Date(currentDate.getTime() + accessTokenTTL); const extendToDate = new Date(currentDate.getTime() + Number(accessTokenTTL));
if (extendToDate > expirationDate) if (extendToDate > expirationDate)
throw new UnauthorizedError({ throw new UnauthorizedError({
message: "Failed to renew MI access token past its Max TTL expiration" message: "Failed to renew MI access token past its Max TTL expiration"
@@ -32,8 +32,15 @@ export const identityProjectServiceFactory = ({
identityOrgMembershipDAL, identityOrgMembershipDAL,
projectDAL projectDAL
}: TIdentityProjectServiceFactoryDep) => { }: TIdentityProjectServiceFactoryDep) => {
const createProjectIdentity = async ({ identityId, actor, actorId, projectId, role }: TCreateProjectIdentityDTO) => { const createProjectIdentity = async ({
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); identityId,
actor,
actorId,
actorOrgId,
projectId,
role
}: TCreateProjectIdentityDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Identity); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Identity);
const existingIdentity = await identityProjectDAL.findOne({ identityId, projectId }); const existingIdentity = await identityProjectDAL.findOne({ identityId, projectId });
@@ -72,8 +79,15 @@ export const identityProjectServiceFactory = ({
return projectIdentity; return projectIdentity;
}; };
const updateProjectIdentity = async ({ projectId, identityId, role, actor, actorId }: TUpdateProjectIdentityDTO) => { const updateProjectIdentity = async ({
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); projectId,
identityId,
role,
actor,
actorId,
actorOrgId
}: TUpdateProjectIdentityDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Identity); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Identity);
const projectIdentity = await identityProjectDAL.findOne({ identityId, projectId }); const projectIdentity = await identityProjectDAL.findOne({ identityId, projectId });
@@ -85,7 +99,8 @@ export const identityProjectServiceFactory = ({
const { permission: identityRolePermission } = await permissionService.getProjectPermission( const { permission: identityRolePermission } = await permissionService.getProjectPermission(
ActorType.IDENTITY, ActorType.IDENTITY,
projectIdentity.identityId, projectIdentity.identityId,
projectIdentity.projectId projectIdentity.projectId,
actorOrgId
); );
const hasRequiredPriviledges = isAtLeastAsPrivileged(permission, identityRolePermission); const hasRequiredPriviledges = isAtLeastAsPrivileged(permission, identityRolePermission);
if (!hasRequiredPriviledges) if (!hasRequiredPriviledges)
@@ -115,7 +130,13 @@ export const identityProjectServiceFactory = ({
return updatedProjectIdentity; return updatedProjectIdentity;
}; };
const deleteProjectIdentity = async ({ identityId, actorId, actor, projectId }: TDeleteProjectIdentityDTO) => { const deleteProjectIdentity = async ({
identityId,
actorId,
actor,
actorOrgId,
projectId
}: TDeleteProjectIdentityDTO) => {
const identityProjectMembership = await identityProjectDAL.findOne({ identityId, projectId }); const identityProjectMembership = await identityProjectDAL.findOne({ identityId, projectId });
if (!identityProjectMembership) if (!identityProjectMembership)
throw new BadRequestError({ message: `Failed to find identity with id ${identityId}` }); throw new BadRequestError({ message: `Failed to find identity with id ${identityId}` });
@@ -123,13 +144,15 @@ export const identityProjectServiceFactory = ({
const { permission } = await permissionService.getProjectPermission( const { permission } = await permissionService.getProjectPermission(
actor, actor,
actorId, actorId,
identityProjectMembership.projectId identityProjectMembership.projectId,
actorOrgId
); );
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Identity); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Identity);
const { permission: identityRolePermission } = await permissionService.getProjectPermission( const { permission: identityRolePermission } = await permissionService.getProjectPermission(
ActorType.IDENTITY, ActorType.IDENTITY,
identityId, identityId,
identityProjectMembership.projectId identityProjectMembership.projectId,
actorOrgId
); );
const hasRequiredPriviledges = isAtLeastAsPrivileged(permission, identityRolePermission); const hasRequiredPriviledges = isAtLeastAsPrivileged(permission, identityRolePermission);
if (!hasRequiredPriviledges) if (!hasRequiredPriviledges)
@@ -139,8 +162,8 @@ export const identityProjectServiceFactory = ({
return deletedIdentity; return deletedIdentity;
}; };
const listProjectIdentities = async ({ projectId, actor, actorId }: TListProjectIdentityDTO) => { const listProjectIdentities = async ({ projectId, actor, actorId, actorOrgId }: TListProjectIdentityDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Identity); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Identity);
const identityMemberhips = await identityProjectDAL.findByProjectId(projectId); const identityMemberhips = await identityProjectDAL.findByProjectId(projectId);
@@ -69,9 +69,9 @@ export const identityUaServiceFactory = ({
if (!validClientSecretInfo) throw new UnauthorizedError(); if (!validClientSecretInfo) throw new UnauthorizedError();
const { clientSecretTTL, clientSecretNumUses, clientSecretNumUsesLimit } = validClientSecretInfo; const { clientSecretTTL, clientSecretNumUses, clientSecretNumUsesLimit } = validClientSecretInfo;
if (clientSecretTTL > 0) { if (Number(clientSecretTTL) > 0) {
const clientSecretCreated = new Date(validClientSecretInfo.createdAt); const clientSecretCreated = new Date(validClientSecretInfo.createdAt);
const ttlInMilliseconds = clientSecretTTL * 1000; const ttlInMilliseconds = Number(clientSecretTTL) * 1000;
const currentDate = new Date(); const currentDate = new Date();
const expirationTime = new Date(clientSecretCreated.getTime() + ttlInMilliseconds); const expirationTime = new Date(clientSecretCreated.getTime() + ttlInMilliseconds);
@@ -124,9 +124,13 @@ export const identityUaServiceFactory = ({
} as TIdentityAccessTokenJwtPayload, } as TIdentityAccessTokenJwtPayload,
appCfg.AUTH_SECRET, appCfg.AUTH_SECRET,
{ {
expiresIn: identityAccessToken.accessTokenMaxTTL === 0 ? undefined : identityAccessToken.accessTokenMaxTTL expiresIn:
Number(identityAccessToken.accessTokenMaxTTL) === 0
? undefined
: Number(identityAccessToken.accessTokenMaxTTL)
} }
); );
return { accessToken, identityUa, validClientSecretInfo, identityAccessToken }; return { accessToken, identityUa, validClientSecretInfo, identityAccessToken };
}; };
@@ -138,7 +142,8 @@ export const identityUaServiceFactory = ({
accessTokenTrustedIps, accessTokenTrustedIps,
clientSecretTrustedIps, clientSecretTrustedIps,
actorId, actorId,
actor actor,
actorOrgId
}: TAttachUaDTO) => { }: TAttachUaDTO) => {
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId }); const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" }); if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" });
@@ -151,7 +156,12 @@ export const identityUaServiceFactory = ({
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" }); throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
} }
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId); const { permission } = await permissionService.getOrgPermission(
actor,
actorId,
identityMembershipOrg.orgId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity);
const plan = await licenseService.getPlan(identityMembershipOrg.orgId); const plan = await licenseService.getPlan(identityMembershipOrg.orgId);
@@ -221,7 +231,8 @@ export const identityUaServiceFactory = ({
accessTokenTrustedIps, accessTokenTrustedIps,
clientSecretTrustedIps, clientSecretTrustedIps,
actorId, actorId,
actor actor,
actorOrgId
}: TUpdateUaDTO) => { }: TUpdateUaDTO) => {
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId }); const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" }); if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" });
@@ -239,7 +250,12 @@ export const identityUaServiceFactory = ({
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" }); throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
} }
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId); const { permission } = await permissionService.getOrgPermission(
actor,
actorId,
identityMembershipOrg.orgId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Identity); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Identity);
const plan = await licenseService.getPlan(identityMembershipOrg.orgId); const plan = await licenseService.getPlan(identityMembershipOrg.orgId);
@@ -290,7 +306,7 @@ export const identityUaServiceFactory = ({
return { ...updatedUaAuth, orgId: identityMembershipOrg.orgId }; return { ...updatedUaAuth, orgId: identityMembershipOrg.orgId };
}; };
const getIdentityUa = async ({ identityId, actorId, actor }: TGetUaDTO) => { const getIdentityUa = async ({ identityId, actorId, actor, actorOrgId }: TGetUaDTO) => {
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId }); const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" }); if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" });
if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.Univeral) if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.Univeral)
@@ -300,7 +316,12 @@ export const identityUaServiceFactory = ({
const uaIdentityAuth = await identityUaDAL.findOne({ identityId }); const uaIdentityAuth = await identityUaDAL.findOne({ identityId });
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId); const { permission } = await permissionService.getOrgPermission(
actor,
actorId,
identityMembershipOrg.orgId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Identity); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Identity);
return { ...uaIdentityAuth, orgId: identityMembershipOrg.orgId }; return { ...uaIdentityAuth, orgId: identityMembershipOrg.orgId };
}; };
@@ -308,6 +329,7 @@ export const identityUaServiceFactory = ({
const createUaClientSecret = async ({ const createUaClientSecret = async ({
actor, actor,
actorId, actorId,
actorOrgId,
identityId, identityId,
ttl, ttl,
description, description,
@@ -319,13 +341,19 @@ export const identityUaServiceFactory = ({
throw new BadRequestError({ throw new BadRequestError({
message: "The identity does not have universal auth" message: "The identity does not have universal auth"
}); });
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId); const { permission } = await permissionService.getOrgPermission(
actor,
actorId,
identityMembershipOrg.orgId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity);
const { permission: rolePermission } = await permissionService.getOrgPermission( const { permission: rolePermission } = await permissionService.getOrgPermission(
ActorType.IDENTITY, ActorType.IDENTITY,
identityMembershipOrg.identityId, identityMembershipOrg.identityId,
identityMembershipOrg.orgId identityMembershipOrg.orgId,
actorOrgId
); );
const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission); const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission);
if (!hasPriviledge) if (!hasPriviledge)
@@ -358,20 +386,26 @@ export const identityUaServiceFactory = ({
}; };
}; };
const getUaClientSecrets = async ({ actor, actorId, identityId }: TGetUaClientSecretsDTO) => { const getUaClientSecrets = async ({ actor, actorId, actorOrgId, identityId }: TGetUaClientSecretsDTO) => {
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId }); const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" }); if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" });
if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.Univeral) if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.Univeral)
throw new BadRequestError({ throw new BadRequestError({
message: "The identity does not have universal auth" message: "The identity does not have universal auth"
}); });
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId); const { permission } = await permissionService.getOrgPermission(
actor,
actorId,
identityMembershipOrg.orgId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Identity); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Identity);
const { permission: rolePermission } = await permissionService.getOrgPermission( const { permission: rolePermission } = await permissionService.getOrgPermission(
ActorType.IDENTITY, ActorType.IDENTITY,
identityMembershipOrg.identityId, identityMembershipOrg.identityId,
identityMembershipOrg.orgId identityMembershipOrg.orgId,
actorOrgId
); );
const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission); const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission);
if (!hasPriviledge) if (!hasPriviledge)
@@ -390,20 +424,32 @@ export const identityUaServiceFactory = ({
return { clientSecrets, orgId: identityMembershipOrg.orgId }; return { clientSecrets, orgId: identityMembershipOrg.orgId };
}; };
const revokeUaClientSecret = async ({ identityId, actorId, actor, clientSecretId }: TRevokeUaClientSecretDTO) => { const revokeUaClientSecret = async ({
identityId,
actorId,
actor,
actorOrgId,
clientSecretId
}: TRevokeUaClientSecretDTO) => {
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId }); const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" }); if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" });
if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.Univeral) if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.Univeral)
throw new BadRequestError({ throw new BadRequestError({
message: "The identity does not have universal auth" message: "The identity does not have universal auth"
}); });
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId); const { permission } = await permissionService.getOrgPermission(
actor,
actorId,
identityMembershipOrg.orgId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Identity); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Identity);
const { permission: rolePermission } = await permissionService.getOrgPermission( const { permission: rolePermission } = await permissionService.getOrgPermission(
ActorType.IDENTITY, ActorType.IDENTITY,
identityMembershipOrg.identityId, identityMembershipOrg.identityId,
identityMembershipOrg.orgId identityMembershipOrg.orgId,
actorOrgId
); );
const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission); const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission);
if (!hasPriviledge) if (!hasPriviledge)
@@ -25,8 +25,8 @@ export const identityServiceFactory = ({
identityOrgMembershipDAL, identityOrgMembershipDAL,
permissionService permissionService
}: TIdentityServiceFactoryDep) => { }: TIdentityServiceFactoryDep) => {
const createIdentity = async ({ name, role, actor, orgId, actorId }: TCreateIdentityDTO) => { const createIdentity = async ({ name, role, actor, orgId, actorId, actorOrgId }: TCreateIdentityDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity);
const { permission: rolePermission, role: customRole } = await permissionService.getOrgPermissionByRole( const { permission: rolePermission, role: customRole } = await permissionService.getOrgPermissionByRole(
@@ -54,17 +54,23 @@ export const identityServiceFactory = ({
return identity; return identity;
}; };
const updateIdentity = async ({ id, role, name, actor, actorId }: TUpdateIdentityDTO) => { const updateIdentity = async ({ id, role, name, actor, actorId, actorOrgId }: TUpdateIdentityDTO) => {
const identityOrgMembership = await identityOrgMembershipDAL.findOne({ identityId: id }); const identityOrgMembership = await identityOrgMembershipDAL.findOne({ identityId: id });
if (!identityOrgMembership) throw new BadRequestError({ message: `Failed to find identity with id ${id}` }); if (!identityOrgMembership) throw new BadRequestError({ message: `Failed to find identity with id ${id}` });
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityOrgMembership.orgId); const { permission } = await permissionService.getOrgPermission(
actor,
actorId,
identityOrgMembership.orgId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Identity); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Identity);
const { permission: identityRolePermission } = await permissionService.getOrgPermission( const { permission: identityRolePermission } = await permissionService.getOrgPermission(
ActorType.IDENTITY, ActorType.IDENTITY,
id, id,
identityOrgMembership.orgId identityOrgMembership.orgId,
actorOrgId
); );
const hasRequiredPriviledges = isAtLeastAsPrivileged(permission, identityRolePermission); const hasRequiredPriviledges = isAtLeastAsPrivileged(permission, identityRolePermission);
if (!hasRequiredPriviledges) if (!hasRequiredPriviledges)
@@ -102,11 +108,16 @@ export const identityServiceFactory = ({
return { ...identity, orgId: identityOrgMembership.orgId }; return { ...identity, orgId: identityOrgMembership.orgId };
}; };
const deleteIdentity = async ({ actorId, actor, id }: TDeleteIdentityDTO) => { const deleteIdentity = async ({ actorId, actor, actorOrgId, id }: TDeleteIdentityDTO) => {
const identityOrgMembership = await identityOrgMembershipDAL.findOne({ identityId: id }); const identityOrgMembership = await identityOrgMembershipDAL.findOne({ identityId: id });
if (!identityOrgMembership) throw new BadRequestError({ message: `Failed to find identity with id ${id}` }); if (!identityOrgMembership) throw new BadRequestError({ message: `Failed to find identity with id ${id}` });
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityOrgMembership.orgId); const { permission } = await permissionService.getOrgPermission(
actor,
actorId,
identityOrgMembership.orgId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Identity); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Identity);
const { permission: identityRolePermission } = await permissionService.getOrgPermission( const { permission: identityRolePermission } = await permissionService.getOrgPermission(
ActorType.IDENTITY, ActorType.IDENTITY,
@@ -121,8 +132,8 @@ export const identityServiceFactory = ({
return { ...deletedIdentity, orgId: identityOrgMembership.orgId }; return { ...deletedIdentity, orgId: identityOrgMembership.orgId };
}; };
const listOrgIdentities = async ({ orgId, actor, actorId }: TOrgPermission) => { const listOrgIdentities = async ({ orgId, actor, actorId, actorOrgId }: TOrgPermission) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId); const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Identity); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Identity);
const identityMemberhips = await identityOrgMembershipDAL.findByOrgId(orgId); const identityMemberhips = await identityOrgMembershipDAL.findByOrgId(orgId);
@@ -59,27 +59,40 @@ export const integrationAuthServiceFactory = ({
projectBotDAL, projectBotDAL,
projectBotService projectBotService
}: TIntegrationAuthServiceFactoryDep) => { }: TIntegrationAuthServiceFactoryDep) => {
const listIntegrationAuthByProjectId = async ({ actorId, actor, projectId }: TProjectPermission) => { const listIntegrationAuthByProjectId = async ({ actorId, actor, actorOrgId, projectId }: TProjectPermission) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const authorizations = await integrationAuthDAL.find({ projectId }); const authorizations = await integrationAuthDAL.find({ projectId });
return authorizations; return authorizations;
}; };
const getIntegrationAuth = async ({ actor, id, actorId }: TGetIntegrationAuthDTO) => { const getIntegrationAuth = async ({ actor, id, actorId, actorOrgId }: TGetIntegrationAuthDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id); const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
return integrationAuth; return integrationAuth;
}; };
const oauthExchange = async ({ projectId, actorId, actor, integration, url, code }: TOauthExchangeDTO) => { const oauthExchange = async ({
projectId,
actorId,
actor,
actorOrgId,
integration,
url,
code
}: TOauthExchangeDTO) => {
if (!Object.values(Integrations).includes(integration as Integrations)) if (!Object.values(Integrations).includes(integration as Integrations))
throw new BadRequestError({ message: "Invalid integration" }); throw new BadRequestError({ message: "Invalid integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations);
const bot = await projectBotDAL.findOne({ isActive: true, projectId }); const bot = await projectBotDAL.findOne({ isActive: true, projectId });
@@ -134,6 +147,7 @@ export const integrationAuthServiceFactory = ({
integration, integration,
url, url,
actor, actor,
actorOrgId,
accessId, accessId,
namespace, namespace,
accessToken accessToken
@@ -141,7 +155,7 @@ export const integrationAuthServiceFactory = ({
if (!Object.values(Integrations).includes(integration as Integrations)) if (!Object.values(Integrations).includes(integration as Integrations))
throw new BadRequestError({ message: "Invalid integration" }); throw new BadRequestError({ message: "Invalid integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations);
const bot = await projectBotDAL.findOne({ isActive: true, projectId }); const bot = await projectBotDAL.findOne({ isActive: true, projectId });
@@ -254,11 +268,23 @@ export const integrationAuthServiceFactory = ({
return { accessId, accessToken }; return { accessId, accessToken };
}; };
const getIntegrationApps = async ({ actor, actorId, teamId, id, workspaceSlug }: TIntegrationAuthAppsDTO) => { const getIntegrationApps = async ({
actor,
actorId,
actorOrgId,
teamId,
id,
workspaceSlug
}: TIntegrationAuthAppsDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id); const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -274,11 +300,16 @@ export const integrationAuthServiceFactory = ({
return apps; return apps;
}; };
const getIntegrationAuthTeams = async ({ actor, actorId, id }: TIntegrationAuthTeamsDTO) => { const getIntegrationAuthTeams = async ({ actor, actorId, actorOrgId, id }: TIntegrationAuthTeamsDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id); const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -291,11 +322,16 @@ export const integrationAuthServiceFactory = ({
return teams; return teams;
}; };
const getVercelBranches = async ({ appId, id, actor, actorId }: TIntegrationAuthVercelBranchesDTO) => { const getVercelBranches = async ({ appId, id, actor, actorId, actorOrgId }: TIntegrationAuthVercelBranchesDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id); const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -319,11 +355,16 @@ export const integrationAuthServiceFactory = ({
return []; return [];
}; };
const getChecklyGroups = async ({ actorId, actor, id, accountId }: TIntegrationAuthChecklyGroupsDTO) => { const getChecklyGroups = async ({ actorId, actor, actorOrgId, id, accountId }: TIntegrationAuthChecklyGroupsDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id); const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -340,11 +381,16 @@ export const integrationAuthServiceFactory = ({
return []; return [];
}; };
const getQoveryOrgs = async ({ actorId, actor, id }: TIntegrationAuthQoveryOrgsDTO) => { const getQoveryOrgs = async ({ actorId, actor, actorOrgId, id }: TIntegrationAuthQoveryOrgsDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id); const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -361,11 +407,16 @@ export const integrationAuthServiceFactory = ({
return data.results.map(({ name, id: orgId }) => ({ name, orgId })); return data.results.map(({ name, id: orgId }) => ({ name, orgId }));
}; };
const getQoveryProjects = async ({ actorId, actor, id, orgId }: TIntegrationAuthQoveryProjectDTO) => { const getQoveryProjects = async ({ actorId, actor, actorOrgId, id, orgId }: TIntegrationAuthQoveryProjectDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id); const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -384,11 +435,22 @@ export const integrationAuthServiceFactory = ({
return []; return [];
}; };
const getQoveryEnvs = async ({ projectId, id, actor, actorId }: TIntegrationAuthQoveryEnvironmentsDTO) => { const getQoveryEnvs = async ({
projectId,
id,
actor,
actorId,
actorOrgId
}: TIntegrationAuthQoveryEnvironmentsDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id); const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -412,11 +474,16 @@ export const integrationAuthServiceFactory = ({
return []; return [];
}; };
const getQoveryApps = async ({ id, actor, actorId, environmentId }: TIntegrationAuthQoveryScopesDTO) => { const getQoveryApps = async ({ id, actor, actorId, actorOrgId, environmentId }: TIntegrationAuthQoveryScopesDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id); const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -439,11 +506,22 @@ export const integrationAuthServiceFactory = ({
return []; return [];
}; };
const getQoveryContainers = async ({ id, actor, actorId, environmentId }: TIntegrationAuthQoveryScopesDTO) => { const getQoveryContainers = async ({
id,
actor,
actorId,
actorOrgId,
environmentId
}: TIntegrationAuthQoveryScopesDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id); const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -466,11 +544,16 @@ export const integrationAuthServiceFactory = ({
return []; return [];
}; };
const getQoveryJobs = async ({ id, actor, actorId, environmentId }: TIntegrationAuthQoveryScopesDTO) => { const getQoveryJobs = async ({ id, actor, actorId, actorOrgId, environmentId }: TIntegrationAuthQoveryScopesDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id); const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -493,11 +576,16 @@ export const integrationAuthServiceFactory = ({
return []; return [];
}; };
const getRailwayEnvironments = async ({ id, actor, actorId, appId }: TIntegrationAuthRailwayEnvDTO) => { const getRailwayEnvironments = async ({ id, actor, actorId, actorOrgId, appId }: TIntegrationAuthRailwayEnvDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id); const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -547,11 +635,17 @@ export const integrationAuthServiceFactory = ({
} }
return []; return [];
}; };
const getRailwayServices = async ({ id, actor, actorId, appId }: TIntegrationAuthRailwayServicesDTO) => {
const getRailwayServices = async ({ id, actor, actorId, actorOrgId, appId }: TIntegrationAuthRailwayServicesDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id); const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -620,11 +714,16 @@ export const integrationAuthServiceFactory = ({
return []; return [];
}; };
const getBitbucketWorkspaces = async ({ actorId, actor, id }: TIntegrationAuthBitbucketWorkspaceDTO) => { const getBitbucketWorkspaces = async ({ actorId, actor, actorOrgId, id }: TIntegrationAuthBitbucketWorkspaceDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id); const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -658,11 +757,22 @@ export const integrationAuthServiceFactory = ({
return workspaces; return workspaces;
}; };
const getNorthFlankSecretGroups = async ({ id, actor, actorId, appId }: TIntegrationAuthNorthflankSecretGroupDTO) => { const getNorthFlankSecretGroups = async ({
id,
actor,
actorId,
actorOrgId,
appId
}: TIntegrationAuthNorthflankSecretGroupDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id); const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -713,11 +823,22 @@ export const integrationAuthServiceFactory = ({
return secretGroups; return secretGroups;
}; };
const getTeamcityBuildConfigs = async ({ appId, id, actorId, actor }: TGetIntegrationAuthTeamCityBuildConfigDTO) => { const getTeamcityBuildConfigs = async ({
appId,
id,
actorId,
actorOrgId,
actor
}: TGetIntegrationAuthTeamCityBuildConfigDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id); const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId); const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey); const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -742,19 +863,30 @@ export const integrationAuthServiceFactory = ({
return []; return [];
}; };
const deleteIntegrationAuths = async ({ projectId, integration, actor, actorId }: TDeleteIntegrationAuthsDTO) => { const deleteIntegrationAuths = async ({
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); projectId,
integration,
actor,
actorId,
actorOrgId
}: TDeleteIntegrationAuthsDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Integrations);
const integrations = await integrationAuthDAL.delete({ integration, projectId }); const integrations = await integrationAuthDAL.delete({ integration, projectId });
return integrations; return integrations;
}; };
const deleteIntegrationAuthById = async ({ id, actorId, actor }: TDeleteIntegrationAuthByIdDTO) => { const deleteIntegrationAuthById = async ({ id, actorId, actor, actorOrgId }: TDeleteIntegrationAuthByIdDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id); const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" }); if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Integrations);
const delIntegrationAuth = await integrationAuthDAL.transaction(async (tx) => { const delIntegrationAuth = await integrationAuthDAL.transaction(async (tx) => {
@@ -31,6 +31,7 @@ export const integrationServiceFactory = ({
const createIntegration = async ({ const createIntegration = async ({
app, app,
actor, actor,
actorOrgId,
path, path,
appId, appId,
owner, owner,
@@ -50,7 +51,12 @@ export const integrationServiceFactory = ({
const integrationAuth = await integrationAuthDAL.findById(integrationAuthId); const integrationAuth = await integrationAuthDAL.findById(integrationAuthId);
if (!integrationAuth) throw new BadRequestError({ message: "Integration auth not found" }); if (!integrationAuth) throw new BadRequestError({ message: "Integration auth not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId); const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations);
const folder = await folderDAL.findBySecretPath(integrationAuth.projectId, sourceEnvironment, secretPath); const folder = await folderDAL.findBySecretPath(integrationAuth.projectId, sourceEnvironment, secretPath);
@@ -86,6 +92,7 @@ export const integrationServiceFactory = ({
const updateIntegration = async ({ const updateIntegration = async ({
actorId, actorId,
actor, actor,
actorOrgId,
targetEnvironment, targetEnvironment,
app, app,
id, id,
@@ -98,7 +105,12 @@ export const integrationServiceFactory = ({
const integration = await integrationDAL.findById(id); const integration = await integrationDAL.findById(id);
if (!integration) throw new BadRequestError({ message: "Integration auth not found" }); if (!integration) throw new BadRequestError({ message: "Integration auth not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integration.projectId); const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integration.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Integrations);
const folder = await folderDAL.findBySecretPath(integration.projectId, environment, secretPath); const folder = await folderDAL.findBySecretPath(integration.projectId, environment, secretPath);
@@ -117,19 +129,24 @@ export const integrationServiceFactory = ({
return updatedIntegration; return updatedIntegration;
}; };
const deleteIntegration = async ({ actorId, id, actor }: TDeleteIntegrationDTO) => { const deleteIntegration = async ({ actorId, id, actor, actorOrgId }: TDeleteIntegrationDTO) => {
const integration = await integrationDAL.findById(id); const integration = await integrationDAL.findById(id);
if (!integration) throw new BadRequestError({ message: "Integration auth not found" }); if (!integration) throw new BadRequestError({ message: "Integration auth not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integration.projectId); const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integration.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Integrations);
const deletedIntegration = await integrationDAL.deleteById(id); const deletedIntegration = await integrationDAL.deleteById(id);
return { ...integration, ...deletedIntegration }; return { ...integration, ...deletedIntegration };
}; };
const listIntegrationByProject = async ({ actor, actorId, projectId }: TProjectPermission) => { const listIntegrationByProject = async ({ actor, actorId, actorOrgId, projectId }: TProjectPermission) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const integrations = await integrationDAL.findByProjectId(projectId); const integrations = await integrationDAL.findByProjectId(projectId);
+4 -1
View File
@@ -11,11 +11,13 @@ import {
TUserEncryptionKeys TUserEncryptionKeys
} from "@app/db/schemas"; } from "@app/db/schemas";
import { DatabaseError } from "@app/lib/errors"; import { DatabaseError } from "@app/lib/errors";
import { buildFindFilter, selectAllTableCols, TFindFilter, TFindOpt, withTransaction } from "@app/lib/knex"; import { buildFindFilter, ormify, selectAllTableCols, TFindFilter, TFindOpt, withTransaction } from "@app/lib/knex";
export type TOrgDALFactory = ReturnType<typeof orgDALFactory>; export type TOrgDALFactory = ReturnType<typeof orgDALFactory>;
export const orgDALFactory = (db: TDbClient) => { export const orgDALFactory = (db: TDbClient) => {
const orgOrm = ormify(db, TableName.Organization);
const findOrgById = async (orgId: string) => { const findOrgById = async (orgId: string) => {
try { try {
const org = await db(TableName.Organization).where({ id: orgId }).first(); const org = await db(TableName.Organization).where({ id: orgId }).first();
@@ -177,6 +179,7 @@ export const orgDALFactory = (db: TDbClient) => {
}; };
return withTransaction(db, { return withTransaction(db, {
...orgOrm,
findOrgByProjectId, findOrgByProjectId,
findAllOrgMembers, findAllOrgMembers,
findOrgById, findOrgById,

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