mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
feat: added token based communications
This commit is contained in:
@@ -31,7 +31,6 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@octokit/webhooks-types": "^7.3.1",
|
|
||||||
"@types/bcrypt": "^5.0.2",
|
"@types/bcrypt": "^5.0.2",
|
||||||
"@types/jmespath": "^0.15.2",
|
"@types/jmespath": "^0.15.2",
|
||||||
"@types/jsonwebtoken": "^9.0.5",
|
"@types/jsonwebtoken": "^9.0.5",
|
||||||
@@ -80,6 +79,7 @@
|
|||||||
"@node-saml/passport-saml": "^4.0.4",
|
"@node-saml/passport-saml": "^4.0.4",
|
||||||
"@octokit/rest": "^20.0.2",
|
"@octokit/rest": "^20.0.2",
|
||||||
"@ucast/mongo2js": "^1.3.4",
|
"@ucast/mongo2js": "^1.3.4",
|
||||||
|
"@octokit/webhooks-types": "^7.3.1",
|
||||||
"ajv": "^8.12.0",
|
"ajv": "^8.12.0",
|
||||||
"argon2": "^0.31.2",
|
"argon2": "^0.31.2",
|
||||||
"aws-sdk": "^2.1532.0",
|
"aws-sdk": "^2.1532.0",
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ const getZodDefaultValue = (type: unknown, value: string | number | boolean | Ob
|
|||||||
case "uuid":
|
case "uuid":
|
||||||
return;
|
return;
|
||||||
case "character varying": {
|
case "character varying": {
|
||||||
|
if (value === "gen_random_uuid()") return;
|
||||||
if (typeof value === "string" && value.includes("::")) {
|
if (typeof value === "string" && value.includes("::")) {
|
||||||
return `.default(${value.split("::")[0]})`;
|
return `.default(${value.split("::")[0]})`;
|
||||||
}
|
}
|
||||||
@@ -85,7 +86,7 @@ const main = async () => {
|
|||||||
.whereRaw("table_schema = current_schema()")
|
.whereRaw("table_schema = current_schema()")
|
||||||
.select<{ tableName: string }[]>("table_name as tableName")
|
.select<{ tableName: string }[]>("table_name as tableName")
|
||||||
.orderBy("table_name")
|
.orderBy("table_name")
|
||||||
).filter((el) => el.tableName.includes("migration"));
|
).filter((el) => !el.tableName.includes("_migrations"));
|
||||||
|
|
||||||
console.log("Select a table to generate schema");
|
console.log("Select a table to generate schema");
|
||||||
console.table(tables);
|
console.table(tables);
|
||||||
|
|||||||
12
backend-pg/src/@types/fastify.d.ts
vendored
12
backend-pg/src/@types/fastify.d.ts
vendored
@@ -10,12 +10,13 @@ import { TSecretApprovalRequestServiceFactory } from "@app/ee/services/secret-ap
|
|||||||
import { TSecretRotationServiceFactory } from "@app/ee/services/secret-rotation/secret-rotation-service";
|
import { TSecretRotationServiceFactory } from "@app/ee/services/secret-rotation/secret-rotation-service";
|
||||||
import { TSecretScanningServiceFactory } from "@app/ee/services/secret-scanning/secret-scanning-service";
|
import { TSecretScanningServiceFactory } from "@app/ee/services/secret-scanning/secret-scanning-service";
|
||||||
import { TSecretSnapshotServiceFactory } from "@app/ee/services/secret-snapshot/secret-snapshot-service";
|
import { TSecretSnapshotServiceFactory } from "@app/ee/services/secret-snapshot/secret-snapshot-service";
|
||||||
|
import { TAuthMode } from "@app/server/plugins/auth/inject-identity";
|
||||||
import { TApiKeyServiceFactory } from "@app/services/api-key/api-key-service";
|
import { TApiKeyServiceFactory } from "@app/services/api-key/api-key-service";
|
||||||
import { TAuthLoginFactory } from "@app/services/auth/auth-login-service";
|
import { TAuthLoginFactory } from "@app/services/auth/auth-login-service";
|
||||||
import { TAuthPasswordFactory } from "@app/services/auth/auth-password-service";
|
import { TAuthPasswordFactory } from "@app/services/auth/auth-password-service";
|
||||||
import { TAuthSignupFactory } from "@app/services/auth/auth-signup-service";
|
import { TAuthSignupFactory } from "@app/services/auth/auth-signup-service";
|
||||||
import { AuthMode } from "@app/services/auth/auth-signup-type";
|
|
||||||
import { ActorType } from "@app/services/auth/auth-type";
|
import { ActorType } from "@app/services/auth/auth-type";
|
||||||
|
import { TAuthTokenServiceFactory } from "@app/services/auth-token/auth-token-service";
|
||||||
import { TIdentityServiceFactory } from "@app/services/identity/identity-service";
|
import { TIdentityServiceFactory } from "@app/services/identity/identity-service";
|
||||||
import { TIdentityAccessTokenServiceFactory } from "@app/services/identity-access-token/identity-access-token-service";
|
import { TIdentityAccessTokenServiceFactory } from "@app/services/identity-access-token/identity-access-token-service";
|
||||||
import { TIdentityProjectServiceFactory } from "@app/services/identity-project/identity-project-service";
|
import { TIdentityProjectServiceFactory } from "@app/services/identity-project/identity-project-service";
|
||||||
@@ -36,7 +37,6 @@ import { TSecretImportServiceFactory } from "@app/services/secret-import/secret-
|
|||||||
import { TSecretTagServiceFactory } from "@app/services/secret-tag/secret-tag-service";
|
import { TSecretTagServiceFactory } from "@app/services/secret-tag/secret-tag-service";
|
||||||
import { TServiceTokenServiceFactory } from "@app/services/service-token/service-token-service";
|
import { TServiceTokenServiceFactory } from "@app/services/service-token/service-token-service";
|
||||||
import { TSuperAdminServiceFactory } from "@app/services/super-admin/super-admin-service";
|
import { TSuperAdminServiceFactory } from "@app/services/super-admin/super-admin-service";
|
||||||
import { TAuthTokenServiceFactory } from "@app/services/token/token-service";
|
|
||||||
import { TUserDalFactory } from "@app/services/user/user-dal";
|
import { TUserDalFactory } from "@app/services/user/user-dal";
|
||||||
import { TUserServiceFactory } from "@app/services/user/user-service";
|
import { TUserServiceFactory } from "@app/services/user/user-service";
|
||||||
import { TWebhookServiceFactory } from "@app/services/webhook/webhook-service";
|
import { TWebhookServiceFactory } from "@app/services/webhook/webhook-service";
|
||||||
@@ -50,13 +50,7 @@ declare module "fastify" {
|
|||||||
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
|
||||||
auth: {
|
auth: TAuthMode;
|
||||||
authMode: AuthMode.JWT | AuthMode.API_KEY_V2 | AuthMode.API_KEY;
|
|
||||||
actor: ActorType.USER;
|
|
||||||
userId: string;
|
|
||||||
tokenVersionId: string; // the session id of token used
|
|
||||||
user: TUsers;
|
|
||||||
};
|
|
||||||
permission: {
|
permission: {
|
||||||
type: ActorType;
|
type: ActorType;
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
|||||||
export async function up(knex: Knex): Promise<void> {
|
export async function up(knex: Knex): Promise<void> {
|
||||||
if (!(await knex.schema.hasTable(TableName.Project))) {
|
if (!(await knex.schema.hasTable(TableName.Project))) {
|
||||||
await knex.schema.createTable(TableName.Project, (t) => {
|
await knex.schema.createTable(TableName.Project, (t) => {
|
||||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
t.string("id").primary().defaultTo(knex.fn.uuid());
|
||||||
t.string("name").notNullable();
|
t.string("name").notNullable();
|
||||||
t.boolean("autoCapitalization").defaultTo(true);
|
t.boolean("autoCapitalization").defaultTo(true);
|
||||||
t.uuid("orgId").notNullable();
|
t.uuid("orgId").notNullable();
|
||||||
@@ -22,7 +22,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
t.string("name").notNullable();
|
t.string("name").notNullable();
|
||||||
t.string("slug").notNullable();
|
t.string("slug").notNullable();
|
||||||
t.integer("position").notNullable();
|
t.integer("position").notNullable();
|
||||||
t.uuid("projectId").notNullable();
|
t.string("projectId").notNullable();
|
||||||
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
// this will ensure ever env has its position
|
// this will ensure ever env has its position
|
||||||
t.unique(["projectId", "position"], {
|
t.unique(["projectId", "position"], {
|
||||||
@@ -43,7 +43,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
t.uuid("senderId");
|
t.uuid("senderId");
|
||||||
// if sender is deleted just don't do anything to this record
|
// if sender is deleted just don't do anything to this record
|
||||||
t.foreign("senderId").references("id").inTable(TableName.Users).onDelete("SET NULL");
|
t.foreign("senderId").references("id").inTable(TableName.Users).onDelete("SET NULL");
|
||||||
t.uuid("projectId").notNullable();
|
t.string("projectId").notNullable();
|
||||||
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
t.timestamps(true, true, true);
|
t.timestamps(true, true, true);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
t.jsonb("permissions").notNullable();
|
t.jsonb("permissions").notNullable();
|
||||||
// does not need update trigger we will do it manually
|
// does not need update trigger we will do it manually
|
||||||
t.timestamps(true, true, true);
|
t.timestamps(true, true, true);
|
||||||
t.uuid("projectId").notNullable();
|
t.string("projectId").notNullable();
|
||||||
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -26,7 +26,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
t.timestamps(true, true, true);
|
t.timestamps(true, true, true);
|
||||||
t.uuid("userId").notNullable();
|
t.uuid("userId").notNullable();
|
||||||
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||||
t.uuid("projectId").notNullable();
|
t.string("projectId").notNullable();
|
||||||
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
// until role is changed/removed the role should not deleted
|
// until role is changed/removed the role should not deleted
|
||||||
t.uuid("roleId");
|
t.uuid("roleId");
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
t.timestamps(true, true, true);
|
t.timestamps(true, true, true);
|
||||||
t.uuid("createdBy");
|
t.uuid("createdBy");
|
||||||
t.foreign("createdBy").references("id").inTable(TableName.Users).onDelete("SET NULL");
|
t.foreign("createdBy").references("id").inTable(TableName.Users).onDelete("SET NULL");
|
||||||
t.uuid("projectId").notNullable();
|
t.string("projectId").notNullable();
|
||||||
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
t.text("saltTag").notNullable();
|
t.text("saltTag").notNullable();
|
||||||
t.string("algorithm").notNullable().defaultTo(SecretEncryptionAlgo.AES_256_GCM);
|
t.string("algorithm").notNullable().defaultTo(SecretEncryptionAlgo.AES_256_GCM);
|
||||||
t.string("keyEncoding").notNullable().defaultTo(SecretKeyEncoding.UTF8);
|
t.string("keyEncoding").notNullable().defaultTo(SecretKeyEncoding.UTF8);
|
||||||
t.uuid("projectId").notNullable().unique();
|
t.string("projectId").notNullable().unique();
|
||||||
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
t.timestamps(true, true, true);
|
t.timestamps(true, true, true);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
t.text("encryptedProjectKey");
|
t.text("encryptedProjectKey");
|
||||||
t.text("encryptedProjectKeyNonce");
|
t.text("encryptedProjectKeyNonce");
|
||||||
// one to one relationship
|
// one to one relationship
|
||||||
t.uuid("projectId").notNullable().unique();
|
t.string("projectId").notNullable().unique();
|
||||||
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
t.uuid("senderId");
|
t.uuid("senderId");
|
||||||
t.foreign("senderId").references("id").inTable(TableName.Users).onDelete("SET NULL");
|
t.foreign("senderId").references("id").inTable(TableName.Users).onDelete("SET NULL");
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
t.jsonb("metadata");
|
t.jsonb("metadata");
|
||||||
t.string("algorithm").notNullable();
|
t.string("algorithm").notNullable();
|
||||||
t.string("keyEncoding").notNullable();
|
t.string("keyEncoding").notNullable();
|
||||||
t.uuid("projectId").notNullable();
|
t.string("projectId").notNullable();
|
||||||
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
t.timestamps(true, true, true);
|
t.timestamps(true, true, true);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
t.timestamps(true, true, true);
|
t.timestamps(true, true, true);
|
||||||
// user is old one
|
// user is old one
|
||||||
t.string("createdBy").notNullable();
|
t.string("createdBy").notNullable();
|
||||||
t.uuid("projectId").notNullable();
|
t.string("projectId").notNullable();
|
||||||
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
t.string("role").notNullable();
|
t.string("role").notNullable();
|
||||||
t.uuid("roleId");
|
t.uuid("roleId");
|
||||||
t.foreign("roleId").references("id").inTable(TableName.ProjectRoles);
|
t.foreign("roleId").references("id").inTable(TableName.ProjectRoles);
|
||||||
t.uuid("projectId").notNullable();
|
t.string("projectId").notNullable();
|
||||||
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
t.uuid("identityId").notNullable();
|
t.uuid("identityId").notNullable();
|
||||||
t.foreign("identityId").references("id").inTable(TableName.Identity).onDelete("CASCADE");
|
t.foreign("identityId").references("id").inTable(TableName.Identity).onDelete("CASCADE");
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
// no trigger needed as this collection is append only
|
// no trigger needed as this collection is append only
|
||||||
t.uuid("orgId");
|
t.uuid("orgId");
|
||||||
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
t.uuid("projectId");
|
t.string("projectId");
|
||||||
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export const AuditLogsSchema = z.object({
|
|||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
orgId: z.string().uuid().nullable().optional(),
|
orgId: z.string().uuid().nullable().optional(),
|
||||||
projectId: z.string().uuid().nullable().optional(),
|
projectId: z.string().nullable().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TAuditLogs = z.infer<typeof AuditLogsSchema>;
|
export type TAuditLogs = z.infer<typeof AuditLogsSchema>;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const IdentityProjectMembershipsSchema = z.object({
|
|||||||
id: z.string().uuid(),
|
id: z.string().uuid(),
|
||||||
role: z.string(),
|
role: z.string(),
|
||||||
roleId: z.string().uuid().nullable().optional(),
|
roleId: z.string().uuid().nullable().optional(),
|
||||||
projectId: z.string().uuid(),
|
projectId: z.string(),
|
||||||
identityId: z.string().uuid(),
|
identityId: z.string().uuid(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export const IntegrationAuthsSchema = z.object({
|
|||||||
metadata: z.unknown().nullable().optional(),
|
metadata: z.unknown().nullable().optional(),
|
||||||
algorithm: z.string(),
|
algorithm: z.string(),
|
||||||
keyEncoding: z.string(),
|
keyEncoding: z.string(),
|
||||||
projectId: z.string().uuid(),
|
projectId: z.string(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export const ProjectBotsSchema = z.object({
|
|||||||
keyEncoding: z.string(),
|
keyEncoding: z.string(),
|
||||||
encryptedProjectKey: z.string().nullable().optional(),
|
encryptedProjectKey: z.string().nullable().optional(),
|
||||||
encryptedProjectKeyNonce: z.string().nullable().optional(),
|
encryptedProjectKeyNonce: z.string().nullable().optional(),
|
||||||
projectId: z.string().uuid(),
|
projectId: z.string(),
|
||||||
senderId: z.string().uuid().nullable().optional(),
|
senderId: z.string().uuid().nullable().optional(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export const ProjectEnvironmentsSchema = z.object({
|
|||||||
name: z.string(),
|
name: z.string(),
|
||||||
slug: z.string(),
|
slug: z.string(),
|
||||||
position: z.number(),
|
position: z.number(),
|
||||||
projectId: z.string().uuid(),
|
projectId: z.string(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export const ProjectKeysSchema = z.object({
|
|||||||
nonce: z.string(),
|
nonce: z.string(),
|
||||||
receiverId: z.string().uuid(),
|
receiverId: z.string().uuid(),
|
||||||
senderId: z.string().uuid().nullable().optional(),
|
senderId: z.string().uuid().nullable().optional(),
|
||||||
projectId: z.string().uuid(),
|
projectId: z.string(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export const ProjectMembershipsSchema = z.object({
|
|||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
userId: z.string().uuid(),
|
userId: z.string().uuid(),
|
||||||
projectId: z.string().uuid(),
|
projectId: z.string(),
|
||||||
roleId: z.string().uuid().nullable().optional(),
|
roleId: z.string().uuid().nullable().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export const ProjectRolesSchema = z.object({
|
|||||||
permissions: z.unknown(),
|
permissions: z.unknown(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
projectId: z.string().uuid(),
|
projectId: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TProjectRoles = z.infer<typeof ProjectRolesSchema>;
|
export type TProjectRoles = z.infer<typeof ProjectRolesSchema>;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { z } from "zod";
|
|||||||
import { TImmutableDBKeys } from "./models";
|
import { TImmutableDBKeys } from "./models";
|
||||||
|
|
||||||
export const ProjectsSchema = z.object({
|
export const ProjectsSchema = z.object({
|
||||||
id: z.string().uuid(),
|
id: z.string(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
autoCapitalization: z.boolean().default(true).nullable().optional(),
|
autoCapitalization: z.boolean().default(true).nullable().optional(),
|
||||||
orgId: z.string().uuid(),
|
orgId: z.string().uuid(),
|
||||||
|
|||||||
@@ -23,15 +23,15 @@ export const SaRequestSecretsSchema = z.object({
|
|||||||
secretReminderNote: z.string().nullable().optional(),
|
secretReminderNote: z.string().nullable().optional(),
|
||||||
secretReminderRepeatDays: z.number().nullable().optional(),
|
secretReminderRepeatDays: z.number().nullable().optional(),
|
||||||
skipMultilineEncoding: z.boolean().default(false).nullable().optional(),
|
skipMultilineEncoding: z.boolean().default(false).nullable().optional(),
|
||||||
algorithm: z.string().default("aes-256-gcm"),
|
algorithm: z.string().default('aes-256-gcm'),
|
||||||
keyEncoding: z.string().default("utf8"),
|
keyEncoding: z.string().default('utf8'),
|
||||||
metadata: z.unknown().nullable().optional(),
|
metadata: z.unknown().nullable().optional(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
requestId: z.string().uuid(),
|
requestId: z.string().uuid(),
|
||||||
op: z.string(),
|
op: z.string(),
|
||||||
secretId: z.string().uuid().nullable().optional(),
|
secretId: z.string().uuid().nullable().optional(),
|
||||||
secretVersion: z.string().uuid().nullable().optional()
|
secretVersion: z.string().uuid().nullable().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TSaRequestSecrets = z.infer<typeof SaRequestSecretsSchema>;
|
export type TSaRequestSecrets = z.infer<typeof SaRequestSecretsSchema>;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export const SecretBlindIndexesSchema = z.object({
|
|||||||
saltTag: z.string(),
|
saltTag: z.string(),
|
||||||
algorithm: z.string().default('aes-256-gcm'),
|
algorithm: z.string().default('aes-256-gcm'),
|
||||||
keyEncoding: z.string().default('utf8'),
|
keyEncoding: z.string().default('utf8'),
|
||||||
projectId: z.string().uuid(),
|
projectId: z.string(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export const SecretTagsSchema = z.object({
|
|||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
createdBy: z.string().uuid().nullable().optional(),
|
createdBy: z.string().uuid().nullable().optional(),
|
||||||
projectId: z.string().uuid(),
|
projectId: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TSecretTags = z.infer<typeof SecretTagsSchema>;
|
export type TSecretTags = z.infer<typeof SecretTagsSchema>;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { TImmutableDBKeys } from "./models";
|
|||||||
export const SecretVersionsSchema = z.object({
|
export const SecretVersionsSchema = z.object({
|
||||||
id: z.string().uuid(),
|
id: z.string().uuid(),
|
||||||
version: z.number().default(1),
|
version: z.number().default(1),
|
||||||
type: z.string().default("shared"),
|
type: z.string().default('shared'),
|
||||||
secretBlindIndex: z.string(),
|
secretBlindIndex: z.string(),
|
||||||
secretKeyCiphertext: z.string(),
|
secretKeyCiphertext: z.string(),
|
||||||
secretKeyIV: z.string(),
|
secretKeyIV: z.string(),
|
||||||
@@ -24,15 +24,15 @@ export const SecretVersionsSchema = z.object({
|
|||||||
secretReminderNote: z.string().nullable().optional(),
|
secretReminderNote: z.string().nullable().optional(),
|
||||||
secretReminderRepeatDays: z.number().nullable().optional(),
|
secretReminderRepeatDays: z.number().nullable().optional(),
|
||||||
skipMultilineEncoding: z.boolean().default(false).nullable().optional(),
|
skipMultilineEncoding: z.boolean().default(false).nullable().optional(),
|
||||||
algorithm: z.string().default("aes-256-gcm"),
|
algorithm: z.string().default('aes-256-gcm'),
|
||||||
keyEncoding: z.string().default("utf8"),
|
keyEncoding: z.string().default('utf8'),
|
||||||
metadata: z.unknown().nullable().optional(),
|
metadata: z.unknown().nullable().optional(),
|
||||||
envId: z.string().uuid().nullable().optional(),
|
envId: z.string().uuid().nullable().optional(),
|
||||||
secretId: z.string().uuid(),
|
secretId: z.string().uuid(),
|
||||||
folderId: z.string().uuid(),
|
folderId: z.string().uuid(),
|
||||||
userId: z.string().uuid().nullable().optional(),
|
userId: z.string().uuid().nullable().optional(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date()
|
updatedAt: z.date(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TSecretVersions = z.infer<typeof SecretVersionsSchema>;
|
export type TSecretVersions = z.infer<typeof SecretVersionsSchema>;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { TImmutableDBKeys } from "./models";
|
|||||||
export const SecretsSchema = z.object({
|
export const SecretsSchema = z.object({
|
||||||
id: z.string().uuid(),
|
id: z.string().uuid(),
|
||||||
version: z.number().default(1),
|
version: z.number().default(1),
|
||||||
type: z.string().default("shared"),
|
type: z.string().default('shared'),
|
||||||
secretBlindIndex: z.string(),
|
secretBlindIndex: z.string(),
|
||||||
secretKeyCiphertext: z.string(),
|
secretKeyCiphertext: z.string(),
|
||||||
secretKeyIV: z.string(),
|
secretKeyIV: z.string(),
|
||||||
@@ -24,13 +24,13 @@ export const SecretsSchema = z.object({
|
|||||||
secretReminderNote: z.string().nullable().optional(),
|
secretReminderNote: z.string().nullable().optional(),
|
||||||
secretReminderRepeatDays: z.number().nullable().optional(),
|
secretReminderRepeatDays: z.number().nullable().optional(),
|
||||||
skipMultilineEncoding: z.boolean().default(false).nullable().optional(),
|
skipMultilineEncoding: z.boolean().default(false).nullable().optional(),
|
||||||
algorithm: z.string().default("aes-256-gcm"),
|
algorithm: z.string().default('aes-256-gcm'),
|
||||||
keyEncoding: z.string().default("utf8"),
|
keyEncoding: z.string().default('utf8'),
|
||||||
metadata: z.unknown().nullable().optional(),
|
metadata: z.unknown().nullable().optional(),
|
||||||
userId: z.string().uuid().nullable().optional(),
|
userId: z.string().uuid().nullable().optional(),
|
||||||
folderId: z.string().uuid(),
|
folderId: z.string().uuid(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date()
|
updatedAt: z.date(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TSecrets = z.infer<typeof SecretsSchema>;
|
export type TSecrets = z.infer<typeof SecretsSchema>;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export const ServiceTokensSchema = z.object({
|
|||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
createdBy: z.string(),
|
createdBy: z.string(),
|
||||||
projectId: z.string().uuid(),
|
projectId: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TServiceTokens = z.infer<typeof ServiceTokensSchema>;
|
export type TServiceTokens = z.infer<typeof ServiceTokensSchema>;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const secretSnapshots = await server.services.snapshot.listSnapshots({
|
const secretSnapshots = await server.services.snapshot.listSnapshots({
|
||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
@@ -54,7 +54,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const count = await server.services.snapshot.projectSecretSnapshotCount({
|
const count = await server.services.snapshot.projectSecretSnapshotCount({
|
||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
@@ -107,7 +107,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
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,
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export const registerSnapshotRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const secretSnapshot = await server.services.snapshot.getSnapshotData({
|
const secretSnapshot = await server.services.snapshot.getSnapshotData({
|
||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
@@ -54,7 +54,7 @@ export const registerSnapshotRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const secretSnapshot = await server.services.snapshot.rollbackSnapshot({
|
const secretSnapshot = await server.services.snapshot.rollbackSnapshot({
|
||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
|
|||||||
6
backend-pg/src/ee/services/license/license-dal.ts
Normal file
6
backend-pg/src/ee/services/license/license-dal.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { TDbClient } from "@app/db";
|
||||||
|
import { TableName } from "@app/db/schemas";
|
||||||
|
|
||||||
|
export type TLicenseDalFactory = ReturnType<typeof licenseDalFactory>;
|
||||||
|
|
||||||
|
export const licenseDalFactory = (db: TDbClient) => ({ });
|
||||||
34
backend-pg/src/ee/services/license/license-service.ts
Normal file
34
backend-pg/src/ee/services/license/license-service.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
import { getConfig } from "@app/lib/config/env";
|
||||||
|
|
||||||
|
import { TLicenseDalFactory } from "./license-dal";
|
||||||
|
|
||||||
|
type TLicenseServiceFactoryDep = {
|
||||||
|
licenseDal: TLicenseDalFactory;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TLicenseServiceFactory = ReturnType<typeof licenseServiceFactory>;
|
||||||
|
|
||||||
|
export const licenseServiceFactory = ({ licenseDal }: TLicenseServiceFactoryDep) => {
|
||||||
|
const appCfg = getConfig();
|
||||||
|
const licenceApi = axios.create({
|
||||||
|
baseURL: appCfg.LICENCE_SERVER_URL
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateOrgCustomerId = async (orgName: string, email: string) => {
|
||||||
|
const {
|
||||||
|
data: { customerId }
|
||||||
|
} = await licenceApi.post("/api/license-server/v1/customers", { email, name: orgName });
|
||||||
|
return customerId;
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeOrgCustomer = async (customerId: string) => {
|
||||||
|
await licenceApi.delete(`/api/license-server/v1/customers/${customerId}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
generateOrgCustomerId,
|
||||||
|
removeOrgCustomer
|
||||||
|
};
|
||||||
|
};
|
||||||
0
backend-pg/src/ee/services/license/license-types.ts
Normal file
0
backend-pg/src/ee/services/license/license-types.ts
Normal file
@@ -1,12 +1,13 @@
|
|||||||
import { createMongoAbility, MongoAbility, RawRuleOf } from "@casl/ability";
|
import { createMongoAbility, MongoAbility, RawRuleOf } from "@casl/ability";
|
||||||
import { PackRule, unpackRules } from "@casl/ability/extra";
|
import { PackRule, unpackRules } from "@casl/ability/extra";
|
||||||
|
|
||||||
import { OrgMembershipRole, ProjectMembershipRole } from "@app/db/schemas";
|
import { OrgMembershipRole, ProjectMembershipRole, ServiceTokenScopes } from "@app/db/schemas";
|
||||||
import { conditionsMatcher } from "@app/lib/casl";
|
import { conditionsMatcher } from "@app/lib/casl";
|
||||||
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
|
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
|
||||||
import { ActorType } from "@app/services/auth/auth-type";
|
import { ActorType } from "@app/services/auth/auth-type";
|
||||||
import { TOrgRoleDalFactory } from "@app/services/org/org-role-dal";
|
import { TOrgRoleDalFactory } from "@app/services/org/org-role-dal";
|
||||||
import { TProjectRoleDalFactory } from "@app/services/project-role/project-role-dal";
|
import { TProjectRoleDalFactory } from "@app/services/project-role/project-role-dal";
|
||||||
|
import { TServiceTokenDalFactory } from "@app/services/service-token/service-token-dal";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
orgAdminPermissions,
|
orgAdminPermissions,
|
||||||
@@ -16,6 +17,7 @@ import {
|
|||||||
} from "./org-permission";
|
} from "./org-permission";
|
||||||
import { TPermissionDalFactory } from "./permission-dal";
|
import { TPermissionDalFactory } from "./permission-dal";
|
||||||
import {
|
import {
|
||||||
|
buildServiceTokenProjectPermission,
|
||||||
projectAdminPermissions,
|
projectAdminPermissions,
|
||||||
projectMemberPermissions,
|
projectMemberPermissions,
|
||||||
projectNoAccessPermissions,
|
projectNoAccessPermissions,
|
||||||
@@ -25,6 +27,7 @@ import {
|
|||||||
type TPermissionServiceFactoryDep = {
|
type TPermissionServiceFactoryDep = {
|
||||||
orgRoleDal: Pick<TOrgRoleDalFactory, "findOne">;
|
orgRoleDal: Pick<TOrgRoleDalFactory, "findOne">;
|
||||||
projectRoleDal: Pick<TProjectRoleDalFactory, "findOne">;
|
projectRoleDal: Pick<TProjectRoleDalFactory, "findOne">;
|
||||||
|
serviceTokenDal: Pick<TServiceTokenDalFactory, "findById">;
|
||||||
permissionDal: TPermissionDalFactory;
|
permissionDal: TPermissionDalFactory;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -33,7 +36,8 @@ export type TPermissionServiceFactory = ReturnType<typeof permissionServiceFacto
|
|||||||
export const permissionServiceFactory = ({
|
export const permissionServiceFactory = ({
|
||||||
permissionDal,
|
permissionDal,
|
||||||
orgRoleDal,
|
orgRoleDal,
|
||||||
projectRoleDal
|
projectRoleDal,
|
||||||
|
serviceTokenDal
|
||||||
}: TPermissionServiceFactoryDep) => {
|
}: TPermissionServiceFactoryDep) => {
|
||||||
const buildOrgPermission = (role: string, permission?: unknown) => {
|
const buildOrgPermission = (role: string, permission?: unknown) => {
|
||||||
switch (role) {
|
switch (role) {
|
||||||
@@ -157,10 +161,25 @@ export const permissionServiceFactory = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getServiceTokenProjectPermission = async (serviceTokenId: string, projectId: string) => {
|
||||||
|
const serviceToken = await serviceTokenDal.findById(serviceTokenId);
|
||||||
|
if (serviceToken.projectId !== projectId)
|
||||||
|
throw new UnauthorizedError({
|
||||||
|
message: "Failed to find service authorization for given project"
|
||||||
|
});
|
||||||
|
const scopes = ServiceTokenScopes.parse(serviceToken.scopes || []);
|
||||||
|
return {
|
||||||
|
permission: buildServiceTokenProjectPermission(scopes, serviceToken.permissions),
|
||||||
|
member: undefined
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const getProjectPermission = async (type: ActorType, id: string, projectId: string) => {
|
const getProjectPermission = async (type: ActorType, id: string, projectId: string) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ActorType.USER:
|
case ActorType.USER:
|
||||||
return getUserProjectPermission(id, projectId);
|
return getUserProjectPermission(id, projectId);
|
||||||
|
case ActorType.SERVICE:
|
||||||
|
return getServiceTokenProjectPermission(id, projectId);
|
||||||
case ActorType.IDENTITY:
|
case ActorType.IDENTITY:
|
||||||
return getIdentityProjectPermission(id, projectId);
|
return getIdentityProjectPermission(id, projectId);
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -230,6 +230,33 @@ const buildNoAccessProjectPermission = () => {
|
|||||||
return build({ conditionsMatcher });
|
return build({ conditionsMatcher });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const buildServiceTokenProjectPermission = (
|
||||||
|
scopes: Array<{ secretPath: string; environment: string }>,
|
||||||
|
permission: string[]
|
||||||
|
) => {
|
||||||
|
const canWrite = permission.includes("write");
|
||||||
|
const canRead = permission.includes("read");
|
||||||
|
const { can, build } = new AbilityBuilder<MongoAbility<ProjectPermissionSet>>(createMongoAbility);
|
||||||
|
scopes.forEach(({ secretPath, environment }) => {
|
||||||
|
if (canWrite) {
|
||||||
|
can(ProjectPermissionActions.Edit, ProjectPermissionSub.Secrets, { secretPath, environment });
|
||||||
|
can(ProjectPermissionActions.Create, ProjectPermissionSub.Secrets, {
|
||||||
|
secretPath,
|
||||||
|
environment
|
||||||
|
});
|
||||||
|
can(ProjectPermissionActions.Delete, ProjectPermissionSub.Secrets, {
|
||||||
|
secretPath,
|
||||||
|
environment
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (canRead) {
|
||||||
|
can(ProjectPermissionActions.Read, ProjectPermissionSub.Secrets, { secretPath, environment });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return build({ conditionsMatcher });
|
||||||
|
};
|
||||||
|
|
||||||
export const projectNoAccessPermissions = buildNoAccessProjectPermission();
|
export const projectNoAccessPermissions = buildNoAccessProjectPermission();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -81,7 +81,10 @@ const envSchema = z
|
|||||||
SECRET_SCANNING_WEBHOOK_PROXY: zpStr(z.string().optional()),
|
SECRET_SCANNING_WEBHOOK_PROXY: zpStr(z.string().optional()),
|
||||||
SECRET_SCANNING_WEBHOOK_SECRET: zpStr(z.string().optional()),
|
SECRET_SCANNING_WEBHOOK_SECRET: zpStr(z.string().optional()),
|
||||||
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_SERVER_URL: zpStr(z.string().optional()),
|
||||||
|
LICENCE_SERVER_KEY: zpStr(z.string().optional())
|
||||||
})
|
})
|
||||||
.transform((data) => ({
|
.transform((data) => ({
|
||||||
...data,
|
...data,
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ export class DatabaseError extends Error {
|
|||||||
|
|
||||||
error: unknown;
|
error: unknown;
|
||||||
|
|
||||||
constructor({ name, error, message }: { message?: string; name: string; error: unknown }) {
|
constructor({ name, error, message }: { message?: string; name?: string; error: unknown }) {
|
||||||
super(message || "Failed to execute db ops");
|
super(message || "Failed to execute db ops");
|
||||||
this.name = name;
|
this.name = name || "DatabaseError";
|
||||||
this.error = error;
|
this.error = error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,6 +103,11 @@ export const isValidIpOrCidr = (ip: string): boolean => {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TIp = {
|
||||||
|
ipAddress: string;
|
||||||
|
type: IPType;
|
||||||
|
prefix: number;
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* Validates the IP address [ipAddress] against the trusted IPs [trustedIps].
|
* Validates the IP address [ipAddress] against the trusted IPs [trustedIps].
|
||||||
*/
|
*/
|
||||||
@@ -111,11 +116,7 @@ export const checkIPAgainstBlocklist = ({
|
|||||||
trustedIps
|
trustedIps
|
||||||
}: {
|
}: {
|
||||||
ipAddress: string;
|
ipAddress: string;
|
||||||
trustedIps: {
|
trustedIps: TIp[];
|
||||||
ipAddress: string;
|
|
||||||
type: IPType;
|
|
||||||
prefix: number;
|
|
||||||
}[];
|
|
||||||
}) => {
|
}) => {
|
||||||
const blockList = new net.BlockList();
|
const blockList = new net.BlockList();
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,22 @@ export const injectAuditLogInfo = fp(async (server: FastifyZodProvider) => {
|
|||||||
userId: req.auth.userId
|
userId: req.auth.userId
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
} else if (req.auth.actor === ActorType.SERVICE) {
|
||||||
|
payload.actor = {
|
||||||
|
type: ActorType.SERVICE,
|
||||||
|
metadata: {
|
||||||
|
name: req.auth.serviceToken.name,
|
||||||
|
serviceId: req.auth.serviceTokenId
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else if (req.auth.actor === ActorType.IDENTITY) {
|
||||||
|
payload.actor = {
|
||||||
|
type: ActorType.IDENTITY,
|
||||||
|
metadata: {
|
||||||
|
name: req.auth.identityName,
|
||||||
|
identityId: req.auth.identityId
|
||||||
|
}
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
throw new BadRequestError({ message: "Missing logic for other actor" });
|
throw new BadRequestError({ message: "Missing logic for other actor" });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { FastifyRequest } from "fastify";
|
|||||||
import fp from "fastify-plugin";
|
import fp from "fastify-plugin";
|
||||||
import jwt, { JwtPayload } from "jsonwebtoken";
|
import jwt, { JwtPayload } from "jsonwebtoken";
|
||||||
|
|
||||||
|
import { TServiceTokens, TUsers } from "@app/db/schemas";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { UnauthorizedError } from "@app/lib/errors";
|
import { UnauthorizedError } from "@app/lib/errors";
|
||||||
import {
|
import {
|
||||||
@@ -10,6 +11,34 @@ import {
|
|||||||
AuthModeJwtTokenPayload,
|
AuthModeJwtTokenPayload,
|
||||||
AuthTokenType
|
AuthTokenType
|
||||||
} from "@app/services/auth/auth-type";
|
} from "@app/services/auth/auth-type";
|
||||||
|
import { TIdentityAccessTokenJwtPayload } from "@app/services/identity-access-token/identity-access-token-types";
|
||||||
|
|
||||||
|
export type TAuthMode =
|
||||||
|
| {
|
||||||
|
authMode: AuthMode.JWT;
|
||||||
|
actor: ActorType.USER;
|
||||||
|
userId: string;
|
||||||
|
tokenVersionId: string; // the session id of token used
|
||||||
|
user: TUsers;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
authMode: AuthMode.API_KEY;
|
||||||
|
actor: ActorType.USER;
|
||||||
|
userId: string;
|
||||||
|
user: TUsers;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
authMode: AuthMode.SERVICE_TOKEN;
|
||||||
|
serviceToken: TServiceTokens;
|
||||||
|
actor: ActorType.SERVICE;
|
||||||
|
serviceTokenId: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
authMode: AuthMode.IDENTITY_ACCESS_TOKEN;
|
||||||
|
actor: ActorType.IDENTITY;
|
||||||
|
identityId: string;
|
||||||
|
identityName: string;
|
||||||
|
};
|
||||||
|
|
||||||
const extractAuth = async (req: FastifyRequest, jwtSecret: string) => {
|
const extractAuth = async (req: FastifyRequest, jwtSecret: string) => {
|
||||||
const apiKey = req.headers?.["x-api-key"];
|
const apiKey = req.headers?.["x-api-key"];
|
||||||
@@ -24,7 +53,7 @@ const extractAuth = async (req: FastifyRequest, jwtSecret: string) => {
|
|||||||
return {
|
return {
|
||||||
authMode: AuthMode.SERVICE_TOKEN,
|
authMode: AuthMode.SERVICE_TOKEN,
|
||||||
token: authTokenValue,
|
token: authTokenValue,
|
||||||
actor: ActorType.USER
|
actor: ActorType.SERVICE
|
||||||
} as const;
|
} as const;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,58 +66,62 @@ const extractAuth = async (req: FastifyRequest, jwtSecret: string) => {
|
|||||||
actor: ActorType.USER
|
actor: ActorType.USER
|
||||||
} as const;
|
} as const;
|
||||||
case AuthTokenType.API_KEY:
|
case AuthTokenType.API_KEY:
|
||||||
return { authMode: AuthMode.API_KEY_V2, token: decodedToken, actor: ActorType.USER } as const;
|
return { authMode: AuthMode.API_KEY, token: decodedToken, actor: ActorType.USER } as const;
|
||||||
case AuthMode.SERVICE_ACCESS_TOKEN:
|
case AuthTokenType.IDENTITY_ACCESS_TOKEN:
|
||||||
return {
|
return {
|
||||||
authMode: AuthMode.SERVICE_ACCESS_TOKEN,
|
authMode: AuthMode.IDENTITY_ACCESS_TOKEN,
|
||||||
token: decodedToken,
|
token: decodedToken as TIdentityAccessTokenJwtPayload,
|
||||||
actor: ActorType.USER
|
actor: ActorType.IDENTITY
|
||||||
} as const;
|
} as const;
|
||||||
default:
|
default:
|
||||||
return { authMode: null, token: null } as const;
|
return { authMode: null, token: null } as const;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getJwtIdentity = async (server: FastifyZodProvider, token: AuthModeJwtTokenPayload) => {
|
|
||||||
const session = await server.services.authToken.getUserTokenSessionById(
|
|
||||||
token.tokenVersionId,
|
|
||||||
token.userId
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!session) throw new UnauthorizedError({ name: "Session not found" });
|
|
||||||
if (token.accessVersion !== session.accessVersion)
|
|
||||||
throw new UnauthorizedError({ name: "Stale session" });
|
|
||||||
|
|
||||||
const user = await server.store.user.findById(session.userId);
|
|
||||||
if (!user || !user.isAccepted) throw new UnauthorizedError({ name: "Token user not found" });
|
|
||||||
|
|
||||||
return { user, tokenVersionId: token.tokenVersionId };
|
|
||||||
};
|
|
||||||
|
|
||||||
export const injectIdentity = fp(async (server: FastifyZodProvider) => {
|
export const injectIdentity = fp(async (server: FastifyZodProvider) => {
|
||||||
server.decorateRequest("auth", null);
|
server.decorateRequest("auth", null);
|
||||||
server.addHook("onRequest", async (req) => {
|
server.addHook("onRequest", async (req) => {
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
const { authMode, token, actor } = await extractAuth(req, appCfg.JWT_AUTH_SECRET);
|
const { authMode, token, actor } = await extractAuth(req, appCfg.JWT_AUTH_SECRET);
|
||||||
if (!authMode) return;
|
if (!authMode) return;
|
||||||
// TODO(akhilmhdh-pg): fill in rest of auth mode logic
|
|
||||||
switch (authMode) {
|
switch (authMode) {
|
||||||
case AuthMode.JWT: {
|
case AuthMode.JWT: {
|
||||||
const { user, tokenVersionId } = await getJwtIdentity(
|
const { user, tokenVersionId } =
|
||||||
server,
|
await server.services.authToken.fnValidateJwtIdentity(token);
|
||||||
token as AuthModeJwtTokenPayload
|
|
||||||
);
|
|
||||||
req.auth = { authMode: AuthMode.JWT, user, userId: user.id, tokenVersionId, actor };
|
req.auth = { authMode: AuthMode.JWT, user, userId: user.id, tokenVersionId, actor };
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AuthMode.SERVICE_TOKEN:
|
case AuthMode.IDENTITY_ACCESS_TOKEN: {
|
||||||
|
const identity = await server.services.identityAccessToken.fnValidateIdentityAccessToken(
|
||||||
|
token,
|
||||||
|
req.realIp
|
||||||
|
);
|
||||||
|
req.auth = {
|
||||||
|
authMode: AuthMode.IDENTITY_ACCESS_TOKEN,
|
||||||
|
actor,
|
||||||
|
identityId: identity.identityId,
|
||||||
|
identityName: identity.name
|
||||||
|
};
|
||||||
break;
|
break;
|
||||||
case AuthMode.SERVICE_ACCESS_TOKEN:
|
}
|
||||||
|
case AuthMode.SERVICE_TOKEN: {
|
||||||
|
const serviceToken = await server.services.serviceToken.fnValidateServiceToken(
|
||||||
|
token as string
|
||||||
|
);
|
||||||
|
req.auth = {
|
||||||
|
authMode: AuthMode.SERVICE_TOKEN as const,
|
||||||
|
serviceToken,
|
||||||
|
serviceTokenId: serviceToken.id,
|
||||||
|
actor
|
||||||
|
};
|
||||||
break;
|
break;
|
||||||
case AuthMode.API_KEY:
|
}
|
||||||
break;
|
case AuthMode.API_KEY: {
|
||||||
case AuthMode.API_KEY_V2:
|
const user = await server.services.apiKey.fnValidateApiKey(token as string);
|
||||||
|
req.auth = { authMode: AuthMode.API_KEY as const, userId: user.id, actor, user };
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
throw new UnauthorizedError({ name: "Unknown token strategy" });
|
throw new UnauthorizedError({ name: "Unknown token strategy" });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ export const injectPermission = fp(async (server) => {
|
|||||||
|
|
||||||
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 };
|
||||||
|
} else if (req.auth.actor === ActorType.IDENTITY) {
|
||||||
|
req.permission = { type: ActorType.IDENTITY, id: req.auth.identityId };
|
||||||
|
} else if (req.auth.actor === ActorType.SERVICE) {
|
||||||
|
req.permission = { type: ActorType.SERVICE, id: req.auth.serviceTokenId };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -169,7 +169,12 @@ export const registerRoutes = async (
|
|||||||
const gitAppOrgDal = gitAppDalFactory(db);
|
const gitAppOrgDal = gitAppDalFactory(db);
|
||||||
const secretScanningDal = secretScanningDalFactory(db);
|
const secretScanningDal = secretScanningDalFactory(db);
|
||||||
|
|
||||||
const permissionService = permissionServiceFactory({ permissionDal, orgRoleDal, projectRoleDal });
|
const permissionService = permissionServiceFactory({
|
||||||
|
permissionDal,
|
||||||
|
orgRoleDal,
|
||||||
|
projectRoleDal,
|
||||||
|
serviceTokenDal
|
||||||
|
});
|
||||||
const auditLogQueue = auditLogQueueServiceFactory({ auditLogDal, queueService });
|
const auditLogQueue = auditLogQueueServiceFactory({ auditLogDal, queueService });
|
||||||
const auditLogService = auditLogServiceFactory({ auditLogDal, permissionService, auditLogQueue });
|
const auditLogService = auditLogServiceFactory({ auditLogDal, permissionService, auditLogQueue });
|
||||||
const sapService = secretApprovalPolicyServiceFactory({
|
const sapService = secretApprovalPolicyServiceFactory({
|
||||||
@@ -187,7 +192,7 @@ export const registerRoutes = async (
|
|||||||
samlConfigDal
|
samlConfigDal
|
||||||
});
|
});
|
||||||
|
|
||||||
const tokenService = tokenServiceFactory({ tokenDal: authTokenDal });
|
const tokenService = tokenServiceFactory({ tokenDal: authTokenDal, userDal });
|
||||||
const userService = userServiceFactory({ userDal });
|
const userService = userServiceFactory({ userDal });
|
||||||
const loginService = authLoginServiceFactory({ userDal, smtpService, tokenService });
|
const loginService = authLoginServiceFactory({ userDal, smtpService, tokenService });
|
||||||
const passwordService = authPaswordServiceFactory({
|
const passwordService = authPaswordServiceFactory({
|
||||||
@@ -220,7 +225,7 @@ export const registerRoutes = async (
|
|||||||
authService: loginService,
|
authService: loginService,
|
||||||
serverCfgDal: superAdminDal
|
serverCfgDal: superAdminDal
|
||||||
});
|
});
|
||||||
const apiKeyService = apiKeyServiceFactory({ apiKeyDal });
|
const apiKeyService = apiKeyServiceFactory({ apiKeyDal, userDal });
|
||||||
|
|
||||||
const secretScanningQueue = secretScanningQueueFactory({
|
const secretScanningQueue = secretScanningQueueFactory({
|
||||||
userDal,
|
userDal,
|
||||||
@@ -425,7 +430,7 @@ export const registerRoutes = async (
|
|||||||
user: userDal
|
user: userDal
|
||||||
});
|
});
|
||||||
|
|
||||||
await server.register(injectIdentity);
|
await server.register(injectIdentity, { userDal, serviceTokenDal });
|
||||||
await server.register(injectPermission);
|
await server.register(injectPermission);
|
||||||
await server.register(injectAuditLogInfo);
|
await server.register(injectAuditLogInfo);
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ export const registerAuthRoutes = async (server: FastifyZodProvider) => {
|
|||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req, res) => {
|
handler: async (req, res) => {
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
await server.services.login.logout(req.auth.userId, req.auth.tokenVersionId);
|
if (req.auth.authMode === AuthMode.JWT) {
|
||||||
|
await server.services.login.logout(req.auth.userId, req.auth.tokenVersionId);
|
||||||
|
}
|
||||||
res.cookie("jid", "", {
|
res.cookie("jid", "", {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
path: "/",
|
path: "/",
|
||||||
@@ -35,6 +37,20 @@ export const registerAuthRoutes = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/checkAuth",
|
||||||
|
method: "POST",
|
||||||
|
schema: {
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
message: z.literal("Authenticated")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: () => ({ message: "Authenticated" as const })
|
||||||
|
});
|
||||||
|
|
||||||
server.route({
|
server.route({
|
||||||
url: "/token",
|
url: "/token",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const environment = await server.services.projectEnv.createEnvironment({
|
const environment = await server.services.projectEnv.createEnvironment({
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
@@ -74,7 +74,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { environment, old } = await server.services.projectEnv.updateEnvironment({
|
const { environment, old } = await server.services.projectEnv.updateEnvironment({
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
@@ -124,7 +124,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const environment = await server.services.projectEnv.deleteEnvironment({
|
const environment = await server.services.projectEnv.deleteEnvironment({
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ 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";
|
||||||
|
|
||||||
export const registerProjectMembershipRouter = async (server: FastifyZodProvider) => {
|
export const registerProjectMembershipRouter = async (server: FastifyZodProvider) => {
|
||||||
// TODO(akhilmhdh-pg): missing adding multiple user workspace refer v2/membership
|
|
||||||
|
|
||||||
server.route({
|
server.route({
|
||||||
url: "/:workspaceId/memberships",
|
url: "/:workspaceId/memberships",
|
||||||
method: "GET",
|
method: "GET",
|
||||||
@@ -37,7 +35,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const memberships = await server.services.projectMembership.getProjectMemberships({
|
const memberships = await server.services.projectMembership.getProjectMemberships({
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
@@ -72,7 +70,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const data = await server.services.projectMembership.addUsersToProject({
|
const data = await server.services.projectMembership.addUsersToProject({
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
@@ -114,7 +112,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const membership = await server.services.projectMembership.updateProjectMembership({
|
const membership = await server.services.projectMembership.updateProjectMembership({
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
@@ -155,7 +153,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const membership = await server.services.projectMembership.deleteProjectMembership({
|
const membership = await server.services.projectMembership.deleteProjectMembership({
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { sanitizedServiceTokenSchema } from "../v2/service-token-router";
|
|||||||
|
|
||||||
const projectWithEnv = ProjectsSchema.merge(
|
const projectWithEnv = ProjectsSchema.merge(
|
||||||
z.object({
|
z.object({
|
||||||
|
_id: z.string(),
|
||||||
environments: z.object({ name: z.string(), slug: z.string(), id: z.string() }).array()
|
environments: z.object({ name: z.string(), slug: z.string(), id: z.string() }).array()
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,10 +11,12 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
schema: {
|
schema: {
|
||||||
body: z.object({
|
body: z.object({
|
||||||
projectId: z.string().trim(),
|
workspaceId: z.string().trim(),
|
||||||
environment: z.string().trim(),
|
environment: z.string().trim(),
|
||||||
name: z.string().trim(),
|
name: z.string().trim(),
|
||||||
path: z.string().trim().default("/")
|
path: z.string().trim().default("/"),
|
||||||
|
// backward compatiability with cli
|
||||||
|
directory: z.string().trim().default("/")
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
@@ -22,23 +24,31 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([
|
||||||
|
AuthMode.JWT,
|
||||||
|
AuthMode.API_KEY,
|
||||||
|
AuthMode.SERVICE_TOKEN,
|
||||||
|
AuthMode.IDENTITY_ACCESS_TOKEN
|
||||||
|
]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
|
const path = req.body.path || req.body.directory;
|
||||||
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,
|
||||||
...req.body
|
...req.body,
|
||||||
|
projectId: req.body.workspaceId,
|
||||||
|
path
|
||||||
});
|
});
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
projectId: req.body.projectId,
|
projectId: req.body.workspaceId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.CREATE_FOLDER,
|
type: EventType.CREATE_FOLDER,
|
||||||
metadata: {
|
metadata: {
|
||||||
environment: req.body.environment,
|
environment: req.body.environment,
|
||||||
folderId: folder.id,
|
folderId: folder.id,
|
||||||
folderName: folder.name,
|
folderName: folder.name,
|
||||||
folderPath: req.body.path
|
folderPath: path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -51,13 +61,16 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
|
|||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
schema: {
|
schema: {
|
||||||
params: z.object({
|
params: z.object({
|
||||||
|
// old way this was name
|
||||||
folderId: z.string()
|
folderId: z.string()
|
||||||
}),
|
}),
|
||||||
body: z.object({
|
body: z.object({
|
||||||
projectId: z.string().trim(),
|
workspaceId: z.string().trim(),
|
||||||
environment: z.string().trim(),
|
environment: z.string().trim(),
|
||||||
name: z.string().trim(),
|
name: z.string().trim(),
|
||||||
path: z.string().trim().default("/")
|
path: z.string().trim().default("/"),
|
||||||
|
// backward compatiability with cli
|
||||||
|
directory: z.string().trim().default("/")
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
@@ -65,23 +78,31 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([
|
||||||
|
AuthMode.JWT,
|
||||||
|
AuthMode.API_KEY,
|
||||||
|
AuthMode.SERVICE_TOKEN,
|
||||||
|
AuthMode.IDENTITY_ACCESS_TOKEN
|
||||||
|
]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
|
const path = req.body.path || req.body.directory;
|
||||||
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,
|
||||||
...req.body,
|
...req.body,
|
||||||
id: req.params.folderId
|
projectId: req.body.workspaceId,
|
||||||
|
id: req.params.folderId,
|
||||||
|
path
|
||||||
});
|
});
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
projectId: req.body.projectId,
|
projectId: req.body.workspaceId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.UPDATE_FOLDER,
|
type: EventType.UPDATE_FOLDER,
|
||||||
metadata: {
|
metadata: {
|
||||||
environment: req.body.environment,
|
environment: req.body.environment,
|
||||||
folderId: folder.id,
|
folderId: folder.id,
|
||||||
folderPath: req.body.path,
|
folderPath: path,
|
||||||
newFolderName: folder.name,
|
newFolderName: folder.name,
|
||||||
oldFolderName: old.name
|
oldFolderName: old.name
|
||||||
}
|
}
|
||||||
@@ -99,9 +120,11 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
|
|||||||
folderId: z.string()
|
folderId: z.string()
|
||||||
}),
|
}),
|
||||||
body: z.object({
|
body: z.object({
|
||||||
projectId: z.string().trim(),
|
workspaceId: z.string().trim(),
|
||||||
environment: z.string().trim(),
|
environment: z.string().trim(),
|
||||||
path: z.string().trim().default("/")
|
path: z.string().trim().default("/"),
|
||||||
|
// keep this here as cli need directory
|
||||||
|
directory: z.string().trim().default("/")
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
@@ -109,23 +132,31 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([
|
||||||
|
AuthMode.JWT,
|
||||||
|
AuthMode.API_KEY,
|
||||||
|
AuthMode.SERVICE_TOKEN,
|
||||||
|
AuthMode.IDENTITY_ACCESS_TOKEN
|
||||||
|
]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
|
const path = req.body.path || req.body.directory;
|
||||||
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,
|
||||||
...req.body,
|
...req.body,
|
||||||
id: req.params.folderId
|
projectId: req.body.workspaceId,
|
||||||
|
id: req.params.folderId,
|
||||||
|
path
|
||||||
});
|
});
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
projectId: req.body.projectId,
|
projectId: req.body.workspaceId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.DELETE_FOLDER,
|
type: EventType.DELETE_FOLDER,
|
||||||
metadata: {
|
metadata: {
|
||||||
environment: req.body.environment,
|
environment: req.body.environment,
|
||||||
folderId: folder.id,
|
folderId: folder.id,
|
||||||
folderPath: req.body.path,
|
folderPath: path,
|
||||||
folderName: folder.name
|
folderName: folder.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,9 +170,11 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
|
|||||||
method: "GET",
|
method: "GET",
|
||||||
schema: {
|
schema: {
|
||||||
querystring: z.object({
|
querystring: z.object({
|
||||||
projectId: z.string().trim(),
|
workspaceId: z.string().trim(),
|
||||||
environment: z.string().trim(),
|
environment: z.string().trim(),
|
||||||
path: z.string().trim().default("/")
|
path: z.string().trim().default("/"),
|
||||||
|
// backward compatiability with cli
|
||||||
|
directory: z.string().trim().default("/")
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
@@ -149,12 +182,20 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([
|
||||||
|
AuthMode.JWT,
|
||||||
|
AuthMode.API_KEY,
|
||||||
|
AuthMode.SERVICE_TOKEN,
|
||||||
|
AuthMode.IDENTITY_ACCESS_TOKEN
|
||||||
|
]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
|
const path = req.query.path || req.query.directory;
|
||||||
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,
|
||||||
...req.query
|
...req.query,
|
||||||
|
projectId: req.query.workspaceId,
|
||||||
|
path
|
||||||
});
|
});
|
||||||
return { folders };
|
return { folders };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
schema: {
|
schema: {
|
||||||
body: z.object({
|
body: z.object({
|
||||||
projectId: z.string().trim(),
|
workspaceId: z.string().trim(),
|
||||||
environment: z.string().trim(),
|
environment: z.string().trim(),
|
||||||
path: z.string().trim().default("/"),
|
path: z.string().trim().default("/"),
|
||||||
import: z.object({
|
import: z.object({
|
||||||
@@ -30,18 +30,24 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([
|
||||||
|
AuthMode.JWT,
|
||||||
|
AuthMode.API_KEY,
|
||||||
|
AuthMode.SERVICE_TOKEN,
|
||||||
|
AuthMode.IDENTITY_ACCESS_TOKEN
|
||||||
|
]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
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,
|
||||||
...req.body,
|
...req.body,
|
||||||
|
projectId: req.body.workspaceId,
|
||||||
data: req.body.import
|
data: req.body.import
|
||||||
});
|
});
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
projectId: req.body.projectId,
|
projectId: req.body.workspaceId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.CREATE_SECRET_IMPORT,
|
type: EventType.CREATE_SECRET_IMPORT,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -66,7 +72,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
|
|||||||
secretImportId: z.string().trim()
|
secretImportId: z.string().trim()
|
||||||
}),
|
}),
|
||||||
body: z.object({
|
body: z.object({
|
||||||
projectId: z.string().trim(),
|
workspaceId: z.string().trim(),
|
||||||
environment: z.string().trim(),
|
environment: z.string().trim(),
|
||||||
path: z.string().trim().default("/"),
|
path: z.string().trim().default("/"),
|
||||||
import: z.object({
|
import: z.object({
|
||||||
@@ -86,19 +92,25 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([
|
||||||
|
AuthMode.JWT,
|
||||||
|
AuthMode.API_KEY,
|
||||||
|
AuthMode.SERVICE_TOKEN,
|
||||||
|
AuthMode.IDENTITY_ACCESS_TOKEN
|
||||||
|
]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
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,
|
||||||
id: req.params.secretImportId,
|
id: req.params.secretImportId,
|
||||||
...req.body,
|
...req.body,
|
||||||
|
projectId: req.body.workspaceId,
|
||||||
data: req.body.import
|
data: req.body.import
|
||||||
});
|
});
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
projectId: req.body.projectId,
|
projectId: req.body.workspaceId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.UPDATE_SECRET_IMPORT,
|
type: EventType.UPDATE_SECRET_IMPORT,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -123,7 +135,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
|
|||||||
secretImportId: z.string().trim()
|
secretImportId: z.string().trim()
|
||||||
}),
|
}),
|
||||||
body: z.object({
|
body: z.object({
|
||||||
projectId: z.string().trim(),
|
workspaceId: z.string().trim(),
|
||||||
environment: z.string().trim(),
|
environment: z.string().trim(),
|
||||||
path: z.string().trim().default("/")
|
path: z.string().trim().default("/")
|
||||||
}),
|
}),
|
||||||
@@ -138,18 +150,24 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([
|
||||||
|
AuthMode.JWT,
|
||||||
|
AuthMode.API_KEY,
|
||||||
|
AuthMode.SERVICE_TOKEN,
|
||||||
|
AuthMode.IDENTITY_ACCESS_TOKEN
|
||||||
|
]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
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,
|
||||||
id: req.params.secretImportId,
|
id: req.params.secretImportId,
|
||||||
...req.body
|
...req.body,
|
||||||
|
projectId: req.body.workspaceId
|
||||||
});
|
});
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
projectId: req.body.projectId,
|
projectId: req.body.workspaceId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.DELETE_SECRET_IMPORT,
|
type: EventType.DELETE_SECRET_IMPORT,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -171,7 +189,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
|
|||||||
method: "GET",
|
method: "GET",
|
||||||
schema: {
|
schema: {
|
||||||
querystring: z.object({
|
querystring: z.object({
|
||||||
projectId: z.string().trim(),
|
workspaceId: z.string().trim(),
|
||||||
environment: z.string().trim(),
|
environment: z.string().trim(),
|
||||||
path: z.string().trim().default("/")
|
path: z.string().trim().default("/")
|
||||||
}),
|
}),
|
||||||
@@ -188,17 +206,23 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([
|
||||||
|
AuthMode.JWT,
|
||||||
|
AuthMode.API_KEY,
|
||||||
|
AuthMode.SERVICE_TOKEN,
|
||||||
|
AuthMode.IDENTITY_ACCESS_TOKEN
|
||||||
|
]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
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,
|
||||||
...req.query
|
...req.query,
|
||||||
|
projectId: req.query.workspaceId
|
||||||
});
|
});
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
projectId: req.query.projectId,
|
projectId: req.query.workspaceId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.GET_SECRET_IMPORTS,
|
type: EventType.GET_SECRET_IMPORTS,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -217,7 +241,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
|
|||||||
method: "GET",
|
method: "GET",
|
||||||
schema: {
|
schema: {
|
||||||
querystring: z.object({
|
querystring: z.object({
|
||||||
projectId: z.string().trim(),
|
workspaceId: z.string().trim(),
|
||||||
environment: z.string().trim(),
|
environment: z.string().trim(),
|
||||||
path: z.string().trim().default("/")
|
path: z.string().trim().default("/")
|
||||||
}),
|
}),
|
||||||
@@ -238,12 +262,18 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([
|
||||||
|
AuthMode.JWT,
|
||||||
|
AuthMode.API_KEY,
|
||||||
|
AuthMode.SERVICE_TOKEN,
|
||||||
|
AuthMode.IDENTITY_ACCESS_TOKEN
|
||||||
|
]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
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,
|
||||||
...req.query
|
...req.query,
|
||||||
|
projectId: req.query.workspaceId
|
||||||
});
|
});
|
||||||
return { secrets: importedSecrets };
|
return { secrets: importedSecrets };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const users = await server.services.org.findAllOrgMembers(
|
const users = await server.services.org.findAllOrgMembers(
|
||||||
req.auth.userId,
|
req.auth.userId,
|
||||||
@@ -58,7 +58,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const membership = await server.services.org.updateOrgMembership({
|
const membership = await server.services.org.updateOrgMembership({
|
||||||
userId: req.auth.userId,
|
userId: req.auth.userId,
|
||||||
@@ -81,7 +81,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const membership = await server.services.org.deleteOrgMembership({
|
const membership = await server.services.org.deleteOrgMembership({
|
||||||
userId: req.auth.userId,
|
userId: req.auth.userId,
|
||||||
|
|||||||
@@ -42,7 +42,12 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([
|
||||||
|
AuthMode.JWT,
|
||||||
|
AuthMode.API_KEY,
|
||||||
|
AuthMode.SERVICE_TOKEN,
|
||||||
|
AuthMode.IDENTITY_ACCESS_TOKEN
|
||||||
|
]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const secrets = await server.services.secret.getSecrets({
|
const secrets = await server.services.secret.getSecrets({
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
@@ -92,7 +97,12 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([
|
||||||
|
AuthMode.JWT,
|
||||||
|
AuthMode.API_KEY,
|
||||||
|
AuthMode.SERVICE_TOKEN,
|
||||||
|
AuthMode.IDENTITY_ACCESS_TOKEN
|
||||||
|
]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const secret = await server.services.secret.getASecret({
|
const secret = await server.services.secret.getASecret({
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
@@ -157,7 +167,12 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([
|
||||||
|
AuthMode.JWT,
|
||||||
|
AuthMode.API_KEY,
|
||||||
|
AuthMode.SERVICE_TOKEN,
|
||||||
|
AuthMode.IDENTITY_ACCESS_TOKEN
|
||||||
|
]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const {
|
const {
|
||||||
workspaceId: projectId,
|
workspaceId: projectId,
|
||||||
@@ -307,7 +322,12 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([
|
||||||
|
AuthMode.JWT,
|
||||||
|
AuthMode.API_KEY,
|
||||||
|
AuthMode.SERVICE_TOKEN,
|
||||||
|
AuthMode.IDENTITY_ACCESS_TOKEN
|
||||||
|
]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const {
|
const {
|
||||||
secretValueCiphertext,
|
secretValueCiphertext,
|
||||||
@@ -452,7 +472,12 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([
|
||||||
|
AuthMode.JWT,
|
||||||
|
AuthMode.API_KEY,
|
||||||
|
AuthMode.SERVICE_TOKEN,
|
||||||
|
AuthMode.IDENTITY_ACCESS_TOKEN
|
||||||
|
]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { secretPath, type, workspaceId: projectId, secretId, environment } = req.body;
|
const { secretPath, type, workspaceId: projectId, secretId, environment } = req.body;
|
||||||
if (req.body.type !== SecretType.Personal && req.permission.type === ActorType.USER) {
|
if (req.body.type !== SecretType.Personal && req.permission.type === ActorType.USER) {
|
||||||
@@ -564,7 +589,12 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([
|
||||||
|
AuthMode.JWT,
|
||||||
|
AuthMode.API_KEY,
|
||||||
|
AuthMode.SERVICE_TOKEN,
|
||||||
|
AuthMode.IDENTITY_ACCESS_TOKEN
|
||||||
|
]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { environment, workspaceId: projectId, secretPath, secrets: inputSecrets } = req.body;
|
const { environment, workspaceId: projectId, secretPath, secrets: inputSecrets } = req.body;
|
||||||
if (req.permission.type === ActorType.USER) {
|
if (req.permission.type === ActorType.USER) {
|
||||||
@@ -672,7 +702,12 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([
|
||||||
|
AuthMode.JWT,
|
||||||
|
AuthMode.API_KEY,
|
||||||
|
AuthMode.SERVICE_TOKEN,
|
||||||
|
AuthMode.IDENTITY_ACCESS_TOKEN
|
||||||
|
]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { environment, workspaceId: projectId, secretPath, secrets: inputSecrets } = req.body;
|
const { environment, workspaceId: projectId, secretPath, secrets: inputSecrets } = req.body;
|
||||||
if (req.permission.type === ActorType.USER) {
|
if (req.permission.type === ActorType.USER) {
|
||||||
@@ -768,7 +803,12 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
onRequest: verifyAuth([
|
||||||
|
AuthMode.JWT,
|
||||||
|
AuthMode.API_KEY,
|
||||||
|
AuthMode.SERVICE_TOKEN,
|
||||||
|
AuthMode.IDENTITY_ACCESS_TOKEN
|
||||||
|
]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { environment, workspaceId: projectId, secretPath, secrets: inputSecrets } = req.body;
|
const { environment, workspaceId: projectId, secretPath, secrets: inputSecrets } = req.body;
|
||||||
if (req.permission.type === ActorType.USER) {
|
if (req.permission.type === ActorType.USER) {
|
||||||
|
|||||||
@@ -4,19 +4,21 @@ import bcrypt from "bcrypt";
|
|||||||
|
|
||||||
import { TApiKeys } from "@app/db/schemas/api-keys";
|
import { TApiKeys } from "@app/db/schemas/api-keys";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
|
||||||
|
|
||||||
|
import { TUserDalFactory } from "../user/user-dal";
|
||||||
import { TApiKeyDalFactory } from "./api-key-dal";
|
import { TApiKeyDalFactory } from "./api-key-dal";
|
||||||
|
|
||||||
type TApiKeyServiceFactoryDep = {
|
type TApiKeyServiceFactoryDep = {
|
||||||
apiKeyDal: TApiKeyDalFactory;
|
apiKeyDal: TApiKeyDalFactory;
|
||||||
|
userDal: Pick<TUserDalFactory, "findById">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TApiKeyServiceFactory = ReturnType<typeof apiKeyServiceFactory>;
|
export type TApiKeyServiceFactory = ReturnType<typeof apiKeyServiceFactory>;
|
||||||
|
|
||||||
const formatApiKey = ({ secretHash, ...data }: TApiKeys) => data;
|
const formatApiKey = ({ secretHash, ...data }: TApiKeys) => data;
|
||||||
|
|
||||||
export const apiKeyServiceFactory = ({ apiKeyDal }: TApiKeyServiceFactoryDep) => {
|
export const apiKeyServiceFactory = ({ apiKeyDal, userDal }: TApiKeyServiceFactoryDep) => {
|
||||||
const getMyApiKeys = async (userId: string) => {
|
const getMyApiKeys = async (userId: string) => {
|
||||||
const apiKeys = await apiKeyDal.find({ userId });
|
const apiKeys = await apiKeyDal.find({ userId });
|
||||||
return apiKeys.map((key) => formatApiKey(key));
|
return apiKeys.map((key) => formatApiKey(key));
|
||||||
@@ -48,9 +50,27 @@ export const apiKeyServiceFactory = ({ apiKeyDal }: TApiKeyServiceFactoryDep) =>
|
|||||||
return formatApiKey(apiKeyData);
|
return formatApiKey(apiKeyData);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fnValidateApiKey = async (token: string) => {
|
||||||
|
const [, TOKEN_IDENTIFIER, TOKEN_SECRET] = <[string, string, string]>token.split(".", 3);
|
||||||
|
const apiKey = await apiKeyDal.findById(TOKEN_IDENTIFIER);
|
||||||
|
if (!apiKey) throw new UnauthorizedError();
|
||||||
|
|
||||||
|
if (apiKey.expiresAt && new Date(apiKey.expiresAt) < new Date()) {
|
||||||
|
await apiKeyDal.deleteById(apiKey.id);
|
||||||
|
throw new UnauthorizedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
const isMatch = await bcrypt.compare(TOKEN_SECRET, apiKey.secretHash);
|
||||||
|
if (!isMatch) throw new UnauthorizedError();
|
||||||
|
await apiKeyDal.updateById(apiKey.id, { lastUsed: new Date() });
|
||||||
|
const user = await userDal.findById(apiKey.userId);
|
||||||
|
return user;
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getMyApiKeys,
|
getMyApiKeys,
|
||||||
createApiKey,
|
createApiKey,
|
||||||
deleteApiKey
|
deleteApiKey,
|
||||||
|
fnValidateApiKey
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,10 @@ import bcrypt from "bcrypt";
|
|||||||
|
|
||||||
import { TAuthTokens, TAuthTokenSessions } from "@app/db/schemas";
|
import { TAuthTokens, TAuthTokenSessions } from "@app/db/schemas";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
|
import { UnauthorizedError } from "@app/lib/errors";
|
||||||
|
|
||||||
|
import { AuthModeJwtTokenPayload } from "../auth/auth-type";
|
||||||
|
import { TUserDalFactory } from "../user/user-dal";
|
||||||
import { TTokenDalFactory } from "./auth-token-dal";
|
import { TTokenDalFactory } from "./auth-token-dal";
|
||||||
import {
|
import {
|
||||||
TCreateTokenForUserDTO,
|
TCreateTokenForUserDTO,
|
||||||
@@ -15,7 +18,7 @@ import {
|
|||||||
|
|
||||||
type TAuthTokenServiceFactoryDep = {
|
type TAuthTokenServiceFactoryDep = {
|
||||||
tokenDal: TTokenDalFactory;
|
tokenDal: TTokenDalFactory;
|
||||||
// adjust the expiry from env through here
|
userDal: Pick<TUserDalFactory, "findById">;
|
||||||
};
|
};
|
||||||
export type TAuthTokenServiceFactory = ReturnType<typeof tokenServiceFactory>;
|
export type TAuthTokenServiceFactory = ReturnType<typeof tokenServiceFactory>;
|
||||||
|
|
||||||
@@ -56,7 +59,7 @@ export const getTokenConfig = (tokenType: TokenType) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const tokenServiceFactory = ({ tokenDal }: TAuthTokenServiceFactoryDep) => {
|
export const tokenServiceFactory = ({ tokenDal, userDal }: TAuthTokenServiceFactoryDep) => {
|
||||||
const createTokenForUser = async ({ type, userId, orgId }: TCreateTokenForUserDTO) => {
|
const createTokenForUser = async ({ type, userId, orgId }: TCreateTokenForUserDTO) => {
|
||||||
const { token, ...tkCfg } = getTokenConfig(type);
|
const { token, ...tkCfg } = getTokenConfig(type);
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
@@ -122,26 +125,43 @@ export const tokenServiceFactory = ({ tokenDal }: TAuthTokenServiceFactoryDep) =
|
|||||||
return session;
|
return session;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getUserTokenSessionById = async (id: string, userId: string) =>
|
|
||||||
tokenDal.findOneTokenSession({ id, userId });
|
|
||||||
|
|
||||||
const clearTokenSessionById = async (
|
const clearTokenSessionById = async (
|
||||||
userId: string,
|
userId: string,
|
||||||
sessionId: string
|
sessionId: string
|
||||||
): Promise<TAuthTokenSessions | undefined> =>
|
): Promise<TAuthTokenSessions | undefined> =>
|
||||||
tokenDal.incrementTokenSessionVersion(userId, sessionId);
|
tokenDal.incrementTokenSessionVersion(userId, sessionId);
|
||||||
|
|
||||||
|
const getUserTokenSessionById = async (id: string, userId: string) =>
|
||||||
|
tokenDal.findOneTokenSession({ id, userId });
|
||||||
|
|
||||||
const getTokenSessionByUser = async (userId: string) => tokenDal.findTokenSessions({ userId });
|
const getTokenSessionByUser = async (userId: string) => tokenDal.findTokenSessions({ userId });
|
||||||
|
|
||||||
const revokeAllMySessions = async (userId: string) => tokenDal.deleteTokenSession({ userId });
|
const revokeAllMySessions = async (userId: string) => tokenDal.deleteTokenSession({ userId });
|
||||||
|
|
||||||
|
// to parse jwt identity in inject identity plugin
|
||||||
|
const fnValidateJwtIdentity = async (token: AuthModeJwtTokenPayload) => {
|
||||||
|
const session = await tokenDal.findOneTokenSession({
|
||||||
|
id: token.tokenVersionId,
|
||||||
|
userId: token.userId
|
||||||
|
});
|
||||||
|
if (!session) throw new UnauthorizedError({ name: "Session not found" });
|
||||||
|
if (token.accessVersion !== session.accessVersion)
|
||||||
|
throw new UnauthorizedError({ name: "Stale session" });
|
||||||
|
|
||||||
|
const user = await userDal.findById(session.userId);
|
||||||
|
if (!user || !user.isAccepted) throw new UnauthorizedError({ name: "Token user not found" });
|
||||||
|
|
||||||
|
return { user, tokenVersionId: token.tokenVersionId };
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
createTokenForUser,
|
createTokenForUser,
|
||||||
validateTokenForUser,
|
validateTokenForUser,
|
||||||
getUserTokenSession,
|
getUserTokenSession,
|
||||||
clearTokenSessionById,
|
clearTokenSessionById,
|
||||||
getUserTokenSessionById,
|
|
||||||
getTokenSessionByUser,
|
getTokenSessionByUser,
|
||||||
revokeAllMySessions
|
revokeAllMySessions,
|
||||||
|
fnValidateJwtIdentity,
|
||||||
|
getUserTokenSessionById
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,9 +23,7 @@ export enum AuthTokenType {
|
|||||||
export enum AuthMode {
|
export enum AuthMode {
|
||||||
JWT = "jwt",
|
JWT = "jwt",
|
||||||
SERVICE_TOKEN = "serviceToken",
|
SERVICE_TOKEN = "serviceToken",
|
||||||
SERVICE_ACCESS_TOKEN = "serviceAccessToken",
|
|
||||||
API_KEY = "apiKey",
|
API_KEY = "apiKey",
|
||||||
API_KEY_V2 = "apiKeyV2",
|
|
||||||
IDENTITY_ACCESS_TOKEN = "identityAccessToken"
|
IDENTITY_ACCESS_TOKEN = "identityAccessToken"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,45 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName } from "@app/db/schemas";
|
import { TableName,TIdentityAccessTokens } from "@app/db/schemas";
|
||||||
import { ormify } from "@app/lib/knex";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
|
import { ormify, selectAllTableCols } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TIdentityAccessTokenDalFactory = ReturnType<typeof identityAccessTokenDalFactory>;
|
export type TIdentityAccessTokenDalFactory = ReturnType<typeof identityAccessTokenDalFactory>;
|
||||||
|
|
||||||
export const identityAccessTokenDalFactory = (db: TDbClient) => {
|
export const identityAccessTokenDalFactory = (db: TDbClient) => {
|
||||||
const identityAccessTokenOrm = ormify(db, TableName.IdentityAccessToken);
|
const identityAccessTokenOrm = ormify(db, TableName.IdentityAccessToken);
|
||||||
return identityAccessTokenOrm;
|
|
||||||
|
const findOne = async (filter: Partial<TIdentityAccessTokens>, tx?: Knex) => {
|
||||||
|
try {
|
||||||
|
const doc = await (tx || db)(TableName.IdentityAccessToken)
|
||||||
|
.where(filter)
|
||||||
|
.join(
|
||||||
|
TableName.Identity,
|
||||||
|
`${TableName.Identity}.id`,
|
||||||
|
`${TableName.IdentityAccessToken}.identityId`
|
||||||
|
)
|
||||||
|
.leftJoin(
|
||||||
|
TableName.IdentityUaClientSecret,
|
||||||
|
`${TableName.IdentityAccessToken}.identityUAClientSecretId`,
|
||||||
|
`${TableName.IdentityUaClientSecret}.id`
|
||||||
|
)
|
||||||
|
.leftJoin(
|
||||||
|
TableName.IdentityUniversalAuth,
|
||||||
|
`${TableName.IdentityUaClientSecret}.identityUAId`,
|
||||||
|
`${TableName.IdentityUniversalAuth}.id`
|
||||||
|
)
|
||||||
|
.select(selectAllTableCols(TableName.IdentityAccessToken))
|
||||||
|
.select(
|
||||||
|
db.ref("accessTokenTrustedIps").withSchema(TableName.IdentityUniversalAuth),
|
||||||
|
db.ref("name").withSchema(TableName.Identity)
|
||||||
|
)
|
||||||
|
.first();
|
||||||
|
return doc;
|
||||||
|
} catch (error) {
|
||||||
|
throw new DatabaseError({ error, name: "IdAccessTokenFindOne" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return { ...identityAccessTokenOrm, findOne };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
import jwt, { JwtPayload } from "jsonwebtoken";
|
import jwt, { JwtPayload } from "jsonwebtoken";
|
||||||
|
|
||||||
|
import { TableName, TIdentityAccessTokens } from "@app/db/schemas";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { UnauthorizedError } from "@app/lib/errors";
|
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
|
||||||
|
import { checkIPAgainstBlocklist, TIp } from "@app/lib/ip";
|
||||||
|
|
||||||
import { AuthTokenType } from "../auth/auth-type";
|
import { AuthTokenType } from "../auth/auth-type";
|
||||||
import { TIdentityAccessTokenDalFactory } from "./identity-access-token-dal";
|
import { TIdentityAccessTokenDalFactory } from "./identity-access-token-dal";
|
||||||
import { TRenewAccessTokenDTO } from "./identity-access-token-types";
|
import {
|
||||||
|
TIdentityAccessTokenJwtPayload,
|
||||||
|
TRenewAccessTokenDTO
|
||||||
|
} from "./identity-access-token-types";
|
||||||
|
|
||||||
type TIdentityAccessTokenServiceFactoryDep = {
|
type TIdentityAccessTokenServiceFactoryDep = {
|
||||||
identityAccessTokenDal: TIdentityAccessTokenDalFactory;
|
identityAccessTokenDal: TIdentityAccessTokenDalFactory;
|
||||||
@@ -18,25 +23,22 @@ export type TIdentityAccessTokenServiceFactory = ReturnType<
|
|||||||
export const identityAccessTokenServiceFactory = ({
|
export const identityAccessTokenServiceFactory = ({
|
||||||
identityAccessTokenDal
|
identityAccessTokenDal
|
||||||
}: TIdentityAccessTokenServiceFactoryDep) => {
|
}: TIdentityAccessTokenServiceFactoryDep) => {
|
||||||
const renewAccessToken = async ({ accessToken }: TRenewAccessTokenDTO) => {
|
const validateAccessTokenExp = async (identityAccessToken: TIdentityAccessTokens) => {
|
||||||
const appCfg = getConfig();
|
|
||||||
|
|
||||||
const decodedToken = jwt.verify(accessToken, appCfg.JWT_AUTH_SECRET) as JwtPayload;
|
|
||||||
if (decodedToken.authTokenType !== AuthTokenType.IDENTITY_ACCESS_TOKEN)
|
|
||||||
throw new UnauthorizedError();
|
|
||||||
|
|
||||||
const identityAccessToken = await identityAccessTokenDal.findOne({
|
|
||||||
id: decodedToken.identityAccessTokenId,
|
|
||||||
isAccessTokenRevoked: false
|
|
||||||
});
|
|
||||||
if (!identityAccessToken) throw new UnauthorizedError();
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
accessTokenTTL,
|
accessTokenTTL,
|
||||||
|
accessTokenNumUses,
|
||||||
|
accessTokenNumUsesLimit,
|
||||||
accessTokenLastRenewedAt,
|
accessTokenLastRenewedAt,
|
||||||
accessTokenMaxTTL,
|
accessTokenMaxTTL,
|
||||||
createdAt: accessTokenCreatedAt
|
createdAt: accessTokenCreatedAt
|
||||||
} = identityAccessToken;
|
} = identityAccessToken;
|
||||||
|
|
||||||
|
if (accessTokenNumUses > 0 && accessTokenNumUses >= accessTokenNumUsesLimit) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Unable to renew because access token number of uses limit reached"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// ttl check
|
// ttl check
|
||||||
if (accessTokenTTL > 0) {
|
if (accessTokenTTL > 0) {
|
||||||
const currentDate = new Date();
|
const currentDate = new Date();
|
||||||
@@ -81,6 +83,22 @@ export const identityAccessTokenServiceFactory = ({
|
|||||||
message: "Failed to renew MI access token past its Max TTL expiration"
|
message: "Failed to renew MI access token past its Max TTL expiration"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const renewAccessToken = async ({ accessToken }: TRenewAccessTokenDTO) => {
|
||||||
|
const appCfg = getConfig();
|
||||||
|
|
||||||
|
const decodedToken = jwt.verify(accessToken, appCfg.JWT_AUTH_SECRET) as JwtPayload;
|
||||||
|
if (decodedToken.authTokenType !== AuthTokenType.IDENTITY_ACCESS_TOKEN)
|
||||||
|
throw new UnauthorizedError();
|
||||||
|
|
||||||
|
const identityAccessToken = await identityAccessTokenDal.findOne({
|
||||||
|
[`${TableName.IdentityAccessToken}.id` as "id"]: decodedToken.identityAccessTokenId,
|
||||||
|
isAccessTokenRevoked: false
|
||||||
|
});
|
||||||
|
if (!identityAccessToken) throw new UnauthorizedError();
|
||||||
|
|
||||||
|
validateAccessTokenExp(identityAccessToken);
|
||||||
|
|
||||||
const updatedIdentityAccessToken = await identityAccessTokenDal.updateById(
|
const updatedIdentityAccessToken = await identityAccessTokenDal.updateById(
|
||||||
identityAccessToken.id,
|
identityAccessToken.id,
|
||||||
@@ -92,5 +110,26 @@ export const identityAccessTokenServiceFactory = ({
|
|||||||
return { accessToken, identityAccessToken: updatedIdentityAccessToken };
|
return { accessToken, identityAccessToken: updatedIdentityAccessToken };
|
||||||
};
|
};
|
||||||
|
|
||||||
return { renewAccessToken };
|
const fnValidateIdentityAccessToken = async (
|
||||||
|
token: TIdentityAccessTokenJwtPayload,
|
||||||
|
ipAddress?: string
|
||||||
|
) => {
|
||||||
|
const identityAccessToken = await identityAccessTokenDal.findOne({
|
||||||
|
[`${TableName.IdentityAccessToken}.id` as "id"]: token.identityAccessTokenId,
|
||||||
|
isAccessTokenRevoked: false
|
||||||
|
});
|
||||||
|
if (!identityAccessToken) throw new UnauthorizedError();
|
||||||
|
|
||||||
|
if (ipAddress) {
|
||||||
|
checkIPAgainstBlocklist({
|
||||||
|
ipAddress,
|
||||||
|
trustedIps: identityAccessToken?.accessTokenTrustedIps as TIp[]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
validateAccessTokenExp(identityAccessToken);
|
||||||
|
return identityAccessToken;
|
||||||
|
};
|
||||||
|
|
||||||
|
return { renewAccessToken, fnValidateIdentityAccessToken };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
export type TRenewAccessTokenDTO = {
|
export type TRenewAccessTokenDTO = {
|
||||||
accessToken: string;
|
accessToken: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TIdentityAccessTokenJwtPayload = {
|
||||||
|
identityId: string;
|
||||||
|
clientSecretId: string;
|
||||||
|
identityAccessTokenId: string;
|
||||||
|
authTokenType: string;
|
||||||
|
};
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { ActorType, AuthTokenType } from "../auth/auth-type";
|
|||||||
import { TIdentityDalFactory } from "../identity/identity-dal";
|
import { TIdentityDalFactory } from "../identity/identity-dal";
|
||||||
import { TIdentityOrgDalFactory } from "../identity/identity-org-dal";
|
import { TIdentityOrgDalFactory } from "../identity/identity-org-dal";
|
||||||
import { TIdentityAccessTokenDalFactory } from "../identity-access-token/identity-access-token-dal";
|
import { TIdentityAccessTokenDalFactory } from "../identity-access-token/identity-access-token-dal";
|
||||||
|
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
||||||
import { TIdentityUaClientSecretDalFactory } from "./identity-ua-client-secret-dal";
|
import { TIdentityUaClientSecretDalFactory } from "./identity-ua-client-secret-dal";
|
||||||
import { TIdentityUaDalFactory } from "./identity-ua-dal";
|
import { TIdentityUaDalFactory } from "./identity-ua-dal";
|
||||||
import {
|
import {
|
||||||
@@ -123,7 +124,7 @@ export const identityUaServiceFactory = ({
|
|||||||
clientSecretId: validClientSecretInfo.id,
|
clientSecretId: validClientSecretInfo.id,
|
||||||
identityAccessTokenId: identityAccessToken.id,
|
identityAccessTokenId: identityAccessToken.id,
|
||||||
authTokenType: AuthTokenType.IDENTITY_ACCESS_TOKEN
|
authTokenType: AuthTokenType.IDENTITY_ACCESS_TOKEN
|
||||||
},
|
} as TIdentityAccessTokenJwtPayload,
|
||||||
appCfg.JWT_AUTH_SECRET,
|
appCfg.JWT_AUTH_SECRET,
|
||||||
{
|
{
|
||||||
expiresIn:
|
expiresIn:
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName, TProjects } from "@app/db/schemas";
|
import { ProjectsSchema, TableName } from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import { mergeOneToManyRelation, ormify } from "@app/lib/knex";
|
import { ormify, selectAllTableCols, sqlNestRelationships } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TProjectDalFactory = ReturnType<typeof projectDalFactory>;
|
export type TProjectDalFactory = ReturnType<typeof projectDalFactory>;
|
||||||
|
|
||||||
export const projectDalFactory = (db: TDbClient) => {
|
export const projectDalFactory = (db: TDbClient) => {
|
||||||
const projectOrm = ormify(db, TableName.Project);
|
const projectOrm = ormify(db, TableName.Project);
|
||||||
|
|
||||||
const findAllProjects = async (
|
const findAllProjects = async (userId: string) => {
|
||||||
userId: string
|
|
||||||
): Promise<(TProjects & { environments: { id: string; slug: string; name: string }[] })[]> => {
|
|
||||||
try {
|
try {
|
||||||
const workspaces = await db(TableName.ProjectMembership)
|
const workspaces = await db(TableName.ProjectMembership)
|
||||||
.where({ userId })
|
.where({ userId })
|
||||||
@@ -25,34 +23,35 @@ export const projectDalFactory = (db: TDbClient) => {
|
|||||||
`${TableName.Project}.id`
|
`${TableName.Project}.id`
|
||||||
)
|
)
|
||||||
.select(
|
.select(
|
||||||
db.ref("id").withSchema(TableName.Project),
|
selectAllTableCols(TableName.Project),
|
||||||
db.ref("name").withSchema(TableName.Project),
|
db.ref("id").withSchema(TableName.Project).as("_id"),
|
||||||
db.ref("autoCapitalization").withSchema(TableName.Project),
|
|
||||||
db.ref("orgId").withSchema(TableName.Project),
|
|
||||||
db.ref("createdAt").withSchema(TableName.Project),
|
|
||||||
db.ref("updatedAt").withSchema(TableName.Project),
|
|
||||||
db.ref("id").withSchema(TableName.Environment).as("envId"),
|
db.ref("id").withSchema(TableName.Environment).as("envId"),
|
||||||
db.ref("slug").withSchema(TableName.Environment).as("envSlug"),
|
db.ref("slug").withSchema(TableName.Environment).as("envSlug"),
|
||||||
db.ref("name").withSchema(TableName.Environment).as("envName")
|
db.ref("name").withSchema(TableName.Environment).as("envName")
|
||||||
)
|
)
|
||||||
.orderBy("createdAt", "asc", "last");
|
.orderBy("createdAt", "asc", "last");
|
||||||
return mergeOneToManyRelation(
|
return sqlNestRelationships({
|
||||||
workspaces,
|
data: workspaces,
|
||||||
"id",
|
key: "id",
|
||||||
({ envId, envSlug, envName, ...data }) => data,
|
parentMapper: ({ _id, ...el }) => ({ _id, ...ProjectsSchema.parse(el) }),
|
||||||
({ envName, envSlug, envId }) => ({ id: envId, slug: envSlug, name: envName }),
|
childrenMapper: [
|
||||||
"environments"
|
{
|
||||||
);
|
key: "envId",
|
||||||
|
label: "environments" as const,
|
||||||
|
mapper: ({ envId: id, envSlug: slug, envName: name }) => ({
|
||||||
|
id,
|
||||||
|
slug,
|
||||||
|
name
|
||||||
|
})
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Find all projects" });
|
throw new DatabaseError({ error, name: "Find all projects" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const findProjectById = async (
|
const findProjectById = async (id: string) => {
|
||||||
id: string
|
|
||||||
): Promise<
|
|
||||||
(TProjects & { environments: { id: string; slug: string; name: string }[] }) | undefined
|
|
||||||
> => {
|
|
||||||
try {
|
try {
|
||||||
const workspaces = await db(TableName.ProjectMembership)
|
const workspaces = await db(TableName.ProjectMembership)
|
||||||
.where(`${TableName.Project}.id`, id)
|
.where(`${TableName.Project}.id`, id)
|
||||||
@@ -67,24 +66,28 @@ export const projectDalFactory = (db: TDbClient) => {
|
|||||||
`${TableName.Project}.id`
|
`${TableName.Project}.id`
|
||||||
)
|
)
|
||||||
.select(
|
.select(
|
||||||
db.ref("id").withSchema(TableName.Project),
|
selectAllTableCols(TableName.Project),
|
||||||
db.ref("name").withSchema(TableName.Project),
|
db.ref("id").withSchema(TableName.Project).as("_id"),
|
||||||
db.ref("autoCapitalization").withSchema(TableName.Project),
|
|
||||||
db.ref("orgId").withSchema(TableName.Project),
|
|
||||||
db.ref("createdAt").withSchema(TableName.Project),
|
|
||||||
db.ref("updatedAt").withSchema(TableName.Project),
|
|
||||||
db.ref("id").withSchema(TableName.Environment).as("envId"),
|
db.ref("id").withSchema(TableName.Environment).as("envId"),
|
||||||
db.ref("slug").withSchema(TableName.Environment).as("envSlug"),
|
db.ref("slug").withSchema(TableName.Environment).as("envSlug"),
|
||||||
db.ref("name").withSchema(TableName.Environment).as("envName")
|
db.ref("name").withSchema(TableName.Environment).as("envName")
|
||||||
);
|
);
|
||||||
const [doc] = mergeOneToManyRelation(
|
return sqlNestRelationships({
|
||||||
workspaces,
|
data: workspaces,
|
||||||
"id",
|
key: "id",
|
||||||
({ envId, envSlug, envName, ...data }) => data,
|
parentMapper: ({ _id, ...el }) => ({ _id, ...ProjectsSchema.parse(el) }),
|
||||||
({ envName, envSlug, envId }) => ({ id: envId, slug: envSlug, name: envName }),
|
childrenMapper: [
|
||||||
"environments"
|
{
|
||||||
);
|
key: "envId",
|
||||||
return doc;
|
label: "environments" as const,
|
||||||
|
mapper: ({ envId, envSlug: slug, envName: name }) => ({
|
||||||
|
id: envId,
|
||||||
|
slug,
|
||||||
|
name
|
||||||
|
})
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})?.[0];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Find all projects" });
|
throw new DatabaseError({ error, name: "Find all projects" });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,7 +90,8 @@ export const projectServiceFactory = ({
|
|||||||
envs.map(({ id }) => ({ name: ROOT_FOLDER_NAME, envId: id, version: 1 })),
|
envs.map(({ id }) => ({ name: ROOT_FOLDER_NAME, envId: id, version: 1 })),
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
return { ...project, environments: envs };
|
// _id for backward compat
|
||||||
|
return { ...project, environments: envs, _id: project.id };
|
||||||
});
|
});
|
||||||
|
|
||||||
return newProject;
|
return newProject;
|
||||||
|
|||||||
@@ -97,12 +97,17 @@ export const secretFolderServiceFactory = ({
|
|||||||
const env = await projectEnvDal.findOne({ projectId, slug: environment });
|
const env = await projectEnvDal.findOne({ projectId, slug: environment });
|
||||||
if (!env)
|
if (!env)
|
||||||
throw new BadRequestError({ message: "Environment not found", name: "Update folder" });
|
throw new BadRequestError({ message: "Environment not found", name: "Update folder" });
|
||||||
const folder = await folderDal.findOne({ envId: env.id, id, parentId: parentFolder.id });
|
let folder = await folderDal.findOne({ envId: env.id, id, parentId: parentFolder.id });
|
||||||
|
// now folder api accepts id based change
|
||||||
|
// this is for cli and when cli removes this will remove this logic
|
||||||
|
if (!folder) {
|
||||||
|
folder = await folderDal.findOne({ envId: env.id, name: id, parentId: parentFolder.id });
|
||||||
|
}
|
||||||
if (!folder) throw new BadRequestError({ message: "Folder not found" });
|
if (!folder) throw new BadRequestError({ message: "Folder not found" });
|
||||||
|
|
||||||
const newFolder = await folderDal.transaction(async (tx) => {
|
const newFolder = await folderDal.transaction(async (tx) => {
|
||||||
const [doc] = await folderDal.update(
|
const [doc] = await folderDal.update(
|
||||||
{ envId: env.id, id, parentId: parentFolder.id },
|
{ envId: env.id, id: folder.id, parentId: parentFolder.id },
|
||||||
{ name },
|
{ name },
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
ProjectPermissionSub
|
ProjectPermissionSub
|
||||||
} from "@app/ee/services/permission/project-permission";
|
} from "@app/ee/services/permission/project-permission";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
|
||||||
|
|
||||||
import { ActorType } from "../auth/auth-type";
|
import { ActorType } from "../auth/auth-type";
|
||||||
import { TProjectEnvDalFactory } from "../project-env/project-env-dal";
|
import { TProjectEnvDalFactory } from "../project-env/project-env-dal";
|
||||||
@@ -130,10 +130,29 @@ export const serviceTokenServiceFactory = ({
|
|||||||
return tokens;
|
return tokens;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fnValidateServiceToken = async (token: string) => {
|
||||||
|
const [, TOKEN_IDENTIFIER, TOKEN_SECRET] = <[string, string, string]>token.split(".", 3);
|
||||||
|
const serviceToken = await serviceTokenDal.findById(TOKEN_IDENTIFIER);
|
||||||
|
if (!serviceToken) throw new UnauthorizedError();
|
||||||
|
|
||||||
|
if (serviceToken.expiresAt && new Date(serviceToken.expiresAt) < new Date()) {
|
||||||
|
await serviceTokenDal.deleteById(serviceToken.id);
|
||||||
|
throw new UnauthorizedError({ message: "failed to authenticate expired service token" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const isMatch = await bcrypt.compare(TOKEN_SECRET, serviceToken.secretHash);
|
||||||
|
if (!isMatch) throw new UnauthorizedError();
|
||||||
|
const updatedToken = await serviceTokenDal.updateById(serviceToken.id, {
|
||||||
|
lastUsed: new Date()
|
||||||
|
});
|
||||||
|
return updatedToken;
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
createServiceToken,
|
createServiceToken,
|
||||||
deleteServiceToken,
|
deleteServiceToken,
|
||||||
getServiceToken,
|
getServiceToken,
|
||||||
getProjectServiceTokens
|
getProjectServiceTokens,
|
||||||
|
fnValidateServiceToken
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -69,19 +69,21 @@ export const extractAuthMode = async ({
|
|||||||
return { authMode: AuthMode.SERVICE_TOKEN, authTokenValue };
|
return { authMode: AuthMode.SERVICE_TOKEN, authTokenValue };
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (decodedToken.authTokenType) {
|
const decodedToken = <jwt.AuthnJwtPayload>jwt.verify(authTokenValue, await getAuthSecret());
|
||||||
case AuthTokenType.ACCESS_TOKEN:
|
|
||||||
return { authMode: AuthMode.JWT, authTokenValue };
|
switch (decodedToken.authTokenType) {
|
||||||
case AuthTokenType.API_KEY:
|
case AuthTokenType.ACCESS_TOKEN:
|
||||||
return { authMode: AuthMode.API_KEY_V2, authTokenValue };
|
return { authMode: AuthMode.JWT, authTokenValue };
|
||||||
case AuthTokenType.IDENTITY_ACCESS_TOKEN:
|
case AuthTokenType.API_KEY:
|
||||||
return { authMode: AuthMode.IDENTITY_ACCESS_TOKEN, authTokenValue };
|
return { authMode: AuthMode.API_KEY_V2, authTokenValue };
|
||||||
default:
|
case AuthTokenType.IDENTITY_ACCESS_TOKEN:
|
||||||
throw UnauthorizedRequestError({
|
return { authMode: AuthMode.IDENTITY_ACCESS_TOKEN, authTokenValue };
|
||||||
message: "Failed to authenticate unknown authentication method"
|
default:
|
||||||
});
|
throw UnauthorizedRequestError({
|
||||||
}
|
message: "Failed to authenticate unknown authentication method"
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const getAuthData = async ({
|
export const getAuthData = async ({
|
||||||
authMode,
|
authMode,
|
||||||
@@ -97,112 +99,9 @@ export const getAuthData = async ({
|
|||||||
authTokenValue
|
authTokenValue
|
||||||
});
|
});
|
||||||
|
|
||||||
switch (authMode) {
|
|
||||||
case AuthMode.SERVICE_TOKEN: {
|
|
||||||
const serviceTokenData = await validateServiceTokenV2({
|
|
||||||
authTokenValue
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
actor: {
|
|
||||||
type: ActorType.SERVICE,
|
|
||||||
metadata: {
|
|
||||||
serviceId: serviceTokenData._id.toString(),
|
|
||||||
name: serviceTokenData.name
|
|
||||||
}
|
|
||||||
},
|
|
||||||
authPayload: serviceTokenData,
|
|
||||||
ipAddress,
|
|
||||||
userAgent,
|
|
||||||
userAgentType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case AuthMode.IDENTITY_ACCESS_TOKEN: {
|
|
||||||
const identity = await validateIdentity({
|
|
||||||
authTokenValue,
|
|
||||||
ipAddress
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
actor: {
|
|
||||||
type: ActorType.IDENTITY,
|
|
||||||
metadata: {
|
|
||||||
identityId: identity._id.toString(),
|
|
||||||
name: identity.name
|
|
||||||
}
|
|
||||||
},
|
|
||||||
authPayload: identity,
|
|
||||||
ipAddress,
|
|
||||||
userAgent,
|
|
||||||
userAgentType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case AuthMode.API_KEY: {
|
|
||||||
const user = await validateAPIKey({
|
|
||||||
authTokenValue
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
actor: {
|
|
||||||
type: ActorType.USER,
|
|
||||||
metadata: {
|
|
||||||
userId: user._id.toString(),
|
|
||||||
email: user.email
|
|
||||||
}
|
|
||||||
},
|
|
||||||
authPayload: user,
|
|
||||||
ipAddress,
|
|
||||||
userAgent,
|
|
||||||
userAgentType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case AuthMode.API_KEY_V2: {
|
|
||||||
const user = await validateAPIKeyV2({
|
|
||||||
authTokenValue
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
actor: {
|
|
||||||
type: ActorType.USER,
|
|
||||||
metadata: {
|
|
||||||
userId: user._id.toString(),
|
|
||||||
email: user.email
|
|
||||||
}
|
|
||||||
},
|
|
||||||
authPayload: user,
|
|
||||||
ipAddress,
|
|
||||||
userAgent,
|
|
||||||
userAgentType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case AuthMode.JWT: {
|
|
||||||
const user = await validateJWT({
|
|
||||||
authTokenValue
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
actor: {
|
|
||||||
type: ActorType.USER,
|
|
||||||
metadata: {
|
|
||||||
userId: user._id.toString(),
|
|
||||||
email: user.email
|
|
||||||
}
|
|
||||||
},
|
|
||||||
authPayload: user,
|
|
||||||
ipAddress,
|
|
||||||
userAgent,
|
|
||||||
userAgentType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case AuthMode.SERVICE_ACCESS_TOKEN: {
|
|
||||||
const serviceTokenData = await validateServiceTokenV3({
|
|
||||||
authTokenValue
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
actor: {
|
actor: {
|
||||||
type: ActorType.SERVICE_V3,
|
type: ActorType.SERVICE,
|
||||||
metadata: {
|
metadata: {
|
||||||
serviceId: serviceTokenData._id.toString(),
|
serviceId: serviceTokenData._id.toString(),
|
||||||
name: serviceTokenData.name
|
name: serviceTokenData.name
|
||||||
@@ -214,6 +113,26 @@ export const getAuthData = async ({
|
|||||||
userAgentType
|
userAgentType
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
case AuthMode.IDENTITY_ACCESS_TOKEN: {
|
||||||
|
const identity = await validateIdentity({
|
||||||
|
authTokenValue,
|
||||||
|
ipAddress
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
actor: {
|
||||||
|
type: ActorType.IDENTITY,
|
||||||
|
metadata: {
|
||||||
|
identityId: identity._id.toString(),
|
||||||
|
name: identity.name
|
||||||
|
}
|
||||||
|
},
|
||||||
|
authPayload: identity,
|
||||||
|
ipAddress,
|
||||||
|
userAgent,
|
||||||
|
userAgentType
|
||||||
|
};
|
||||||
|
}
|
||||||
case AuthMode.API_KEY: {
|
case AuthMode.API_KEY: {
|
||||||
const user = await validateAPIKey({
|
const user = await validateAPIKey({
|
||||||
authTokenValue
|
authTokenValue
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ export const folderQueryKeys = {
|
|||||||
["secret-folders", { projectId, environment, path }] as const
|
["secret-folders", { projectId, environment, path }] as const
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchProjectFolders = async (projectId: string, environment: string, path = "/") => {
|
const fetchProjectFolders = async (workspaceId: string, environment: string, path = "/") => {
|
||||||
const { data } = await apiRequest.get<{ folders: TSecretFolder[] }>("/api/v1/folders", {
|
const { data } = await apiRequest.get<{ folders: TSecretFolder[] }>("/api/v1/folders", {
|
||||||
params: {
|
params: {
|
||||||
projectId,
|
workspaceId,
|
||||||
environment,
|
environment,
|
||||||
path
|
path
|
||||||
}
|
}
|
||||||
@@ -102,7 +102,10 @@ export const useCreateFolder = () => {
|
|||||||
|
|
||||||
return useMutation<{}, {}, TCreateFolderDTO>({
|
return useMutation<{}, {}, TCreateFolderDTO>({
|
||||||
mutationFn: async (dto) => {
|
mutationFn: async (dto) => {
|
||||||
const { data } = await apiRequest.post("/api/v1/folders", dto);
|
const { data } = await apiRequest.post("/api/v1/folders", {
|
||||||
|
...dto,
|
||||||
|
workspaceId: dto.projectId
|
||||||
|
});
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
onSuccess: (_, { projectId, environment, path }) => {
|
onSuccess: (_, { projectId, environment, path }) => {
|
||||||
@@ -127,7 +130,7 @@ export const useUpdateFolder = () => {
|
|||||||
const { data } = await apiRequest.patch(`/api/v1/folders/${folderId}`, {
|
const { data } = await apiRequest.patch(`/api/v1/folders/${folderId}`, {
|
||||||
name,
|
name,
|
||||||
environment,
|
environment,
|
||||||
projectId,
|
workspaceId: projectId,
|
||||||
path
|
path
|
||||||
});
|
});
|
||||||
return data;
|
return data;
|
||||||
@@ -154,7 +157,7 @@ export const useDeleteFolder = () => {
|
|||||||
const { data } = await apiRequest.delete(`/api/v1/folders/${folderId}`, {
|
const { data } = await apiRequest.delete(`/api/v1/folders/${folderId}`, {
|
||||||
data: {
|
data: {
|
||||||
environment,
|
environment,
|
||||||
projectId,
|
workspaceId: projectId,
|
||||||
path
|
path
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export const useCreateSecretImport = () => {
|
|||||||
const { data } = await apiRequest.post("/api/v1/secret-imports", {
|
const { data } = await apiRequest.post("/api/v1/secret-imports", {
|
||||||
import: secretImport,
|
import: secretImport,
|
||||||
environment,
|
environment,
|
||||||
projectId,
|
workspaceId: projectId,
|
||||||
path
|
path
|
||||||
});
|
});
|
||||||
return data;
|
return data;
|
||||||
@@ -38,7 +38,7 @@ export const useUpdateSecretImport = () => {
|
|||||||
import: secretImports,
|
import: secretImports,
|
||||||
environment,
|
environment,
|
||||||
path,
|
path,
|
||||||
projectId
|
workspaceId: projectId
|
||||||
});
|
});
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
@@ -60,7 +60,7 @@ export const useDeleteSecretImport = () => {
|
|||||||
mutationFn: async ({ id, projectId, path, environment }) => {
|
mutationFn: async ({ id, projectId, path, environment }) => {
|
||||||
const { data } = await apiRequest.delete(`/api/v1/secret-imports/${id}`, {
|
const { data } = await apiRequest.delete(`/api/v1/secret-imports/${id}`, {
|
||||||
data: {
|
data: {
|
||||||
projectId,
|
workspaceId: projectId,
|
||||||
path,
|
path,
|
||||||
environment
|
environment
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ const fetchSecretImport = async ({ projectId, environment, path = "/" }: TGetSec
|
|||||||
"/api/v1/secret-imports",
|
"/api/v1/secret-imports",
|
||||||
{
|
{
|
||||||
params: {
|
params: {
|
||||||
projectId,
|
workspaceId: projectId,
|
||||||
environment,
|
environment,
|
||||||
path
|
path
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,7 @@ const fetchImportedSecrets = async (
|
|||||||
"/api/v1/secret-imports/secrets",
|
"/api/v1/secret-imports/secrets",
|
||||||
{
|
{
|
||||||
params: {
|
params: {
|
||||||
projectId: workspaceId,
|
workspaceId,
|
||||||
environment,
|
environment,
|
||||||
path: directory
|
path: directory
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ export {
|
|||||||
useGetWorkspaceUsers,
|
useGetWorkspaceUsers,
|
||||||
useNameWorkspaceSecrets,
|
useNameWorkspaceSecrets,
|
||||||
useRenameWorkspace,
|
useRenameWorkspace,
|
||||||
useReorderWsEnvironment,
|
|
||||||
useToggleAutoCapitalization,
|
useToggleAutoCapitalization,
|
||||||
useUpdateIdentityWorkspaceRole,
|
useUpdateIdentityWorkspaceRole,
|
||||||
useUpdateUserWorkspaceRole,
|
useUpdateUserWorkspaceRole,
|
||||||
useUpdateWsEnvironment} from "./queries";
|
useUpdateWsEnvironment
|
||||||
|
} from "./queries";
|
||||||
|
|||||||
Reference in New Issue
Block a user