mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
feat: changed line length to 120
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"singleQuote": false,
|
"singleQuote": false,
|
||||||
"printWidth": 100,
|
"printWidth": 120,
|
||||||
"trailingComma": "none",
|
"trailingComma": "none",
|
||||||
"tabWidth": 2,
|
"tabWidth": 2,
|
||||||
"semi": true
|
"semi": true
|
||||||
}
|
}
|
||||||
|
|||||||
7
backend/src/@types/fastify-zod.d.ts
vendored
7
backend/src/@types/fastify-zod.d.ts
vendored
@@ -1,9 +1,4 @@
|
|||||||
import {
|
import { FastifyInstance, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerDefault } from "fastify";
|
||||||
FastifyInstance,
|
|
||||||
RawReplyDefaultExpression,
|
|
||||||
RawRequestDefaultExpression,
|
|
||||||
RawServerDefault
|
|
||||||
} from "fastify";
|
|
||||||
import { Logger } from "pino";
|
import { Logger } from "pino";
|
||||||
|
|
||||||
import { ZodTypeProvider } from "@app/server/plugins/fastify-zod";
|
import { ZodTypeProvider } from "@app/server/plugins/fastify-zod";
|
||||||
|
|||||||
108
backend/src/@types/knex.d.ts
vendored
108
backend/src/@types/knex.d.ts
vendored
@@ -177,11 +177,7 @@ declare module "knex/types/tables" {
|
|||||||
TUserEncryptionKeysInsert,
|
TUserEncryptionKeysInsert,
|
||||||
TUserEncryptionKeysUpdate
|
TUserEncryptionKeysUpdate
|
||||||
>;
|
>;
|
||||||
[TableName.AuthTokens]: Knex.CompositeTableType<
|
[TableName.AuthTokens]: Knex.CompositeTableType<TAuthTokens, TAuthTokensInsert, TAuthTokensUpdate>;
|
||||||
TAuthTokens,
|
|
||||||
TAuthTokensInsert,
|
|
||||||
TAuthTokensUpdate
|
|
||||||
>;
|
|
||||||
[TableName.AuthTokenSession]: Knex.CompositeTableType<
|
[TableName.AuthTokenSession]: Knex.CompositeTableType<
|
||||||
TAuthTokenSessions,
|
TAuthTokenSessions,
|
||||||
TAuthTokenSessionsInsert,
|
TAuthTokenSessionsInsert,
|
||||||
@@ -192,32 +188,16 @@ declare module "knex/types/tables" {
|
|||||||
TBackupPrivateKeyInsert,
|
TBackupPrivateKeyInsert,
|
||||||
TBackupPrivateKeyUpdate
|
TBackupPrivateKeyUpdate
|
||||||
>;
|
>;
|
||||||
[TableName.Organization]: Knex.CompositeTableType<
|
[TableName.Organization]: Knex.CompositeTableType<TOrganizations, TOrganizationsInsert, TOrganizationsUpdate>;
|
||||||
TOrganizations,
|
[TableName.OrgMembership]: Knex.CompositeTableType<TOrgMemberships, TOrgMembershipsInsert, TOrgMembershipsUpdate>;
|
||||||
TOrganizationsInsert,
|
|
||||||
TOrganizationsUpdate
|
|
||||||
>;
|
|
||||||
[TableName.OrgMembership]: Knex.CompositeTableType<
|
|
||||||
TOrgMemberships,
|
|
||||||
TOrgMembershipsInsert,
|
|
||||||
TOrgMembershipsUpdate
|
|
||||||
>;
|
|
||||||
[TableName.OrgRoles]: Knex.CompositeTableType<TOrgRoles, TOrgRolesInsert, TOrgRolesUpdate>;
|
[TableName.OrgRoles]: Knex.CompositeTableType<TOrgRoles, TOrgRolesInsert, TOrgRolesUpdate>;
|
||||||
[TableName.IncidentContact]: Knex.CompositeTableType<
|
[TableName.IncidentContact]: Knex.CompositeTableType<
|
||||||
TIncidentContacts,
|
TIncidentContacts,
|
||||||
TIncidentContactsInsert,
|
TIncidentContactsInsert,
|
||||||
TIncidentContactsUpdate
|
TIncidentContactsUpdate
|
||||||
>;
|
>;
|
||||||
[TableName.UserAction]: Knex.CompositeTableType<
|
[TableName.UserAction]: Knex.CompositeTableType<TUserActions, TUserActionsInsert, TUserActionsUpdate>;
|
||||||
TUserActions,
|
[TableName.SuperAdmin]: Knex.CompositeTableType<TSuperAdmin, TSuperAdminInsert, TSuperAdminUpdate>;
|
||||||
TUserActionsInsert,
|
|
||||||
TUserActionsUpdate
|
|
||||||
>;
|
|
||||||
[TableName.SuperAdmin]: Knex.CompositeTableType<
|
|
||||||
TSuperAdmin,
|
|
||||||
TSuperAdminInsert,
|
|
||||||
TSuperAdminUpdate
|
|
||||||
>;
|
|
||||||
[TableName.ApiKey]: Knex.CompositeTableType<TApiKeys, TApiKeysInsert, TApiKeysUpdate>;
|
[TableName.ApiKey]: Knex.CompositeTableType<TApiKeys, TApiKeysInsert, TApiKeysUpdate>;
|
||||||
[TableName.Project]: Knex.CompositeTableType<TProjects, TProjectsInsert, TProjectsUpdate>;
|
[TableName.Project]: Knex.CompositeTableType<TProjects, TProjectsInsert, TProjectsUpdate>;
|
||||||
[TableName.ProjectMembership]: Knex.CompositeTableType<
|
[TableName.ProjectMembership]: Knex.CompositeTableType<
|
||||||
@@ -230,73 +210,33 @@ declare module "knex/types/tables" {
|
|||||||
TProjectEnvironmentsInsert,
|
TProjectEnvironmentsInsert,
|
||||||
TProjectEnvironmentsUpdate
|
TProjectEnvironmentsUpdate
|
||||||
>;
|
>;
|
||||||
[TableName.ProjectBot]: Knex.CompositeTableType<
|
[TableName.ProjectBot]: Knex.CompositeTableType<TProjectBots, TProjectBotsInsert, TProjectBotsUpdate>;
|
||||||
TProjectBots,
|
[TableName.ProjectRoles]: Knex.CompositeTableType<TProjectRoles, TProjectRolesInsert, TProjectRolesUpdate>;
|
||||||
TProjectBotsInsert,
|
[TableName.ProjectKeys]: Knex.CompositeTableType<TProjectKeys, TProjectKeysInsert, TProjectKeysUpdate>;
|
||||||
TProjectBotsUpdate
|
|
||||||
>;
|
|
||||||
[TableName.ProjectRoles]: Knex.CompositeTableType<
|
|
||||||
TProjectRoles,
|
|
||||||
TProjectRolesInsert,
|
|
||||||
TProjectRolesUpdate
|
|
||||||
>;
|
|
||||||
[TableName.ProjectKeys]: Knex.CompositeTableType<
|
|
||||||
TProjectKeys,
|
|
||||||
TProjectKeysInsert,
|
|
||||||
TProjectKeysUpdate
|
|
||||||
>;
|
|
||||||
[TableName.Secret]: Knex.CompositeTableType<TSecrets, TSecretsInsert, TSecretsUpdate>;
|
[TableName.Secret]: Knex.CompositeTableType<TSecrets, TSecretsInsert, TSecretsUpdate>;
|
||||||
[TableName.SecretBlindIndex]: Knex.CompositeTableType<
|
[TableName.SecretBlindIndex]: Knex.CompositeTableType<
|
||||||
TSecretBlindIndexes,
|
TSecretBlindIndexes,
|
||||||
TSecretBlindIndexesInsert,
|
TSecretBlindIndexesInsert,
|
||||||
TSecretBlindIndexesUpdate
|
TSecretBlindIndexesUpdate
|
||||||
>;
|
>;
|
||||||
[TableName.SecretVersion]: Knex.CompositeTableType<
|
[TableName.SecretVersion]: Knex.CompositeTableType<TSecretVersions, TSecretVersionsInsert, TSecretVersionsUpdate>;
|
||||||
TSecretVersions,
|
[TableName.SecretFolder]: Knex.CompositeTableType<TSecretFolders, TSecretFoldersInsert, TSecretFoldersUpdate>;
|
||||||
TSecretVersionsInsert,
|
|
||||||
TSecretVersionsUpdate
|
|
||||||
>;
|
|
||||||
[TableName.SecretFolder]: Knex.CompositeTableType<
|
|
||||||
TSecretFolders,
|
|
||||||
TSecretFoldersInsert,
|
|
||||||
TSecretFoldersUpdate
|
|
||||||
>;
|
|
||||||
[TableName.SecretFolderVersion]: Knex.CompositeTableType<
|
[TableName.SecretFolderVersion]: Knex.CompositeTableType<
|
||||||
TSecretFolderVersions,
|
TSecretFolderVersions,
|
||||||
TSecretFolderVersionsInsert,
|
TSecretFolderVersionsInsert,
|
||||||
TSecretFolderVersionsUpdate
|
TSecretFolderVersionsUpdate
|
||||||
>;
|
>;
|
||||||
[TableName.SecretTag]: Knex.CompositeTableType<
|
[TableName.SecretTag]: Knex.CompositeTableType<TSecretTags, TSecretTagsInsert, TSecretTagsUpdate>;
|
||||||
TSecretTags,
|
[TableName.SecretImport]: Knex.CompositeTableType<TSecretImports, TSecretImportsInsert, TSecretImportsUpdate>;
|
||||||
TSecretTagsInsert,
|
[TableName.Integration]: Knex.CompositeTableType<TIntegrations, TIntegrationsInsert, TIntegrationsUpdate>;
|
||||||
TSecretTagsUpdate
|
|
||||||
>;
|
|
||||||
[TableName.SecretImport]: Knex.CompositeTableType<
|
|
||||||
TSecretImports,
|
|
||||||
TSecretImportsInsert,
|
|
||||||
TSecretImportsUpdate
|
|
||||||
>;
|
|
||||||
[TableName.Integration]: Knex.CompositeTableType<
|
|
||||||
TIntegrations,
|
|
||||||
TIntegrationsInsert,
|
|
||||||
TIntegrationsUpdate
|
|
||||||
>;
|
|
||||||
[TableName.Webhook]: Knex.CompositeTableType<TWebhooks, TWebhooksInsert, TWebhooksUpdate>;
|
[TableName.Webhook]: Knex.CompositeTableType<TWebhooks, TWebhooksInsert, TWebhooksUpdate>;
|
||||||
[TableName.ServiceToken]: Knex.CompositeTableType<
|
[TableName.ServiceToken]: Knex.CompositeTableType<TServiceTokens, TServiceTokensInsert, TServiceTokensUpdate>;
|
||||||
TServiceTokens,
|
|
||||||
TServiceTokensInsert,
|
|
||||||
TServiceTokensUpdate
|
|
||||||
>;
|
|
||||||
[TableName.IntegrationAuth]: Knex.CompositeTableType<
|
[TableName.IntegrationAuth]: Knex.CompositeTableType<
|
||||||
TIntegrationAuths,
|
TIntegrationAuths,
|
||||||
TIntegrationAuthsInsert,
|
TIntegrationAuthsInsert,
|
||||||
TIntegrationAuthsUpdate
|
TIntegrationAuthsUpdate
|
||||||
>;
|
>;
|
||||||
[TableName.Identity]: Knex.CompositeTableType<
|
[TableName.Identity]: Knex.CompositeTableType<TIdentities, TIdentitiesInsert, TIdentitiesUpdate>;
|
||||||
TIdentities,
|
|
||||||
TIdentitiesInsert,
|
|
||||||
TIdentitiesUpdate
|
|
||||||
>;
|
|
||||||
[TableName.IdentityUniversalAuth]: Knex.CompositeTableType<
|
[TableName.IdentityUniversalAuth]: Knex.CompositeTableType<
|
||||||
TIdentityUniversalAuths,
|
TIdentityUniversalAuths,
|
||||||
TIdentityUniversalAuthsInsert,
|
TIdentityUniversalAuthsInsert,
|
||||||
@@ -362,11 +302,7 @@ declare module "knex/types/tables" {
|
|||||||
TSecretRotationOutputsInsert,
|
TSecretRotationOutputsInsert,
|
||||||
TSecretRotationOutputsUpdate
|
TSecretRotationOutputsUpdate
|
||||||
>;
|
>;
|
||||||
[TableName.Snapshot]: Knex.CompositeTableType<
|
[TableName.Snapshot]: Knex.CompositeTableType<TSecretSnapshots, TSecretSnapshotsInsert, TSecretSnapshotsUpdate>;
|
||||||
TSecretSnapshots,
|
|
||||||
TSecretSnapshotsInsert,
|
|
||||||
TSecretSnapshotsUpdate
|
|
||||||
>;
|
|
||||||
[TableName.SnapshotSecret]: Knex.CompositeTableType<
|
[TableName.SnapshotSecret]: Knex.CompositeTableType<
|
||||||
TSecretSnapshotSecrets,
|
TSecretSnapshotSecrets,
|
||||||
TSecretSnapshotSecretsInsert,
|
TSecretSnapshotSecretsInsert,
|
||||||
@@ -377,11 +313,7 @@ declare module "knex/types/tables" {
|
|||||||
TSecretSnapshotFoldersInsert,
|
TSecretSnapshotFoldersInsert,
|
||||||
TSecretSnapshotFoldersUpdate
|
TSecretSnapshotFoldersUpdate
|
||||||
>;
|
>;
|
||||||
[TableName.SamlConfig]: Knex.CompositeTableType<
|
[TableName.SamlConfig]: Knex.CompositeTableType<TSamlConfigs, TSamlConfigsInsert, TSamlConfigsUpdate>;
|
||||||
TSamlConfigs,
|
|
||||||
TSamlConfigsInsert,
|
|
||||||
TSamlConfigsUpdate
|
|
||||||
>;
|
|
||||||
[TableName.OrgBot]: Knex.CompositeTableType<TOrgBots, TOrgBotsInsert, TOrgBotsUpdate>;
|
[TableName.OrgBot]: Knex.CompositeTableType<TOrgBots, TOrgBotsInsert, TOrgBotsUpdate>;
|
||||||
[TableName.AuditLog]: Knex.CompositeTableType<TAuditLogs, TAuditLogsInsert, TAuditLogsUpdate>;
|
[TableName.AuditLog]: Knex.CompositeTableType<TAuditLogs, TAuditLogsInsert, TAuditLogsUpdate>;
|
||||||
[TableName.GitAppInstallSession]: Knex.CompositeTableType<
|
[TableName.GitAppInstallSession]: Knex.CompositeTableType<
|
||||||
@@ -395,11 +327,7 @@ declare module "knex/types/tables" {
|
|||||||
TSecretScanningGitRisksInsert,
|
TSecretScanningGitRisksInsert,
|
||||||
TSecretScanningGitRisksUpdate
|
TSecretScanningGitRisksUpdate
|
||||||
>;
|
>;
|
||||||
[TableName.TrustedIps]: Knex.CompositeTableType<
|
[TableName.TrustedIps]: Knex.CompositeTableType<TTrustedIps, TTrustedIpsInsert, TTrustedIpsUpdate>;
|
||||||
TTrustedIps,
|
|
||||||
TTrustedIpsInsert,
|
|
||||||
TTrustedIpsUpdate
|
|
||||||
>;
|
|
||||||
// Junction tables
|
// Junction tables
|
||||||
[TableName.JnSecretTag]: Knex.CompositeTableType<
|
[TableName.JnSecretTag]: Knex.CompositeTableType<
|
||||||
TSecretTagJunction,
|
TSecretTagJunction,
|
||||||
|
|||||||
@@ -38,12 +38,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
}
|
}
|
||||||
await createOnUpdateTrigger(knex, TableName.SecretVersion);
|
await createOnUpdateTrigger(knex, TableName.SecretVersion);
|
||||||
// many to many relation between tags
|
// many to many relation between tags
|
||||||
await createJunctionTable(
|
await createJunctionTable(knex, TableName.SecretVersionTag, TableName.SecretVersion, TableName.SecretTag);
|
||||||
knex,
|
|
||||||
TableName.SecretVersionTag,
|
|
||||||
TableName.SecretVersion,
|
|
||||||
TableName.SecretTag
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function down(knex: Knex): Promise<void> {
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
|||||||
@@ -50,10 +50,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
t.string("integration").notNullable();
|
t.string("integration").notNullable();
|
||||||
t.jsonb("metadata");
|
t.jsonb("metadata");
|
||||||
t.uuid("integrationAuthId").notNullable();
|
t.uuid("integrationAuthId").notNullable();
|
||||||
t.foreign("integrationAuthId")
|
t.foreign("integrationAuthId").references("id").inTable(TableName.IntegrationAuth).onDelete("CASCADE");
|
||||||
.references("id")
|
|
||||||
.inTable(TableName.IntegrationAuth)
|
|
||||||
.onDelete("CASCADE");
|
|
||||||
t.uuid("envId").notNullable();
|
t.uuid("envId").notNullable();
|
||||||
t.string("secretPath").defaultTo("/").notNullable();
|
t.string("secretPath").defaultTo("/").notNullable();
|
||||||
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||||
|
|||||||
@@ -31,10 +31,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
t.boolean("isClientSecretRevoked").defaultTo(false).notNullable();
|
t.boolean("isClientSecretRevoked").defaultTo(false).notNullable();
|
||||||
t.timestamps(true, true, true);
|
t.timestamps(true, true, true);
|
||||||
t.uuid("identityUAId").notNullable();
|
t.uuid("identityUAId").notNullable();
|
||||||
t.foreign("identityUAId")
|
t.foreign("identityUAId").references("id").inTable(TableName.IdentityUniversalAuth).onDelete("CASCADE");
|
||||||
.references("id")
|
|
||||||
.inTable(TableName.IdentityUniversalAuth)
|
|
||||||
.onDelete("CASCADE");
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
await createOnUpdateTrigger(knex, TableName.IdentityUniversalAuth);
|
await createOnUpdateTrigger(knex, TableName.IdentityUniversalAuth);
|
||||||
|
|||||||
@@ -21,15 +21,9 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
await knex.schema.createTable(TableName.SecretApprovalPolicyApprover, (t) => {
|
await knex.schema.createTable(TableName.SecretApprovalPolicyApprover, (t) => {
|
||||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
t.uuid("approverId").notNullable();
|
t.uuid("approverId").notNullable();
|
||||||
t.foreign("approverId")
|
t.foreign("approverId").references("id").inTable(TableName.ProjectMembership).onDelete("CASCADE");
|
||||||
.references("id")
|
|
||||||
.inTable(TableName.ProjectMembership)
|
|
||||||
.onDelete("CASCADE");
|
|
||||||
t.uuid("policyId").notNullable();
|
t.uuid("policyId").notNullable();
|
||||||
t.foreign("policyId")
|
t.foreign("policyId").references("id").inTable(TableName.SecretApprovalPolicy).onDelete("CASCADE");
|
||||||
.references("id")
|
|
||||||
.inTable(TableName.SecretApprovalPolicy)
|
|
||||||
.onDelete("CASCADE");
|
|
||||||
t.timestamps(true, true, true);
|
t.timestamps(true, true, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,23 +11,14 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
t.boolean("hasMerged").defaultTo(false).notNullable();
|
t.boolean("hasMerged").defaultTo(false).notNullable();
|
||||||
t.string("status").defaultTo("open").notNullable();
|
t.string("status").defaultTo("open").notNullable();
|
||||||
t.jsonb("conflicts");
|
t.jsonb("conflicts");
|
||||||
t.foreign("policyId")
|
t.foreign("policyId").references("id").inTable(TableName.SecretApprovalPolicy).onDelete("CASCADE");
|
||||||
.references("id")
|
|
||||||
.inTable(TableName.SecretApprovalPolicy)
|
|
||||||
.onDelete("CASCADE");
|
|
||||||
t.string("slug").notNullable();
|
t.string("slug").notNullable();
|
||||||
t.uuid("folderId").notNullable();
|
t.uuid("folderId").notNullable();
|
||||||
t.foreign("folderId").references("id").inTable(TableName.SecretFolder).onDelete("CASCADE");
|
t.foreign("folderId").references("id").inTable(TableName.SecretFolder).onDelete("CASCADE");
|
||||||
t.uuid("statusChangeBy");
|
t.uuid("statusChangeBy");
|
||||||
t.foreign("statusChangeBy")
|
t.foreign("statusChangeBy").references("id").inTable(TableName.ProjectMembership).onDelete("SET NULL");
|
||||||
.references("id")
|
|
||||||
.inTable(TableName.ProjectMembership)
|
|
||||||
.onDelete("SET NULL");
|
|
||||||
t.uuid("committerId").notNullable();
|
t.uuid("committerId").notNullable();
|
||||||
t.foreign("committerId")
|
t.foreign("committerId").references("id").inTable(TableName.ProjectMembership).onDelete("CASCADE");
|
||||||
.references("id")
|
|
||||||
.inTable(TableName.ProjectMembership)
|
|
||||||
.onDelete("CASCADE");
|
|
||||||
t.timestamps(true, true, true);
|
t.timestamps(true, true, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -40,10 +31,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
t.foreign("member").references("id").inTable(TableName.ProjectMembership).onDelete("CASCADE");
|
t.foreign("member").references("id").inTable(TableName.ProjectMembership).onDelete("CASCADE");
|
||||||
t.string("status").notNullable();
|
t.string("status").notNullable();
|
||||||
t.uuid("requestId").notNullable();
|
t.uuid("requestId").notNullable();
|
||||||
t.foreign("requestId")
|
t.foreign("requestId").references("id").inTable(TableName.SecretApprovalRequest).onDelete("CASCADE");
|
||||||
.references("id")
|
|
||||||
.inTable(TableName.SecretApprovalRequest)
|
|
||||||
.onDelete("CASCADE");
|
|
||||||
t.timestamps(true, true, true);
|
t.timestamps(true, true, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -73,18 +61,12 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
t.timestamps(true, true, true);
|
t.timestamps(true, true, true);
|
||||||
// commit details
|
// commit details
|
||||||
t.uuid("requestId").notNullable();
|
t.uuid("requestId").notNullable();
|
||||||
t.foreign("requestId")
|
t.foreign("requestId").references("id").inTable(TableName.SecretApprovalRequest).onDelete("CASCADE");
|
||||||
.references("id")
|
|
||||||
.inTable(TableName.SecretApprovalRequest)
|
|
||||||
.onDelete("CASCADE");
|
|
||||||
t.string("op").notNullable();
|
t.string("op").notNullable();
|
||||||
t.uuid("secretId");
|
t.uuid("secretId");
|
||||||
t.foreign("secretId").references("id").inTable(TableName.Secret).onDelete("SET NULL");
|
t.foreign("secretId").references("id").inTable(TableName.Secret).onDelete("SET NULL");
|
||||||
t.uuid("secretVersion");
|
t.uuid("secretVersion");
|
||||||
t.foreign("secretVersion")
|
t.foreign("secretVersion").references("id").inTable(TableName.SecretVersion).onDelete("SET NULL");
|
||||||
.references("id")
|
|
||||||
.inTable(TableName.SecretVersion)
|
|
||||||
.onDelete("SET NULL");
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
await createOnUpdateTrigger(knex, TableName.SecretApprovalRequestSecret);
|
await createOnUpdateTrigger(knex, TableName.SecretApprovalRequestSecret);
|
||||||
@@ -93,10 +75,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
await knex.schema.createTable(TableName.SecretApprovalRequestSecretTag, (t) => {
|
await knex.schema.createTable(TableName.SecretApprovalRequestSecretTag, (t) => {
|
||||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
t.uuid("secretId").notNullable();
|
t.uuid("secretId").notNullable();
|
||||||
t.foreign("secretId")
|
t.foreign("secretId").references("id").inTable(TableName.SecretApprovalRequestSecret).onDelete("CASCADE");
|
||||||
.references("id")
|
|
||||||
.inTable(TableName.SecretApprovalRequestSecret)
|
|
||||||
.onDelete("CASCADE");
|
|
||||||
t.uuid("tagId").notNullable();
|
t.uuid("tagId").notNullable();
|
||||||
t.foreign("tagId").references("id").inTable(TableName.SecretTag).onDelete("CASCADE");
|
t.foreign("tagId").references("id").inTable(TableName.SecretTag).onDelete("CASCADE");
|
||||||
t.timestamps(true, true, true);
|
t.timestamps(true, true, true);
|
||||||
|
|||||||
@@ -32,10 +32,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
t.uuid("secretId").notNullable();
|
t.uuid("secretId").notNullable();
|
||||||
t.foreign("secretId").references("id").inTable(TableName.Secret).onDelete("CASCADE");
|
t.foreign("secretId").references("id").inTable(TableName.Secret).onDelete("CASCADE");
|
||||||
t.uuid("rotationId").notNullable();
|
t.uuid("rotationId").notNullable();
|
||||||
t.foreign("rotationId")
|
t.foreign("rotationId").references("id").inTable(TableName.SecretRotation).onDelete("CASCADE");
|
||||||
.references("id")
|
|
||||||
.inTable(TableName.SecretRotation)
|
|
||||||
.onDelete("CASCADE");
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,10 +25,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||||
// not a relation kept like that to keep it when rolled back
|
// not a relation kept like that to keep it when rolled back
|
||||||
t.uuid("secretVersionId").notNullable();
|
t.uuid("secretVersionId").notNullable();
|
||||||
t.foreign("secretVersionId")
|
t.foreign("secretVersionId").references("id").inTable(TableName.SecretVersion).onDelete("CASCADE");
|
||||||
.references("id")
|
|
||||||
.inTable(TableName.SecretVersion)
|
|
||||||
.onDelete("CASCADE");
|
|
||||||
t.uuid("snapshotId").notNullable();
|
t.uuid("snapshotId").notNullable();
|
||||||
t.foreign("snapshotId").references("id").inTable(TableName.Snapshot).onDelete("CASCADE");
|
t.foreign("snapshotId").references("id").inTable(TableName.Snapshot).onDelete("CASCADE");
|
||||||
t.timestamps(true, true, true);
|
t.timestamps(true, true, true);
|
||||||
@@ -42,10 +39,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||||
// not a relation kept like that to keep it when rolled back
|
// not a relation kept like that to keep it when rolled back
|
||||||
t.uuid("folderVersionId").notNullable();
|
t.uuid("folderVersionId").notNullable();
|
||||||
t.foreign("folderVersionId")
|
t.foreign("folderVersionId").references("id").inTable(TableName.SecretFolderVersion).onDelete("CASCADE");
|
||||||
.references("id")
|
|
||||||
.inTable(TableName.SecretFolderVersion)
|
|
||||||
.onDelete("CASCADE");
|
|
||||||
t.uuid("snapshotId").notNullable();
|
t.uuid("snapshotId").notNullable();
|
||||||
t.foreign("snapshotId").references("id").inTable(TableName.Snapshot).onDelete("CASCADE");
|
t.foreign("snapshotId").references("id").inTable(TableName.Snapshot).onDelete("CASCADE");
|
||||||
t.timestamps(true, true, true);
|
t.timestamps(true, true, true);
|
||||||
|
|||||||
@@ -19,6 +19,4 @@ export const IdentityOrgMembershipsSchema = z.object({
|
|||||||
|
|
||||||
export type TIdentityOrgMemberships = z.infer<typeof IdentityOrgMembershipsSchema>;
|
export type TIdentityOrgMemberships = z.infer<typeof IdentityOrgMembershipsSchema>;
|
||||||
export type TIdentityOrgMembershipsInsert = Omit<TIdentityOrgMemberships, TImmutableDBKeys>;
|
export type TIdentityOrgMembershipsInsert = Omit<TIdentityOrgMemberships, TImmutableDBKeys>;
|
||||||
export type TIdentityOrgMembershipsUpdate = Partial<
|
export type TIdentityOrgMembershipsUpdate = Partial<Omit<TIdentityOrgMemberships, TImmutableDBKeys>>;
|
||||||
Omit<TIdentityOrgMemberships, TImmutableDBKeys>
|
|
||||||
>;
|
|
||||||
|
|||||||
@@ -19,6 +19,4 @@ export const IdentityProjectMembershipsSchema = z.object({
|
|||||||
|
|
||||||
export type TIdentityProjectMemberships = z.infer<typeof IdentityProjectMembershipsSchema>;
|
export type TIdentityProjectMemberships = z.infer<typeof IdentityProjectMembershipsSchema>;
|
||||||
export type TIdentityProjectMembershipsInsert = Omit<TIdentityProjectMemberships, TImmutableDBKeys>;
|
export type TIdentityProjectMembershipsInsert = Omit<TIdentityProjectMemberships, TImmutableDBKeys>;
|
||||||
export type TIdentityProjectMembershipsUpdate = Partial<
|
export type TIdentityProjectMembershipsUpdate = Partial<Omit<TIdentityProjectMemberships, TImmutableDBKeys>>;
|
||||||
Omit<TIdentityProjectMemberships, TImmutableDBKeys>
|
|
||||||
>;
|
|
||||||
|
|||||||
@@ -24,6 +24,4 @@ export const IdentityUaClientSecretsSchema = z.object({
|
|||||||
|
|
||||||
export type TIdentityUaClientSecrets = z.infer<typeof IdentityUaClientSecretsSchema>;
|
export type TIdentityUaClientSecrets = z.infer<typeof IdentityUaClientSecretsSchema>;
|
||||||
export type TIdentityUaClientSecretsInsert = Omit<TIdentityUaClientSecrets, TImmutableDBKeys>;
|
export type TIdentityUaClientSecretsInsert = Omit<TIdentityUaClientSecrets, TImmutableDBKeys>;
|
||||||
export type TIdentityUaClientSecretsUpdate = Partial<
|
export type TIdentityUaClientSecretsUpdate = Partial<Omit<TIdentityUaClientSecrets, TImmutableDBKeys>>;
|
||||||
Omit<TIdentityUaClientSecrets, TImmutableDBKeys>
|
|
||||||
>;
|
|
||||||
|
|||||||
@@ -22,6 +22,4 @@ export const IdentityUniversalAuthsSchema = z.object({
|
|||||||
|
|
||||||
export type TIdentityUniversalAuths = z.infer<typeof IdentityUniversalAuthsSchema>;
|
export type TIdentityUniversalAuths = z.infer<typeof IdentityUniversalAuthsSchema>;
|
||||||
export type TIdentityUniversalAuthsInsert = Omit<TIdentityUniversalAuths, TImmutableDBKeys>;
|
export type TIdentityUniversalAuthsInsert = Omit<TIdentityUniversalAuths, TImmutableDBKeys>;
|
||||||
export type TIdentityUniversalAuthsUpdate = Partial<
|
export type TIdentityUniversalAuthsUpdate = Partial<Omit<TIdentityUniversalAuths, TImmutableDBKeys>>;
|
||||||
Omit<TIdentityUniversalAuths, TImmutableDBKeys>
|
|
||||||
>;
|
|
||||||
|
|||||||
@@ -15,13 +15,6 @@ export const SecretApprovalPoliciesApproversSchema = z.object({
|
|||||||
updatedAt: z.date()
|
updatedAt: z.date()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TSecretApprovalPoliciesApprovers = z.infer<
|
export type TSecretApprovalPoliciesApprovers = z.infer<typeof SecretApprovalPoliciesApproversSchema>;
|
||||||
typeof SecretApprovalPoliciesApproversSchema
|
export type TSecretApprovalPoliciesApproversInsert = Omit<TSecretApprovalPoliciesApprovers, TImmutableDBKeys>;
|
||||||
>;
|
export type TSecretApprovalPoliciesApproversUpdate = Partial<Omit<TSecretApprovalPoliciesApprovers, TImmutableDBKeys>>;
|
||||||
export type TSecretApprovalPoliciesApproversInsert = Omit<
|
|
||||||
TSecretApprovalPoliciesApprovers,
|
|
||||||
TImmutableDBKeys
|
|
||||||
>;
|
|
||||||
export type TSecretApprovalPoliciesApproversUpdate = Partial<
|
|
||||||
Omit<TSecretApprovalPoliciesApprovers, TImmutableDBKeys>
|
|
||||||
>;
|
|
||||||
|
|||||||
@@ -19,6 +19,4 @@ export const SecretApprovalPoliciesSchema = z.object({
|
|||||||
|
|
||||||
export type TSecretApprovalPolicies = z.infer<typeof SecretApprovalPoliciesSchema>;
|
export type TSecretApprovalPolicies = z.infer<typeof SecretApprovalPoliciesSchema>;
|
||||||
export type TSecretApprovalPoliciesInsert = Omit<TSecretApprovalPolicies, TImmutableDBKeys>;
|
export type TSecretApprovalPoliciesInsert = Omit<TSecretApprovalPolicies, TImmutableDBKeys>;
|
||||||
export type TSecretApprovalPoliciesUpdate = Partial<
|
export type TSecretApprovalPoliciesUpdate = Partial<Omit<TSecretApprovalPolicies, TImmutableDBKeys>>;
|
||||||
Omit<TSecretApprovalPolicies, TImmutableDBKeys>
|
|
||||||
>;
|
|
||||||
|
|||||||
@@ -15,13 +15,6 @@ export const SecretApprovalRequestSecretTagsSchema = z.object({
|
|||||||
updatedAt: z.date()
|
updatedAt: z.date()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TSecretApprovalRequestSecretTags = z.infer<
|
export type TSecretApprovalRequestSecretTags = z.infer<typeof SecretApprovalRequestSecretTagsSchema>;
|
||||||
typeof SecretApprovalRequestSecretTagsSchema
|
export type TSecretApprovalRequestSecretTagsInsert = Omit<TSecretApprovalRequestSecretTags, TImmutableDBKeys>;
|
||||||
>;
|
export type TSecretApprovalRequestSecretTagsUpdate = Partial<Omit<TSecretApprovalRequestSecretTags, TImmutableDBKeys>>;
|
||||||
export type TSecretApprovalRequestSecretTagsInsert = Omit<
|
|
||||||
TSecretApprovalRequestSecretTags,
|
|
||||||
TImmutableDBKeys
|
|
||||||
>;
|
|
||||||
export type TSecretApprovalRequestSecretTagsUpdate = Partial<
|
|
||||||
Omit<TSecretApprovalRequestSecretTags, TImmutableDBKeys>
|
|
||||||
>;
|
|
||||||
|
|||||||
@@ -16,13 +16,6 @@ export const SecretApprovalRequestsReviewersSchema = z.object({
|
|||||||
updatedAt: z.date()
|
updatedAt: z.date()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TSecretApprovalRequestsReviewers = z.infer<
|
export type TSecretApprovalRequestsReviewers = z.infer<typeof SecretApprovalRequestsReviewersSchema>;
|
||||||
typeof SecretApprovalRequestsReviewersSchema
|
export type TSecretApprovalRequestsReviewersInsert = Omit<TSecretApprovalRequestsReviewers, TImmutableDBKeys>;
|
||||||
>;
|
export type TSecretApprovalRequestsReviewersUpdate = Partial<Omit<TSecretApprovalRequestsReviewers, TImmutableDBKeys>>;
|
||||||
export type TSecretApprovalRequestsReviewersInsert = Omit<
|
|
||||||
TSecretApprovalRequestsReviewers,
|
|
||||||
TImmutableDBKeys
|
|
||||||
>;
|
|
||||||
export type TSecretApprovalRequestsReviewersUpdate = Partial<
|
|
||||||
Omit<TSecretApprovalRequestsReviewers, TImmutableDBKeys>
|
|
||||||
>;
|
|
||||||
|
|||||||
@@ -35,10 +35,5 @@ export const SecretApprovalRequestsSecretsSchema = z.object({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export type TSecretApprovalRequestsSecrets = z.infer<typeof SecretApprovalRequestsSecretsSchema>;
|
export type TSecretApprovalRequestsSecrets = z.infer<typeof SecretApprovalRequestsSecretsSchema>;
|
||||||
export type TSecretApprovalRequestsSecretsInsert = Omit<
|
export type TSecretApprovalRequestsSecretsInsert = Omit<TSecretApprovalRequestsSecrets, TImmutableDBKeys>;
|
||||||
TSecretApprovalRequestsSecrets,
|
export type TSecretApprovalRequestsSecretsUpdate = Partial<Omit<TSecretApprovalRequestsSecrets, TImmutableDBKeys>>;
|
||||||
TImmutableDBKeys
|
|
||||||
>;
|
|
||||||
export type TSecretApprovalRequestsSecretsUpdate = Partial<
|
|
||||||
Omit<TSecretApprovalRequestsSecrets, TImmutableDBKeys>
|
|
||||||
>;
|
|
||||||
|
|||||||
@@ -23,6 +23,4 @@ export const SecretApprovalRequestsSchema = z.object({
|
|||||||
|
|
||||||
export type TSecretApprovalRequests = z.infer<typeof SecretApprovalRequestsSchema>;
|
export type TSecretApprovalRequests = z.infer<typeof SecretApprovalRequestsSchema>;
|
||||||
export type TSecretApprovalRequestsInsert = Omit<TSecretApprovalRequests, TImmutableDBKeys>;
|
export type TSecretApprovalRequestsInsert = Omit<TSecretApprovalRequests, TImmutableDBKeys>;
|
||||||
export type TSecretApprovalRequestsUpdate = Partial<
|
export type TSecretApprovalRequestsUpdate = Partial<Omit<TSecretApprovalRequests, TImmutableDBKeys>>;
|
||||||
Omit<TSecretApprovalRequests, TImmutableDBKeys>
|
|
||||||
>;
|
|
||||||
|
|||||||
@@ -43,6 +43,4 @@ export const SecretScanningGitRisksSchema = z.object({
|
|||||||
|
|
||||||
export type TSecretScanningGitRisks = z.infer<typeof SecretScanningGitRisksSchema>;
|
export type TSecretScanningGitRisks = z.infer<typeof SecretScanningGitRisksSchema>;
|
||||||
export type TSecretScanningGitRisksInsert = Omit<TSecretScanningGitRisks, TImmutableDBKeys>;
|
export type TSecretScanningGitRisksInsert = Omit<TSecretScanningGitRisks, TImmutableDBKeys>;
|
||||||
export type TSecretScanningGitRisksUpdate = Partial<
|
export type TSecretScanningGitRisksUpdate = Partial<Omit<TSecretScanningGitRisks, TImmutableDBKeys>>;
|
||||||
Omit<TSecretScanningGitRisks, TImmutableDBKeys>
|
|
||||||
>;
|
|
||||||
|
|||||||
@@ -15,6 +15,4 @@ export const SecretVersionTagJunctionSchema = z.object({
|
|||||||
|
|
||||||
export type TSecretVersionTagJunction = z.infer<typeof SecretVersionTagJunctionSchema>;
|
export type TSecretVersionTagJunction = z.infer<typeof SecretVersionTagJunctionSchema>;
|
||||||
export type TSecretVersionTagJunctionInsert = Omit<TSecretVersionTagJunction, TImmutableDBKeys>;
|
export type TSecretVersionTagJunctionInsert = Omit<TSecretVersionTagJunction, TImmutableDBKeys>;
|
||||||
export type TSecretVersionTagJunctionUpdate = Partial<
|
export type TSecretVersionTagJunctionUpdate = Partial<Omit<TSecretVersionTagJunction, TImmutableDBKeys>>;
|
||||||
Omit<TSecretVersionTagJunction, TImmutableDBKeys>
|
|
||||||
>;
|
|
||||||
|
|||||||
@@ -48,14 +48,12 @@ export const generateUserSrpKeys = async (password: string) => {
|
|||||||
await new Promise((resolve) => {
|
await new Promise((resolve) => {
|
||||||
client.init({ username: seedData1.email, password: seedData1.password }, () => resolve(null));
|
client.init({ username: seedData1.email, password: seedData1.password }, () => resolve(null));
|
||||||
});
|
});
|
||||||
const { salt, verifier } = await new Promise<{ salt: string; verifier: string }>(
|
const { salt, verifier } = await new Promise<{ salt: string; verifier: string }>((resolve, reject) => {
|
||||||
(resolve, reject) => {
|
client.createVerifier((err, res) => {
|
||||||
client.createVerifier((err, res) => {
|
if (err) return reject(err);
|
||||||
if (err) return reject(err);
|
return resolve(res);
|
||||||
return resolve(res);
|
});
|
||||||
});
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
const derivedKey = await argon2.hash(password, {
|
const derivedKey = await argon2.hash(password, {
|
||||||
salt: Buffer.from(salt),
|
salt: Buffer.from(salt),
|
||||||
memoryCost: 65536,
|
memoryCost: 65536,
|
||||||
|
|||||||
@@ -45,7 +45,5 @@ export async function seed(knex: Knex): Promise<void> {
|
|||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
.returning("*");
|
.returning("*");
|
||||||
await knex(TableName.SecretFolder).insert(
|
await knex(TableName.SecretFolder).insert(envs.map(({ id }) => ({ name: "root", envId: id, parentId: null })));
|
||||||
envs.map(({ id }) => ({ name: "root", envId: id, parentId: null }))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,7 @@ import { Knex } from "knex";
|
|||||||
|
|
||||||
import { TableName } from "./schemas";
|
import { TableName } from "./schemas";
|
||||||
|
|
||||||
export const createJunctionTable = (
|
export const createJunctionTable = (knex: Knex, tableName: TableName, table1Name: TableName, table2Name: TableName) =>
|
||||||
knex: Knex,
|
|
||||||
tableName: TableName,
|
|
||||||
table1Name: TableName,
|
|
||||||
table2Name: TableName
|
|
||||||
) =>
|
|
||||||
knex.schema.createTable(tableName, (table) => {
|
knex.schema.createTable(tableName, (table) => {
|
||||||
table.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
table.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
table.uuid(`${table1Name}Id`).unsigned().notNullable(); // Foreign key for table1
|
table.uuid(`${table1Name}Id`).unsigned().notNullable(); // Foreign key for table1
|
||||||
|
|||||||
@@ -26,11 +26,7 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const role = await server.services.orgRole.createRole(
|
const role = await server.services.orgRole.createRole(req.permission.id, req.params.organizationId, req.body);
|
||||||
req.permission.id,
|
|
||||||
req.params.organizationId,
|
|
||||||
req.body
|
|
||||||
);
|
|
||||||
return { role };
|
return { role };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -111,10 +107,7 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const roles = await server.services.orgRole.listRoles(
|
const roles = await server.services.orgRole.listRoles(req.permission.id, req.params.organizationId);
|
||||||
req.permission.id,
|
|
||||||
req.params.organizationId
|
|
||||||
);
|
|
||||||
return { data: { roles } };
|
return { data: { roles } };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -82,9 +82,9 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
|
|||||||
const serverCfg = getServerCfg();
|
const serverCfg = getServerCfg();
|
||||||
if (!profile) throw new BadRequestError({ message: "Missing profile" });
|
if (!profile) throw new BadRequestError({ message: "Missing profile" });
|
||||||
const { firstName } = profile;
|
const { firstName } = profile;
|
||||||
const email = profile?.email ?? profile?.emailAddress as string // emailRippling is added because in Rippling the field `email` reserved
|
const email = profile?.email ?? (profile?.emailAddress as string); // emailRippling is added because in Rippling the field `email` reserved
|
||||||
|
|
||||||
if (!email || !firstName){
|
if (!email || !firstName) {
|
||||||
throw new BadRequestError({ message: "Invalid request. Missing email or first name" });
|
throw new BadRequestError({ message: "Invalid request. Missing email or first name" });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,15 +150,11 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
|
|||||||
handler: (req, res) => {
|
handler: (req, res) => {
|
||||||
if (req.passportUser.isUserCompleted) {
|
if (req.passportUser.isUserCompleted) {
|
||||||
return res.redirect(
|
return res.redirect(
|
||||||
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(
|
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
|
||||||
req.passportUser.providerAuthToken
|
|
||||||
)}`
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return res.redirect(
|
return res.redirect(
|
||||||
`${appCfg.SITE_URL}/signup/sso?token=${encodeURIComponent(
|
`${appCfg.SITE_URL}/signup/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
|
||||||
req.passportUser.providerAuthToken
|
|
||||||
)}`
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -117,12 +117,11 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const approvals =
|
const approvals = await server.services.secretApprovalPolicy.getSecretApprovalPolicyByProjectId({
|
||||||
await server.services.secretApprovalPolicy.getSecretApprovalPolicyByProjectId({
|
actor: req.permission.type,
|
||||||
actor: req.permission.type,
|
actorId: req.permission.id,
|
||||||
actorId: req.permission.id,
|
projectId: req.query.workspaceId
|
||||||
projectId: req.query.workspaceId
|
});
|
||||||
});
|
|
||||||
return { approvals };
|
return { approvals };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,10 +9,7 @@ import {
|
|||||||
SecretVersionsSchema
|
SecretVersionsSchema
|
||||||
} from "@app/db/schemas";
|
} from "@app/db/schemas";
|
||||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import {
|
import { ApprovalStatus, RequestState } from "@app/ee/services/secret-approval-request/secret-approval-request-types";
|
||||||
ApprovalStatus,
|
|
||||||
RequestState
|
|
||||||
} from "@app/ee/services/secret-approval-request/secret-approval-request-types";
|
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
@@ -41,9 +38,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
|
|||||||
approvers: z.string().array(),
|
approvers: z.string().array(),
|
||||||
secretPath: z.string().optional().nullable()
|
secretPath: z.string().optional().nullable()
|
||||||
}),
|
}),
|
||||||
commits: z
|
commits: z.object({ op: z.string(), secretId: z.string().nullable().optional() }).array(),
|
||||||
.object({ op: z.string(), secretId: z.string().nullable().optional() })
|
|
||||||
.array(),
|
|
||||||
environment: z.string(),
|
environment: z.string(),
|
||||||
reviewers: z.object({ member: z.string(), status: z.string() }).array(),
|
reviewers: z.object({ member: z.string(), status: z.string() }).array(),
|
||||||
approvers: z.string().array()
|
approvers: z.string().array()
|
||||||
@@ -176,8 +171,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
|
|||||||
type: isClosing ? EventType.SECRET_APPROVAL_CLOSED : EventType.SECRET_APPROVAL_REOPENED,
|
type: isClosing ? EventType.SECRET_APPROVAL_CLOSED : EventType.SECRET_APPROVAL_REOPENED,
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
metadata: {
|
metadata: {
|
||||||
[isClosing ? ("closedBy" as const) : ("reopenedBy" as const)]:
|
[isClosing ? ("closedBy" as const) : ("reopenedBy" as const)]: approval.statusChangeBy as string,
|
||||||
approval.statusChangeBy as string,
|
|
||||||
secretApprovalRequestId: approval.id,
|
secretApprovalRequestId: approval.id,
|
||||||
secretApprovalRequestSlug: approval.slug
|
secretApprovalRequestSlug: approval.slug
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
|
|||||||
@@ -62,12 +62,11 @@ export const registerSecretScanningRouter = async (server: FastifyZodProvider) =
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const appInstallationCompleted =
|
const appInstallationCompleted = await server.services.secretScanning.getOrgInstallationStatus({
|
||||||
await server.services.secretScanning.getOrgInstallationStatus({
|
actor: req.permission.type,
|
||||||
actor: req.permission.type,
|
actorId: req.permission.id,
|
||||||
actorId: req.permission.id,
|
orgId: req.params.organizationId
|
||||||
orgId: req.params.organizationId
|
});
|
||||||
});
|
|
||||||
return { appInstallationCompleted };
|
return { appInstallationCompleted };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -22,17 +22,7 @@ export const auditLogDALFactory = (db: TDbClient) => {
|
|||||||
const auditLogOrm = ormify(db, TableName.AuditLog);
|
const auditLogOrm = ormify(db, TableName.AuditLog);
|
||||||
|
|
||||||
const find = async (
|
const find = async (
|
||||||
{
|
{ orgId, projectId, userAgentType, startDate, endDate, limit = 20, offset = 0, actor, eventType }: TFindQuery,
|
||||||
orgId,
|
|
||||||
projectId,
|
|
||||||
userAgentType,
|
|
||||||
startDate,
|
|
||||||
endDate,
|
|
||||||
limit = 20,
|
|
||||||
offset = 0,
|
|
||||||
actor,
|
|
||||||
eventType
|
|
||||||
}: TFindQuery,
|
|
||||||
tx?: Knex
|
tx?: Knex
|
||||||
) => {
|
) => {
|
||||||
const sqlQuery = (tx || db)(TableName.AuditLog)
|
const sqlQuery = (tx || db)(TableName.AuditLog)
|
||||||
|
|||||||
@@ -34,10 +34,7 @@ export const auditLogServiceFactory = ({
|
|||||||
auditLogActor
|
auditLogActor
|
||||||
}: TListProjectAuditLogDTO) => {
|
}: TListProjectAuditLogDTO) => {
|
||||||
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.AuditLogs);
|
||||||
ProjectPermissionActions.Read,
|
|
||||||
ProjectPermissionSub.AuditLogs
|
|
||||||
);
|
|
||||||
const auditLogs = await auditLogDAL.find({
|
const auditLogs = await auditLogDAL.find({
|
||||||
startDate,
|
startDate,
|
||||||
endDate,
|
endDate,
|
||||||
@@ -48,20 +45,17 @@ export const auditLogServiceFactory = ({
|
|||||||
actor: auditLogActor,
|
actor: auditLogActor,
|
||||||
projectId
|
projectId
|
||||||
});
|
});
|
||||||
return auditLogs.map(
|
return auditLogs.map(({ eventType: logEventType, actor: eActor, actorMetadata, eventMetadata, ...el }) => ({
|
||||||
({ eventType: logEventType, actor: eActor, actorMetadata, eventMetadata, ...el }) => ({
|
...el,
|
||||||
...el,
|
event: { type: logEventType, metadata: eventMetadata },
|
||||||
event: { type: logEventType, metadata: eventMetadata },
|
actor: { type: eActor, metadata: actorMetadata }
|
||||||
actor: { type: eActor, metadata: actorMetadata }
|
}));
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const createAuditLog = async (data: TCreateAuditLogDTO) => {
|
const createAuditLog = async (data: TCreateAuditLogDTO) => {
|
||||||
// add all cases in which project id or org id cannot be added
|
// add all cases in which project id or org id cannot be added
|
||||||
if (data.event.type !== EventType.LOGIN_IDENTITY_UNIVERSAL_AUTH) {
|
if (data.event.type !== EventType.LOGIN_IDENTITY_UNIVERSAL_AUTH) {
|
||||||
if (!data.projectId && !data.orgId)
|
if (!data.projectId && !data.orgId) throw new BadRequestError({ message: "Must either project id or org id" });
|
||||||
throw new BadRequestError({ message: "Must either project id or org id" });
|
|
||||||
}
|
}
|
||||||
return auditLogQueue.pushToLog(data);
|
return auditLogQueue.pushToLog(data);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,11 +31,7 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({
|
|||||||
secretRotation: true
|
secretRotation: true
|
||||||
});
|
});
|
||||||
|
|
||||||
export const setupLicenceRequestWithStore = (
|
export const setupLicenceRequestWithStore = (baseURL: string, refreshUrl: string, licenseKey: string) => {
|
||||||
baseURL: string,
|
|
||||||
refreshUrl: string,
|
|
||||||
licenseKey: string
|
|
||||||
) => {
|
|
||||||
let token: string;
|
let token: string;
|
||||||
const licenceReq = axios.create({
|
const licenceReq = axios.create({
|
||||||
baseURL,
|
baseURL,
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
InstanceType,
|
InstanceType,
|
||||||
TAddOrgPmtMethodDTO,
|
TAddOrgPmtMethodDTO,
|
||||||
TAddOrgTaxIdDTO,
|
TAddOrgTaxIdDTO,
|
||||||
|
TCreateOrgPortalSession,
|
||||||
TDelOrgPmtMethodDTO,
|
TDelOrgPmtMethodDTO,
|
||||||
TDelOrgTaxIdDTO,
|
TDelOrgTaxIdDTO,
|
||||||
TFeatureSet,
|
TFeatureSet,
|
||||||
@@ -31,7 +32,6 @@ import {
|
|||||||
TOrgPlansTableDTO,
|
TOrgPlansTableDTO,
|
||||||
TOrgPmtMethodsDTO,
|
TOrgPmtMethodsDTO,
|
||||||
TStartOrgTrialDTO,
|
TStartOrgTrialDTO,
|
||||||
TCreateOrgPortalSession,
|
|
||||||
TUpdateOrgBillingDetailsDTO
|
TUpdateOrgBillingDetailsDTO
|
||||||
} from "./license-types";
|
} from "./license-types";
|
||||||
|
|
||||||
@@ -47,11 +47,7 @@ const LICENSE_SERVER_CLOUD_LOGIN = "/api/auth/v1/license-server-login";
|
|||||||
const LICENSE_SERVER_ON_PREM_LOGIN = "/api/auth/v1/licence-login";
|
const LICENSE_SERVER_ON_PREM_LOGIN = "/api/auth/v1/licence-login";
|
||||||
|
|
||||||
const FEATURE_CACHE_KEY = (orgId: string, projectId?: string) => `${orgId}-${projectId || ""}`;
|
const FEATURE_CACHE_KEY = (orgId: string, projectId?: string) => `${orgId}-${projectId || ""}`;
|
||||||
export const licenseServiceFactory = ({
|
export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }: TLicenseServiceFactoryDep) => {
|
||||||
orgDAL,
|
|
||||||
permissionService,
|
|
||||||
licenseDAL
|
|
||||||
}: TLicenseServiceFactoryDep) => {
|
|
||||||
let isValidLicense = false;
|
let isValidLicense = false;
|
||||||
let instanceType = InstanceType.OnPrem;
|
let instanceType = InstanceType.OnPrem;
|
||||||
let onPremFeatures: TFeatureSet = getDefaultOnPremFeatures();
|
let onPremFeatures: TFeatureSet = getDefaultOnPremFeatures();
|
||||||
@@ -84,9 +80,7 @@ export const licenseServiceFactory = ({
|
|||||||
if (token) {
|
if (token) {
|
||||||
const {
|
const {
|
||||||
data: { currentPlan }
|
data: { currentPlan }
|
||||||
} = await licenseServerOnPremApi.request.get<{ currentPlan: TFeatureSet }>(
|
} = await licenseServerOnPremApi.request.get<{ currentPlan: TFeatureSet }>("/api/license/v1/plan");
|
||||||
"/api/license/v1/plan"
|
|
||||||
);
|
|
||||||
onPremFeatures = currentPlan;
|
onPremFeatures = currentPlan;
|
||||||
instanceType = InstanceType.EnterpriseOnPrem;
|
instanceType = InstanceType.EnterpriseOnPrem;
|
||||||
logger.info(`Instance type: ${InstanceType.EnterpriseOnPrem}`);
|
logger.info(`Instance type: ${InstanceType.EnterpriseOnPrem}`);
|
||||||
@@ -168,12 +162,9 @@ export const licenseServiceFactory = ({
|
|||||||
|
|
||||||
const count = await licenseDAL.countOfOrgMembers(orgId);
|
const count = await licenseDAL.countOfOrgMembers(orgId);
|
||||||
if (org?.customerId) {
|
if (org?.customerId) {
|
||||||
await licenseServerCloudApi.request.patch(
|
await licenseServerCloudApi.request.patch(`/api/license-server/v1/customers/${org.customerId}/cloud-plan`, {
|
||||||
`/api/license-server/v1/customers/${org.customerId}/cloud-plan`,
|
quantity: count
|
||||||
{
|
});
|
||||||
quantity: count
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
featureStore.del(orgId);
|
featureStore.del(orgId);
|
||||||
} else if (instanceType === InstanceType.EnterpriseOnPrem) {
|
} else if (instanceType === InstanceType.EnterpriseOnPrem) {
|
||||||
@@ -184,17 +175,9 @@ export const licenseServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
// below all are api calls
|
// below all are api calls
|
||||||
const getOrgPlansTableByBillCycle = async ({
|
const getOrgPlansTableByBillCycle = async ({ orgId, actor, actorId, billingCycle }: TOrgPlansTableDTO) => {
|
||||||
orgId,
|
|
||||||
actor,
|
|
||||||
actorId,
|
|
||||||
billingCycle
|
|
||||||
}: TOrgPlansTableDTO) => {
|
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||||
OrgPermissionActions.Read,
|
|
||||||
OrgPermissionSubjects.Billing
|
|
||||||
);
|
|
||||||
const { data } = await licenseServerCloudApi.request.get(
|
const { data } = await licenseServerCloudApi.request.get(
|
||||||
`/api/license-server/v1/cloud-products?billing-cycle=${billingCycle}`
|
`/api/license-server/v1/cloud-products?billing-cycle=${billingCycle}`
|
||||||
);
|
);
|
||||||
@@ -203,24 +186,15 @@ export const licenseServiceFactory = ({
|
|||||||
|
|
||||||
const getOrgPlan = async ({ orgId, actor, actorId, projectId }: TOrgPlanDTO) => {
|
const getOrgPlan = async ({ orgId, actor, actorId, projectId }: TOrgPlanDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||||
OrgPermissionActions.Read,
|
|
||||||
OrgPermissionSubjects.Billing
|
|
||||||
);
|
|
||||||
const plan = await getPlan(orgId, projectId);
|
const plan = await getPlan(orgId, projectId);
|
||||||
return plan;
|
return plan;
|
||||||
};
|
};
|
||||||
|
|
||||||
const startOrgTrial = async ({ orgId, actorId, actor, success_url }: TStartOrgTrialDTO) => {
|
const startOrgTrial = async ({ orgId, actorId, actor, success_url }: TStartOrgTrialDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Billing);
|
||||||
OrgPermissionActions.Create,
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Billing);
|
||||||
OrgPermissionSubjects.Billing
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
OrgPermissionActions.Edit,
|
|
||||||
OrgPermissionSubjects.Billing
|
|
||||||
);
|
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findOrgById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
@@ -241,14 +215,8 @@ export const licenseServiceFactory = ({
|
|||||||
|
|
||||||
const createOrganizationPortalSession = async ({ orgId, actorId, actor }: TCreateOrgPortalSession) => {
|
const createOrganizationPortalSession = async ({ orgId, actorId, actor }: TCreateOrgPortalSession) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Billing);
|
||||||
OrgPermissionActions.Create,
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Billing);
|
||||||
OrgPermissionSubjects.Billing
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
OrgPermissionActions.Edit,
|
|
||||||
OrgPermissionSubjects.Billing
|
|
||||||
);
|
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findOrgById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
@@ -259,7 +227,7 @@ export const licenseServiceFactory = ({
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
data: { pmtMethods }
|
data: { pmtMethods }
|
||||||
} = await licenseServerCloudApi.request.get(
|
} = await licenseServerCloudApi.request.get<{ pmtMethods: string[] }>(
|
||||||
`/api/license-server/v1/customers/${organization.customerId}/billing-details/payment-methods`
|
`/api/license-server/v1/customers/${organization.customerId}/billing-details/payment-methods`
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -271,34 +239,30 @@ export const licenseServiceFactory = ({
|
|||||||
} = await licenseServerCloudApi.request.post(
|
} = await licenseServerCloudApi.request.post(
|
||||||
`/api/license-server/v1/customers/${organization.customerId}/billing-details/payment-methods`,
|
`/api/license-server/v1/customers/${organization.customerId}/billing-details/payment-methods`,
|
||||||
{
|
{
|
||||||
success_url: appCfg.SITE_URL + "/dashboard",
|
success_url: `${appCfg.SITE_URL}/dashboard`,
|
||||||
cancel_url: appCfg.SITE_URL + "/dashboard"
|
cancel_url: `${appCfg.SITE_URL}/dashboard`
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return { url };
|
|
||||||
} else {
|
|
||||||
// case: organization has payment method on file
|
|
||||||
// -> redirect to billing portal
|
|
||||||
const {
|
|
||||||
data: { url }
|
|
||||||
} = await licenseServerCloudApi.request.post(
|
|
||||||
`/api/license-server/v1/customers/${organization.customerId}/billing-details/billing-portal`,
|
|
||||||
{
|
|
||||||
return_url: appCfg.SITE_URL + "/dashboard"
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return { url };
|
return { url };
|
||||||
}
|
}
|
||||||
}
|
// case: organization has payment method on file
|
||||||
|
// -> redirect to billing portal
|
||||||
|
const {
|
||||||
|
data: { url }
|
||||||
|
} = await licenseServerCloudApi.request.post(
|
||||||
|
`/api/license-server/v1/customers/${organization.customerId}/billing-details/billing-portal`,
|
||||||
|
{
|
||||||
|
return_url: `${appCfg.SITE_URL}/dashboard`
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return { url };
|
||||||
|
};
|
||||||
|
|
||||||
const getOrgBillingInfo = async ({ orgId, actor, actorId }: TGetOrgBillInfoDTO) => {
|
const getOrgBillingInfo = async ({ orgId, actor, actorId }: TGetOrgBillInfoDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||||
OrgPermissionActions.Read,
|
|
||||||
OrgPermissionSubjects.Billing
|
|
||||||
);
|
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findOrgById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
@@ -315,10 +279,7 @@ export const licenseServiceFactory = ({
|
|||||||
// returns org current plan feature table
|
// returns org current plan feature table
|
||||||
const getOrgPlanTable = async ({ orgId, actor, actorId }: TGetOrgBillInfoDTO) => {
|
const getOrgPlanTable = async ({ orgId, actor, actorId }: TGetOrgBillInfoDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||||
OrgPermissionActions.Read,
|
|
||||||
OrgPermissionSubjects.Billing
|
|
||||||
);
|
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findOrgById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
@@ -334,10 +295,7 @@ export const licenseServiceFactory = ({
|
|||||||
|
|
||||||
const getOrgBillingDetails = async ({ orgId, actor, actorId }: TGetOrgBillInfoDTO) => {
|
const getOrgBillingDetails = async ({ orgId, actor, actorId }: TGetOrgBillInfoDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||||
OrgPermissionActions.Read,
|
|
||||||
OrgPermissionSubjects.Billing
|
|
||||||
);
|
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findOrgById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
@@ -352,18 +310,9 @@ export const licenseServiceFactory = ({
|
|||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateOrgBillingDetails = async ({
|
const updateOrgBillingDetails = async ({ actorId, actor, orgId, name, email }: TUpdateOrgBillingDetailsDTO) => {
|
||||||
actorId,
|
|
||||||
actor,
|
|
||||||
orgId,
|
|
||||||
name,
|
|
||||||
email
|
|
||||||
}: TUpdateOrgBillingDetailsDTO) => {
|
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||||
OrgPermissionActions.Read,
|
|
||||||
OrgPermissionSubjects.Billing
|
|
||||||
);
|
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findOrgById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
@@ -383,10 +332,7 @@ export const licenseServiceFactory = ({
|
|||||||
|
|
||||||
const getOrgPmtMethods = async ({ orgId, actor, actorId }: TOrgPmtMethodsDTO) => {
|
const getOrgPmtMethods = async ({ orgId, actor, actorId }: TOrgPmtMethodsDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||||
OrgPermissionActions.Read,
|
|
||||||
OrgPermissionSubjects.Billing
|
|
||||||
);
|
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findOrgById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
@@ -403,18 +349,9 @@ export const licenseServiceFactory = ({
|
|||||||
return pmtMethods;
|
return pmtMethods;
|
||||||
};
|
};
|
||||||
|
|
||||||
const addOrgPmtMethods = async ({
|
const addOrgPmtMethods = async ({ orgId, actor, actorId, success_url, cancel_url }: TAddOrgPmtMethodDTO) => {
|
||||||
orgId,
|
|
||||||
actor,
|
|
||||||
actorId,
|
|
||||||
success_url,
|
|
||||||
cancel_url
|
|
||||||
}: TAddOrgPmtMethodDTO) => {
|
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||||
OrgPermissionActions.Read,
|
|
||||||
OrgPermissionSubjects.Billing
|
|
||||||
);
|
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findOrgById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
@@ -436,10 +373,7 @@ export const licenseServiceFactory = ({
|
|||||||
|
|
||||||
const delOrgPmtMethods = async ({ actorId, actor, orgId, pmtMethodId }: TDelOrgPmtMethodDTO) => {
|
const delOrgPmtMethods = async ({ actorId, actor, orgId, pmtMethodId }: TDelOrgPmtMethodDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||||
OrgPermissionActions.Read,
|
|
||||||
OrgPermissionSubjects.Billing
|
|
||||||
);
|
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findOrgById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
@@ -456,10 +390,7 @@ export const licenseServiceFactory = ({
|
|||||||
|
|
||||||
const getOrgTaxIds = async ({ orgId, actor, actorId }: TGetOrgTaxIdDTO) => {
|
const getOrgTaxIds = async ({ orgId, actor, actorId }: TGetOrgTaxIdDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||||
OrgPermissionActions.Read,
|
|
||||||
OrgPermissionSubjects.Billing
|
|
||||||
);
|
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findOrgById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
@@ -477,10 +408,7 @@ export const licenseServiceFactory = ({
|
|||||||
|
|
||||||
const addOrgTaxId = async ({ actorId, actor, orgId, type, value }: TAddOrgTaxIdDTO) => {
|
const addOrgTaxId = async ({ actorId, actor, orgId, type, value }: TAddOrgTaxIdDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||||
OrgPermissionActions.Read,
|
|
||||||
OrgPermissionSubjects.Billing
|
|
||||||
);
|
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findOrgById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
@@ -501,10 +429,7 @@ export const licenseServiceFactory = ({
|
|||||||
|
|
||||||
const delOrgTaxId = async ({ orgId, actor, actorId, taxId }: TDelOrgTaxIdDTO) => {
|
const delOrgTaxId = async ({ orgId, actor, actorId, taxId }: TDelOrgTaxIdDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||||
OrgPermissionActions.Read,
|
|
||||||
OrgPermissionSubjects.Billing
|
|
||||||
);
|
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findOrgById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
@@ -521,10 +446,7 @@ export const licenseServiceFactory = ({
|
|||||||
|
|
||||||
const getOrgTaxInvoices = async ({ actorId, actor, orgId }: TOrgInvoiceDTO) => {
|
const getOrgTaxInvoices = async ({ actorId, actor, orgId }: TOrgInvoiceDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||||
OrgPermissionActions.Read,
|
|
||||||
OrgPermissionSubjects.Billing
|
|
||||||
);
|
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findOrgById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
@@ -535,18 +457,13 @@ export const licenseServiceFactory = ({
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
data: { invoices }
|
data: { invoices }
|
||||||
} = await licenseServerCloudApi.request.get(
|
} = await licenseServerCloudApi.request.get(`/api/license-server/v1/customers/${organization.customerId}/invoices`);
|
||||||
`/api/license-server/v1/customers/${organization.customerId}/invoices`
|
|
||||||
);
|
|
||||||
return invoices;
|
return invoices;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getOrgLicenses = async ({ orgId, actor, actorId }: TOrgLicensesDTO) => {
|
const getOrgLicenses = async ({ orgId, actor, actorId }: TOrgLicensesDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
|
||||||
OrgPermissionActions.Read,
|
|
||||||
OrgPermissionSubjects.Billing
|
|
||||||
);
|
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findOrgById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
@@ -557,9 +474,7 @@ export const licenseServiceFactory = ({
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
data: { licenses }
|
data: { licenses }
|
||||||
} = await licenseServerCloudApi.request.get(
|
} = await licenseServerCloudApi.request.get(`/api/license-server/v1/customers/${organization.customerId}/licenses`);
|
||||||
`/api/license-server/v1/customers/${organization.customerId}/licenses`
|
|
||||||
);
|
|
||||||
return licenses;
|
return licenses;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -9,11 +9,7 @@ export const permissionDALFactory = (db: TDbClient) => {
|
|||||||
const getOrgPermission = async (userId: string, orgId: string) => {
|
const getOrgPermission = async (userId: string, orgId: string) => {
|
||||||
try {
|
try {
|
||||||
const membership = await db(TableName.OrgMembership)
|
const membership = await db(TableName.OrgMembership)
|
||||||
.leftJoin(
|
.leftJoin(TableName.OrgRoles, `${TableName.OrgMembership}.roleId`, `${TableName.OrgRoles}.id`)
|
||||||
TableName.OrgRoles,
|
|
||||||
`${TableName.OrgMembership}.roleId`,
|
|
||||||
`${TableName.OrgRoles}.id`
|
|
||||||
)
|
|
||||||
.where("userId", userId)
|
.where("userId", userId)
|
||||||
.where(`${TableName.OrgMembership}.orgId`, orgId)
|
.where(`${TableName.OrgMembership}.orgId`, orgId)
|
||||||
.select("permissions")
|
.select("permissions")
|
||||||
@@ -29,11 +25,7 @@ export const permissionDALFactory = (db: TDbClient) => {
|
|||||||
const getOrgIdentityPermission = async (identityId: string, orgId: string) => {
|
const getOrgIdentityPermission = async (identityId: string, orgId: string) => {
|
||||||
try {
|
try {
|
||||||
const membership = await db(TableName.IdentityOrgMembership)
|
const membership = await db(TableName.IdentityOrgMembership)
|
||||||
.leftJoin(
|
.leftJoin(TableName.OrgRoles, `${TableName.IdentityOrgMembership}.roleId`, `${TableName.OrgRoles}.id`)
|
||||||
TableName.OrgRoles,
|
|
||||||
`${TableName.IdentityOrgMembership}.roleId`,
|
|
||||||
`${TableName.OrgRoles}.id`
|
|
||||||
)
|
|
||||||
.where("identityId", identityId)
|
.where("identityId", identityId)
|
||||||
.where(`${TableName.IdentityOrgMembership}.orgId`, orgId)
|
.where(`${TableName.IdentityOrgMembership}.orgId`, orgId)
|
||||||
.select(selectAllTableCols(TableName.IdentityOrgMembership))
|
.select(selectAllTableCols(TableName.IdentityOrgMembership))
|
||||||
@@ -48,11 +40,7 @@ export const permissionDALFactory = (db: TDbClient) => {
|
|||||||
const getProjectPermission = async (userId: string, projectId: string) => {
|
const getProjectPermission = async (userId: string, projectId: string) => {
|
||||||
try {
|
try {
|
||||||
const membership = await db(TableName.ProjectMembership)
|
const membership = await db(TableName.ProjectMembership)
|
||||||
.leftJoin(
|
.leftJoin(TableName.ProjectRoles, `${TableName.ProjectMembership}.roleId`, `${TableName.ProjectRoles}.id`)
|
||||||
TableName.ProjectRoles,
|
|
||||||
`${TableName.ProjectMembership}.roleId`,
|
|
||||||
`${TableName.ProjectRoles}.id`
|
|
||||||
)
|
|
||||||
.where("userId", userId)
|
.where("userId", userId)
|
||||||
.where(`${TableName.ProjectMembership}.projectId`, projectId)
|
.where(`${TableName.ProjectMembership}.projectId`, projectId)
|
||||||
.select(selectAllTableCols(TableName.ProjectMembership))
|
.select(selectAllTableCols(TableName.ProjectMembership))
|
||||||
|
|||||||
@@ -16,12 +16,7 @@ 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 { TServiceTokenDALFactory } from "@app/services/service-token/service-token-dal";
|
||||||
|
|
||||||
import {
|
import { orgAdminPermissions, orgMemberPermissions, orgNoAccessPermissions, OrgPermissionSet } from "./org-permission";
|
||||||
orgAdminPermissions,
|
|
||||||
orgMemberPermissions,
|
|
||||||
orgNoAccessPermissions,
|
|
||||||
OrgPermissionSet
|
|
||||||
} from "./org-permission";
|
|
||||||
import { TPermissionDALFactory } from "./permission-dal";
|
import { TPermissionDALFactory } from "./permission-dal";
|
||||||
import {
|
import {
|
||||||
buildServiceTokenProjectPermission,
|
buildServiceTokenProjectPermission,
|
||||||
@@ -188,9 +183,9 @@ export const permissionServiceFactory = ({
|
|||||||
? { permission: MongoAbility<ProjectPermissionSet, MongoQuery>; membership: undefined }
|
? { permission: MongoAbility<ProjectPermissionSet, MongoQuery>; membership: undefined }
|
||||||
: {
|
: {
|
||||||
permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
|
permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
|
||||||
membership: (T extends ActorType.USER
|
membership: (T extends ActorType.USER ? TProjectMemberships : TIdentityProjectMemberships) & {
|
||||||
? TProjectMemberships
|
permissions?: unknown;
|
||||||
: TIdentityProjectMemberships) & { permissions?: unknown };
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const getProjectPermission = async <T extends ActorType>(
|
const getProjectPermission = async <T extends ActorType>(
|
||||||
@@ -214,9 +209,7 @@ export const permissionServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getProjectPermissionByRole = async (role: string, projectId: string) => {
|
const getProjectPermissionByRole = async (role: string, projectId: string) => {
|
||||||
const isCustomRole = !Object.values(ProjectMembershipRole).includes(
|
const isCustomRole = !Object.values(ProjectMembershipRole).includes(role as ProjectMembershipRole);
|
||||||
role as ProjectMembershipRole
|
|
||||||
);
|
|
||||||
if (isCustomRole) {
|
if (isCustomRole) {
|
||||||
const projectRole = await projectRoleDAL.findOne({ slug: role, projectId });
|
const projectRole = await projectRoleDAL.findOne({ slug: role, projectId });
|
||||||
if (!projectRole) throw new BadRequestError({ message: "Role not found" });
|
if (!projectRole) throw new BadRequestError({ message: "Role not found" });
|
||||||
|
|||||||
@@ -38,10 +38,7 @@ import {
|
|||||||
type TSamlConfigServiceFactoryDep = {
|
type TSamlConfigServiceFactoryDep = {
|
||||||
samlConfigDAL: TSamlConfigDALFactory;
|
samlConfigDAL: TSamlConfigDALFactory;
|
||||||
userDAL: Pick<TUserDALFactory, "create" | "findUserByEmail" | "transaction" | "updateById">;
|
userDAL: Pick<TUserDALFactory, "create" | "findUserByEmail" | "transaction" | "updateById">;
|
||||||
orgDAL: Pick<
|
orgDAL: Pick<TOrgDALFactory, "createMembership" | "updateMembershipById" | "findMembership" | "findOrgById">;
|
||||||
TOrgDALFactory,
|
|
||||||
"createMembership" | "updateMembershipById" | "findMembership" | "findOrgById"
|
|
||||||
>;
|
|
||||||
orgBotDAL: Pick<TOrgBotDALFactory, "findOne" | "create" | "transaction">;
|
orgBotDAL: Pick<TOrgBotDALFactory, "findOne" | "create" | "transaction">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
@@ -68,10 +65,7 @@ export const samlConfigServiceFactory = ({
|
|||||||
authProvider
|
authProvider
|
||||||
}: TCreateSamlCfgDTO) => {
|
}: TCreateSamlCfgDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Sso);
|
||||||
OrgPermissionActions.Create,
|
|
||||||
OrgPermissionSubjects.Sso
|
|
||||||
);
|
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(orgId);
|
const plan = await licenseService.getPlan(orgId);
|
||||||
if (!plan.samlSSO)
|
if (!plan.samlSSO)
|
||||||
@@ -128,16 +122,8 @@ export const samlConfigServiceFactory = ({
|
|||||||
keyEncoding: orgBot.symmetricKeyKeyEncoding as SecretKeyEncoding
|
keyEncoding: orgBot.symmetricKeyKeyEncoding as SecretKeyEncoding
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const { ciphertext: encryptedEntryPoint, iv: entryPointIV, tag: entryPointTag } = encryptSymmetric(entryPoint, key);
|
||||||
ciphertext: encryptedEntryPoint,
|
const { ciphertext: encryptedIssuer, iv: issuerIV, tag: issuerTag } = encryptSymmetric(issuer, key);
|
||||||
iv: entryPointIV,
|
|
||||||
tag: entryPointTag
|
|
||||||
} = encryptSymmetric(entryPoint, key);
|
|
||||||
const {
|
|
||||||
ciphertext: encryptedIssuer,
|
|
||||||
iv: issuerIV,
|
|
||||||
tag: issuerTag
|
|
||||||
} = encryptSymmetric(issuer, key);
|
|
||||||
|
|
||||||
const { ciphertext: encryptedCert, iv: certIV, tag: certTag } = encryptSymmetric(cert, key);
|
const { ciphertext: encryptedCert, iv: certIV, tag: certTag } = encryptSymmetric(cert, key);
|
||||||
const samlConfig = await samlConfigDAL.create({
|
const samlConfig = await samlConfigDAL.create({
|
||||||
@@ -168,10 +154,7 @@ export const samlConfigServiceFactory = ({
|
|||||||
authProvider
|
authProvider
|
||||||
}: TUpdateSamlCfgDTO) => {
|
}: TUpdateSamlCfgDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Sso);
|
||||||
OrgPermissionActions.Edit,
|
|
||||||
OrgPermissionSubjects.Sso
|
|
||||||
);
|
|
||||||
const plan = await licenseService.getPlan(orgId);
|
const plan = await licenseService.getPlan(orgId);
|
||||||
if (!plan.samlSSO)
|
if (!plan.samlSSO)
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -181,8 +164,7 @@ export const samlConfigServiceFactory = ({
|
|||||||
|
|
||||||
const updateQuery: TSamlConfigsUpdate = { authProvider, isActive };
|
const updateQuery: TSamlConfigsUpdate = { authProvider, isActive };
|
||||||
const orgBot = await orgBotDAL.findOne({ orgId });
|
const orgBot = await orgBotDAL.findOne({ orgId });
|
||||||
if (!orgBot)
|
if (!orgBot) throw new BadRequestError({ message: "Org bot not found", name: "OrgBotNotFound" });
|
||||||
throw new BadRequestError({ message: "Org bot not found", name: "OrgBotNotFound" });
|
|
||||||
const key = infisicalSymmetricDecrypt({
|
const key = infisicalSymmetricDecrypt({
|
||||||
ciphertext: orgBot.encryptedSymmetricKey,
|
ciphertext: orgBot.encryptedSymmetricKey,
|
||||||
iv: orgBot.symmetricKeyIV,
|
iv: orgBot.symmetricKeyIV,
|
||||||
@@ -201,11 +183,7 @@ export const samlConfigServiceFactory = ({
|
|||||||
updateQuery.entryPointTag = entryPointTag;
|
updateQuery.entryPointTag = entryPointTag;
|
||||||
}
|
}
|
||||||
if (issuer) {
|
if (issuer) {
|
||||||
const {
|
const { ciphertext: encryptedIssuer, iv: issuerIV, tag: issuerTag } = encryptSymmetric(issuer, key);
|
||||||
ciphertext: encryptedIssuer,
|
|
||||||
iv: issuerIV,
|
|
||||||
tag: issuerTag
|
|
||||||
} = encryptSymmetric(issuer, key);
|
|
||||||
updateQuery.encryptedIssuer = encryptedIssuer;
|
updateQuery.encryptedIssuer = encryptedIssuer;
|
||||||
updateQuery.issuerIV = issuerIV;
|
updateQuery.issuerIV = issuerIV;
|
||||||
updateQuery.issuerTag = issuerTag;
|
updateQuery.issuerTag = issuerTag;
|
||||||
@@ -249,15 +227,8 @@ export const samlConfigServiceFactory = ({
|
|||||||
|
|
||||||
// when dto is type id means it's internally used
|
// when dto is type id means it's internally used
|
||||||
if (dto.type === "org") {
|
if (dto.type === "org") {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission(dto.actor, dto.actorId, ssoConfig.orgId);
|
||||||
dto.actor,
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Sso);
|
||||||
dto.actorId,
|
|
||||||
ssoConfig.orgId
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
OrgPermissionActions.Read,
|
|
||||||
OrgPermissionSubjects.Sso
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
const {
|
const {
|
||||||
entryPointTag,
|
entryPointTag,
|
||||||
@@ -272,8 +243,7 @@ export const samlConfigServiceFactory = ({
|
|||||||
} = ssoConfig;
|
} = ssoConfig;
|
||||||
|
|
||||||
const orgBot = await orgBotDAL.findOne({ orgId: ssoConfig.orgId });
|
const orgBot = await orgBotDAL.findOne({ orgId: ssoConfig.orgId });
|
||||||
if (!orgBot)
|
if (!orgBot) throw new BadRequestError({ message: "Org bot not found", name: "OrgBotNotFound" });
|
||||||
throw new BadRequestError({ message: "Org bot not found", name: "OrgBotNotFound" });
|
|
||||||
const key = infisicalSymmetricDecrypt({
|
const key = infisicalSymmetricDecrypt({
|
||||||
ciphertext: orgBot.encryptedSymmetricKey,
|
ciphertext: orgBot.encryptedSymmetricKey,
|
||||||
iv: orgBot.symmetricKeyIV,
|
iv: orgBot.symmetricKeyIV,
|
||||||
@@ -330,8 +300,7 @@ export const samlConfigServiceFactory = ({
|
|||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
let user = await userDAL.findUserByEmail(email);
|
let user = await userDAL.findUserByEmail(email);
|
||||||
const isSamlSignUpDisabled = !isSignupAllowed && !user;
|
const isSamlSignUpDisabled = !isSignupAllowed && !user;
|
||||||
if (isSamlSignUpDisabled)
|
if (isSamlSignUpDisabled) throw new BadRequestError({ message: "User signup disabled", name: "Saml SSO login" });
|
||||||
throw new BadRequestError({ message: "User signup disabled", name: "Saml SSO login" });
|
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findOrgById(orgId);
|
||||||
if (!organization) throw new BadRequestError({ message: "Org not found" });
|
if (!organization) throw new BadRequestError({ message: "Org not found" });
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ import { TDbClient } from "@app/db";
|
|||||||
import { TableName } from "@app/db/schemas";
|
import { TableName } from "@app/db/schemas";
|
||||||
import { ormify } from "@app/lib/knex";
|
import { ormify } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TSecretApprovalPolicyApproverDALFactory = ReturnType<
|
export type TSecretApprovalPolicyApproverDALFactory = ReturnType<typeof secretApprovalPolicyApproverDALFactory>;
|
||||||
typeof secretApprovalPolicyApproverDALFactory
|
|
||||||
>;
|
|
||||||
|
|
||||||
export const secretApprovalPolicyApproverDALFactory = (db: TDbClient) => {
|
export const secretApprovalPolicyApproverDALFactory = (db: TDbClient) => {
|
||||||
const sapApproverOrm = ormify(db, TableName.SecretApprovalPolicyApprover);
|
const sapApproverOrm = ormify(db, TableName.SecretApprovalPolicyApprover);
|
||||||
|
|||||||
@@ -3,13 +3,7 @@ import { Knex } from "knex";
|
|||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName, TSecretApprovalPolicies } from "@app/db/schemas";
|
import { TableName, TSecretApprovalPolicies } from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import {
|
import { buildFindFilter, mergeOneToManyRelation, ormify, selectAllTableCols, TFindFilter } from "@app/lib/knex";
|
||||||
buildFindFilter,
|
|
||||||
mergeOneToManyRelation,
|
|
||||||
ormify,
|
|
||||||
selectAllTableCols,
|
|
||||||
TFindFilter
|
|
||||||
} from "@app/lib/knex";
|
|
||||||
|
|
||||||
export type TSecretApprovalPolicyDALFactory = ReturnType<typeof secretApprovalPolicyDALFactory>;
|
export type TSecretApprovalPolicyDALFactory = ReturnType<typeof secretApprovalPolicyDALFactory>;
|
||||||
|
|
||||||
@@ -20,11 +14,7 @@ export const secretApprovalPolicyDALFactory = (db: TDbClient) => {
|
|||||||
tx(TableName.SecretApprovalPolicy)
|
tx(TableName.SecretApprovalPolicy)
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
.where(buildFindFilter(filter))
|
.where(buildFindFilter(filter))
|
||||||
.join(
|
.join(TableName.Environment, `${TableName.SecretApprovalPolicy}.envId`, `${TableName.Environment}.id`)
|
||||||
TableName.Environment,
|
|
||||||
`${TableName.SecretApprovalPolicy}.envId`,
|
|
||||||
`${TableName.Environment}.id`
|
|
||||||
)
|
|
||||||
.join(
|
.join(
|
||||||
TableName.SecretApprovalPolicyApprover,
|
TableName.SecretApprovalPolicyApprover,
|
||||||
`${TableName.SecretApprovalPolicy}.id`,
|
`${TableName.SecretApprovalPolicy}.id`,
|
||||||
@@ -60,10 +50,7 @@ export const secretApprovalPolicyDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const find = async (
|
const find = async (filter: TFindFilter<TSecretApprovalPolicies & { projectId: string }>, tx?: Knex) => {
|
||||||
filter: TFindFilter<TSecretApprovalPolicies & { projectId: string }>,
|
|
||||||
tx?: Knex
|
|
||||||
) => {
|
|
||||||
try {
|
try {
|
||||||
const docs = await sapFindQuery(tx || db, filter);
|
const docs = await sapFindQuery(tx || db, filter);
|
||||||
const formatedDoc = mergeOneToManyRelation(
|
const formatedDoc = mergeOneToManyRelation(
|
||||||
|
|||||||
@@ -2,10 +2,7 @@ import { ForbiddenError, subject } from "@casl/ability";
|
|||||||
import picomatch from "picomatch";
|
import picomatch from "picomatch";
|
||||||
|
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||||
import {
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
||||||
ProjectPermissionActions,
|
|
||||||
ProjectPermissionSub
|
|
||||||
} from "@app/ee/services/permission/project-permission";
|
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
import { containsGlobPatterns } from "@app/lib/picomatch";
|
import { containsGlobPatterns } from "@app/lib/picomatch";
|
||||||
import { TProjectEnvDALFactory } from "@app/services/project-env/project-env-dal";
|
import { TProjectEnvDALFactory } from "@app/services/project-env/project-env-dal";
|
||||||
@@ -34,9 +31,7 @@ type TSecretApprovalPolicyServiceFactoryDep = {
|
|||||||
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "find">;
|
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "find">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TSecretApprovalPolicyServiceFactory = ReturnType<
|
export type TSecretApprovalPolicyServiceFactory = ReturnType<typeof secretApprovalPolicyServiceFactory>;
|
||||||
typeof secretApprovalPolicyServiceFactory
|
|
||||||
>;
|
|
||||||
|
|
||||||
export const secretApprovalPolicyServiceFactory = ({
|
export const secretApprovalPolicyServiceFactory = ({
|
||||||
secretApprovalPolicyDAL,
|
secretApprovalPolicyDAL,
|
||||||
@@ -105,18 +100,10 @@ export const secretApprovalPolicyServiceFactory = ({
|
|||||||
secretPolicyId
|
secretPolicyId
|
||||||
}: TUpdateSapDTO) => {
|
}: TUpdateSapDTO) => {
|
||||||
const secretApprovalPolicy = await secretApprovalPolicyDAL.findById(secretPolicyId);
|
const secretApprovalPolicy = await secretApprovalPolicyDAL.findById(secretPolicyId);
|
||||||
if (!secretApprovalPolicy)
|
if (!secretApprovalPolicy) throw new BadRequestError({ message: "Secret approval policy not found" });
|
||||||
throw new BadRequestError({ message: "Secret approval policy not found" });
|
|
||||||
|
|
||||||
const { permission } = await permissionService.getProjectPermission(
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, secretApprovalPolicy.projectId);
|
||||||
actor,
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SecretApproval);
|
||||||
actorId,
|
|
||||||
secretApprovalPolicy.projectId
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
ProjectPermissionActions.Edit,
|
|
||||||
ProjectPermissionSub.SecretApproval
|
|
||||||
);
|
|
||||||
|
|
||||||
const updatedSap = await secretApprovalPolicyDAL.transaction(async (tx) => {
|
const updatedSap = await secretApprovalPolicyDAL.transaction(async (tx) => {
|
||||||
const doc = await secretApprovalPolicyDAL.updateById(
|
const doc = await secretApprovalPolicyDAL.updateById(
|
||||||
@@ -162,11 +149,7 @@ export const secretApprovalPolicyServiceFactory = ({
|
|||||||
const sapPolicy = await secretApprovalPolicyDAL.findById(secretPolicyId);
|
const sapPolicy = await secretApprovalPolicyDAL.findById(secretPolicyId);
|
||||||
if (!sapPolicy) throw new BadRequestError({ message: "Secret approval policy not found" });
|
if (!sapPolicy) throw new BadRequestError({ message: "Secret approval policy not found" });
|
||||||
|
|
||||||
const { permission } = await permissionService.getProjectPermission(
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, sapPolicy.projectId);
|
||||||
actor,
|
|
||||||
actorId,
|
|
||||||
sapPolicy.projectId
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Delete,
|
ProjectPermissionActions.Delete,
|
||||||
ProjectPermissionSub.SecretApproval
|
ProjectPermissionSub.SecretApproval
|
||||||
@@ -178,20 +161,13 @@ export const secretApprovalPolicyServiceFactory = ({
|
|||||||
|
|
||||||
const getSecretApprovalPolicyByProjectId = async ({ actorId, actor, projectId }: TListSapDTO) => {
|
const getSecretApprovalPolicyByProjectId = async ({ actorId, actor, projectId }: TListSapDTO) => {
|
||||||
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval);
|
||||||
ProjectPermissionActions.Read,
|
|
||||||
ProjectPermissionSub.SecretApproval
|
|
||||||
);
|
|
||||||
|
|
||||||
const sapPolicies = await secretApprovalPolicyDAL.find({ projectId });
|
const sapPolicies = await secretApprovalPolicyDAL.find({ projectId });
|
||||||
return sapPolicies;
|
return sapPolicies;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getSecretApprovalPolicy = async (
|
const getSecretApprovalPolicy = async (projectId: string, environment: string, secretPath: string) => {
|
||||||
projectId: string,
|
|
||||||
environment: string,
|
|
||||||
secretPath: string
|
|
||||||
) => {
|
|
||||||
const env = await projectEnvDAL.findOne({ slug: environment, projectId });
|
const env = await projectEnvDAL.findOne({ slug: environment, projectId });
|
||||||
if (!env) throw new BadRequestError({ message: "Environment not found" });
|
if (!env) throw new BadRequestError({ message: "Environment not found" });
|
||||||
|
|
||||||
@@ -199,14 +175,11 @@ export const secretApprovalPolicyServiceFactory = ({
|
|||||||
if (!policies.length) return;
|
if (!policies.length) return;
|
||||||
// this will filter policies either without scoped to secret path or the one that matches with secret path
|
// this will filter policies either without scoped to secret path or the one that matches with secret path
|
||||||
const policiesFilteredByPath = policies.filter(
|
const policiesFilteredByPath = policies.filter(
|
||||||
({ secretPath: policyPath }) =>
|
({ secretPath: policyPath }) => !policyPath || picomatch.isMatch(secretPath, policyPath, { strictSlashes: false })
|
||||||
!policyPath || picomatch.isMatch(secretPath, policyPath, { strictSlashes: false })
|
|
||||||
);
|
);
|
||||||
// now sort by priority. exact secret path gets first match followed by glob followed by just env scoped
|
// now sort by priority. exact secret path gets first match followed by glob followed by just env scoped
|
||||||
// if that is tie get by first createdAt
|
// if that is tie get by first createdAt
|
||||||
const policiesByPriority = policiesFilteredByPath.sort(
|
const policiesByPriority = policiesFilteredByPath.sort((a, b) => getPolicyScore(b) - getPolicyScore(a));
|
||||||
(a, b) => getPolicyScore(b) - getPolicyScore(a)
|
|
||||||
);
|
|
||||||
const finalPolicy = policiesByPriority.shift();
|
const finalPolicy = policiesByPriority.shift();
|
||||||
return finalPolicy;
|
return finalPolicy;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,13 +8,7 @@ import {
|
|||||||
TSecretApprovalRequestsSecrets
|
TSecretApprovalRequestsSecrets
|
||||||
} from "@app/db/schemas";
|
} from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import {
|
import { ormify, selectAllTableCols, sqlNestRelationships, stripUndefinedInWhere, TFindFilter } from "@app/lib/knex";
|
||||||
ormify,
|
|
||||||
selectAllTableCols,
|
|
||||||
sqlNestRelationships,
|
|
||||||
stripUndefinedInWhere,
|
|
||||||
TFindFilter
|
|
||||||
} from "@app/lib/knex";
|
|
||||||
|
|
||||||
import { RequestState } from "./secret-approval-request-types";
|
import { RequestState } from "./secret-approval-request-types";
|
||||||
|
|
||||||
@@ -36,11 +30,7 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
|
|||||||
const findQuery = (filter: TFindFilter<TSecretApprovalRequests>, tx: Knex) =>
|
const findQuery = (filter: TFindFilter<TSecretApprovalRequests>, tx: Knex) =>
|
||||||
tx(TableName.SecretApprovalRequest)
|
tx(TableName.SecretApprovalRequest)
|
||||||
.where(filter)
|
.where(filter)
|
||||||
.join(
|
.join(TableName.SecretFolder, `${TableName.SecretApprovalRequest}.folderId`, `${TableName.SecretFolder}.id`)
|
||||||
TableName.SecretFolder,
|
|
||||||
`${TableName.SecretApprovalRequest}.folderId`,
|
|
||||||
`${TableName.SecretFolder}.id`
|
|
||||||
)
|
|
||||||
.join(TableName.Environment, `${TableName.SecretFolder}.envId`, `${TableName.Environment}.id`)
|
.join(TableName.Environment, `${TableName.SecretFolder}.envId`, `${TableName.Environment}.id`)
|
||||||
.join(
|
.join(
|
||||||
TableName.SecretApprovalPolicy,
|
TableName.SecretApprovalPolicy,
|
||||||
@@ -92,8 +82,7 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
|
|||||||
{
|
{
|
||||||
key: "reviewerMemberId",
|
key: "reviewerMemberId",
|
||||||
label: "reviewers" as const,
|
label: "reviewers" as const,
|
||||||
mapper: ({ reviewerMemberId: member, reviewerStatus: status }) =>
|
mapper: ({ reviewerMemberId: member, reviewerStatus: status }) => (member ? { member, status } : undefined)
|
||||||
member ? { member, status } : undefined
|
|
||||||
},
|
},
|
||||||
{ key: "approverId", label: "approvers" as const, mapper: ({ approverId }) => approverId }
|
{ key: "approverId", label: "approvers" as const, mapper: ({ approverId }) => approverId }
|
||||||
]
|
]
|
||||||
@@ -114,16 +103,8 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
|
|||||||
.with(
|
.with(
|
||||||
"temp",
|
"temp",
|
||||||
(tx || db)(TableName.SecretApprovalRequest)
|
(tx || db)(TableName.SecretApprovalRequest)
|
||||||
.join(
|
.join(TableName.SecretFolder, `${TableName.SecretApprovalRequest}.folderId`, `${TableName.SecretFolder}.id`)
|
||||||
TableName.SecretFolder,
|
.join(TableName.Environment, `${TableName.SecretFolder}.envId`, `${TableName.Environment}.id`)
|
||||||
`${TableName.SecretApprovalRequest}.folderId`,
|
|
||||||
`${TableName.SecretFolder}.id`
|
|
||||||
)
|
|
||||||
.join(
|
|
||||||
TableName.Environment,
|
|
||||||
`${TableName.SecretFolder}.envId`,
|
|
||||||
`${TableName.Environment}.id`
|
|
||||||
)
|
|
||||||
.join(
|
.join(
|
||||||
TableName.SecretApprovalPolicyApprover,
|
TableName.SecretApprovalPolicyApprover,
|
||||||
`${TableName.SecretApprovalRequest}.policyId`,
|
`${TableName.SecretApprovalRequest}.policyId`,
|
||||||
@@ -147,13 +128,11 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
open: parseInt(
|
open: parseInt(
|
||||||
(docs.find(({ status }) => status === RequestState.Open) as { count: string })?.count ||
|
(docs.find(({ status }) => status === RequestState.Open) as { count: string })?.count || "0",
|
||||||
"0",
|
|
||||||
10
|
10
|
||||||
),
|
),
|
||||||
closed: parseInt(
|
closed: parseInt(
|
||||||
(docs.find(({ status }) => status === RequestState.Closed) as { count: string })?.count ||
|
(docs.find(({ status }) => status === RequestState.Closed) as { count: string })?.count || "0",
|
||||||
"0",
|
|
||||||
10
|
10
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
@@ -163,31 +142,15 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const findByProjectId = async (
|
const findByProjectId = async (
|
||||||
{
|
{ status, limit = 20, offset = 0, projectId, committer, environment, membershipId }: TFindQueryFilter,
|
||||||
status,
|
|
||||||
limit = 20,
|
|
||||||
offset = 0,
|
|
||||||
projectId,
|
|
||||||
committer,
|
|
||||||
environment,
|
|
||||||
membershipId
|
|
||||||
}: TFindQueryFilter,
|
|
||||||
tx?: Knex
|
tx?: Knex
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
// akhilmhdh: If ever u wanted a 1 to so many relationship connected with pagination
|
// akhilmhdh: If ever u wanted a 1 to so many relationship connected with pagination
|
||||||
// this is the place u wanna look at.
|
// this is the place u wanna look at.
|
||||||
const query = (tx || db)(TableName.SecretApprovalRequest)
|
const query = (tx || db)(TableName.SecretApprovalRequest)
|
||||||
.join(
|
.join(TableName.SecretFolder, `${TableName.SecretApprovalRequest}.folderId`, `${TableName.SecretFolder}.id`)
|
||||||
TableName.SecretFolder,
|
.join(TableName.Environment, `${TableName.SecretFolder}.envId`, `${TableName.Environment}.id`)
|
||||||
`${TableName.SecretApprovalRequest}.folderId`,
|
|
||||||
`${TableName.SecretFolder}.id`
|
|
||||||
)
|
|
||||||
.join(
|
|
||||||
TableName.Environment,
|
|
||||||
`${TableName.SecretFolder}.envId`,
|
|
||||||
`${TableName.Environment}.id`
|
|
||||||
)
|
|
||||||
.join(
|
.join(
|
||||||
TableName.SecretApprovalPolicy,
|
TableName.SecretApprovalPolicy,
|
||||||
`${TableName.SecretApprovalRequest}.policyId`,
|
`${TableName.SecretApprovalRequest}.policyId`,
|
||||||
@@ -266,8 +229,7 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
|
|||||||
{
|
{
|
||||||
key: "reviewerMemberId",
|
key: "reviewerMemberId",
|
||||||
label: "reviewers" as const,
|
label: "reviewers" as const,
|
||||||
mapper: ({ reviewerMemberId: member, reviewerStatus: s }) =>
|
mapper: ({ reviewerMemberId: member, reviewerStatus: s }) => (member ? { member, status: s } : undefined)
|
||||||
member ? { member, status: s } : undefined
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "approverId",
|
key: "approverId",
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ import { TDbClient } from "@app/db";
|
|||||||
import { TableName } from "@app/db/schemas";
|
import { TableName } from "@app/db/schemas";
|
||||||
import { ormify } from "@app/lib/knex";
|
import { ormify } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TSecretApprovalRequestReviewerDALFactory = ReturnType<
|
export type TSecretApprovalRequestReviewerDALFactory = ReturnType<typeof secretApprovalRequestReviewerDALFactory>;
|
||||||
typeof secretApprovalRequestReviewerDALFactory
|
|
||||||
>;
|
|
||||||
|
|
||||||
export const secretApprovalRequestReviewerDALFactory = (db: TDbClient) => {
|
export const secretApprovalRequestReviewerDALFactory = (db: TDbClient) => {
|
||||||
const secretApprovalRequestReviewerOrm = ormify(db, TableName.SecretApprovalRequestReviewer);
|
const secretApprovalRequestReviewerOrm = ormify(db, TableName.SecretApprovalRequestReviewer);
|
||||||
|
|||||||
@@ -5,9 +5,7 @@ import { SecretApprovalRequestsSecretsSchema, TableName, TSecretTags } from "@ap
|
|||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import { ormify, selectAllTableCols, sqlNestRelationships } from "@app/lib/knex";
|
import { ormify, selectAllTableCols, sqlNestRelationships } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TSecretApprovalRequestSecretDALFactory = ReturnType<
|
export type TSecretApprovalRequestSecretDALFactory = ReturnType<typeof secretApprovalRequestSecretDALFactory>;
|
||||||
typeof secretApprovalRequestSecretDALFactory
|
|
||||||
>;
|
|
||||||
|
|
||||||
export const secretApprovalRequestSecretDALFactory = (db: TDbClient) => {
|
export const secretApprovalRequestSecretDALFactory = (db: TDbClient) => {
|
||||||
const secretApprovalRequestSecretOrm = ormify(db, TableName.SecretApprovalRequestSecret);
|
const secretApprovalRequestSecretOrm = ormify(db, TableName.SecretApprovalRequestSecret);
|
||||||
@@ -25,16 +23,8 @@ export const secretApprovalRequestSecretDALFactory = (db: TDbClient) => {
|
|||||||
`${TableName.SecretApprovalRequestSecret}.id`,
|
`${TableName.SecretApprovalRequestSecret}.id`,
|
||||||
`${TableName.SecretApprovalRequestSecretTag}.secretId`
|
`${TableName.SecretApprovalRequestSecretTag}.secretId`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(TableName.SecretTag, `${TableName.SecretApprovalRequestSecretTag}.tagId`, `${TableName.SecretTag}.id`)
|
||||||
TableName.SecretTag,
|
.leftJoin(TableName.Secret, `${TableName.SecretApprovalRequestSecret}.secretId`, `${TableName.Secret}.id`)
|
||||||
`${TableName.SecretApprovalRequestSecretTag}.tagId`,
|
|
||||||
`${TableName.SecretTag}.id`
|
|
||||||
)
|
|
||||||
.leftJoin(
|
|
||||||
TableName.Secret,
|
|
||||||
`${TableName.SecretApprovalRequestSecret}.secretId`,
|
|
||||||
`${TableName.Secret}.id`
|
|
||||||
)
|
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.SecretVersion,
|
TableName.SecretVersion,
|
||||||
`${TableName.SecretVersion}.id`,
|
`${TableName.SecretVersion}.id`,
|
||||||
@@ -75,37 +65,24 @@ export const secretApprovalRequestSecretDALFactory = (db: TDbClient) => {
|
|||||||
db.ref("secretValueCiphertext").withSchema(TableName.Secret).as("orgSecValueCiphertext"),
|
db.ref("secretValueCiphertext").withSchema(TableName.Secret).as("orgSecValueCiphertext"),
|
||||||
db.ref("secretCommentIV").withSchema(TableName.Secret).as("orgSecCommentIV"),
|
db.ref("secretCommentIV").withSchema(TableName.Secret).as("orgSecCommentIV"),
|
||||||
db.ref("secretCommentTag").withSchema(TableName.Secret).as("orgSecCommentTag"),
|
db.ref("secretCommentTag").withSchema(TableName.Secret).as("orgSecCommentTag"),
|
||||||
db
|
db.ref("secretCommentCiphertext").withSchema(TableName.Secret).as("orgSecCommentCiphertext")
|
||||||
.ref("secretCommentCiphertext")
|
|
||||||
.withSchema(TableName.Secret)
|
|
||||||
.as("orgSecCommentCiphertext")
|
|
||||||
)
|
)
|
||||||
.select(
|
.select(
|
||||||
db.ref("version").withSchema(TableName.SecretVersion).as("secVerVersion"),
|
db.ref("version").withSchema(TableName.SecretVersion).as("secVerVersion"),
|
||||||
db.ref("secretKeyIV").withSchema(TableName.SecretVersion).as("secVerKeyIV"),
|
db.ref("secretKeyIV").withSchema(TableName.SecretVersion).as("secVerKeyIV"),
|
||||||
db.ref("secretKeyTag").withSchema(TableName.SecretVersion).as("secVerKeyTag"),
|
db.ref("secretKeyTag").withSchema(TableName.SecretVersion).as("secVerKeyTag"),
|
||||||
db
|
db.ref("secretKeyCiphertext").withSchema(TableName.SecretVersion).as("secVerKeyCiphertext"),
|
||||||
.ref("secretKeyCiphertext")
|
|
||||||
.withSchema(TableName.SecretVersion)
|
|
||||||
.as("secVerKeyCiphertext"),
|
|
||||||
db.ref("secretValueIV").withSchema(TableName.SecretVersion).as("secVerValueIV"),
|
db.ref("secretValueIV").withSchema(TableName.SecretVersion).as("secVerValueIV"),
|
||||||
db.ref("secretValueTag").withSchema(TableName.SecretVersion).as("secVerValueTag"),
|
db.ref("secretValueTag").withSchema(TableName.SecretVersion).as("secVerValueTag"),
|
||||||
db
|
db.ref("secretValueCiphertext").withSchema(TableName.SecretVersion).as("secVerValueCiphertext"),
|
||||||
.ref("secretValueCiphertext")
|
|
||||||
.withSchema(TableName.SecretVersion)
|
|
||||||
.as("secVerValueCiphertext"),
|
|
||||||
db.ref("secretCommentIV").withSchema(TableName.SecretVersion).as("secVerCommentIV"),
|
db.ref("secretCommentIV").withSchema(TableName.SecretVersion).as("secVerCommentIV"),
|
||||||
db.ref("secretCommentTag").withSchema(TableName.SecretVersion).as("secVerCommentTag"),
|
db.ref("secretCommentTag").withSchema(TableName.SecretVersion).as("secVerCommentTag"),
|
||||||
db
|
db.ref("secretCommentCiphertext").withSchema(TableName.SecretVersion).as("secVerCommentCiphertext")
|
||||||
.ref("secretCommentCiphertext")
|
|
||||||
.withSchema(TableName.SecretVersion)
|
|
||||||
.as("secVerCommentCiphertext")
|
|
||||||
);
|
);
|
||||||
const formatedDoc = sqlNestRelationships({
|
const formatedDoc = sqlNestRelationships({
|
||||||
data: doc,
|
data: doc,
|
||||||
key: "id",
|
key: "id",
|
||||||
parentMapper: (data) =>
|
parentMapper: (data) => SecretApprovalRequestsSecretsSchema.omit({ secretVersion: true }).parse(data),
|
||||||
SecretApprovalRequestsSecretsSchema.omit({ secretVersion: true }).parse(data),
|
|
||||||
childrenMapper: [
|
childrenMapper: [
|
||||||
{
|
{
|
||||||
key: "tagJnId",
|
key: "tagJnId",
|
||||||
@@ -186,12 +163,7 @@ export const secretApprovalRequestSecretDALFactory = (db: TDbClient) => {
|
|||||||
{
|
{
|
||||||
key: "secVerTagId",
|
key: "secVerTagId",
|
||||||
label: "tags" as const,
|
label: "tags" as const,
|
||||||
mapper: ({
|
mapper: ({ secVerTagId: id, secVerTagName: name, secVerTagSlug: slug, secVerTagColor: color }) => ({
|
||||||
secVerTagId: id,
|
|
||||||
secVerTagName: name,
|
|
||||||
secVerTagSlug: slug,
|
|
||||||
secVerTagColor: color
|
|
||||||
}) => ({
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
id,
|
id,
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
|
|||||||
@@ -42,10 +42,7 @@ type TSecretApprovalRequestServiceFactoryDep = {
|
|||||||
secretApprovalRequestDAL: TSecretApprovalRequestDALFactory;
|
secretApprovalRequestDAL: TSecretApprovalRequestDALFactory;
|
||||||
secretApprovalRequestSecretDAL: TSecretApprovalRequestSecretDALFactory;
|
secretApprovalRequestSecretDAL: TSecretApprovalRequestSecretDALFactory;
|
||||||
secretApprovalRequestReviewerDAL: TSecretApprovalRequestReviewerDALFactory;
|
secretApprovalRequestReviewerDAL: TSecretApprovalRequestReviewerDALFactory;
|
||||||
folderDAL: Pick<
|
folderDAL: Pick<TSecretFolderDALFactory, "findBySecretPath" | "findById" | "findSecretPathByFolderIds">;
|
||||||
TSecretFolderDALFactory,
|
|
||||||
"findBySecretPath" | "findById" | "findSecretPathByFolderIds"
|
|
||||||
>;
|
|
||||||
secretTagDAL: Pick<TSecretTagDALFactory, "findManyTagsById">;
|
secretTagDAL: Pick<TSecretTagDALFactory, "findManyTagsById">;
|
||||||
secretBlindIndexDAL: Pick<TSecretBlindIndexDALFactory, "findOne">;
|
secretBlindIndexDAL: Pick<TSecretBlindIndexDALFactory, "findOne">;
|
||||||
snapshotService: Pick<TSecretSnapshotServiceFactory, "performSnapshot">;
|
snapshotService: Pick<TSecretSnapshotServiceFactory, "performSnapshot">;
|
||||||
@@ -61,9 +58,7 @@ type TSecretApprovalRequestServiceFactoryDep = {
|
|||||||
secretQueueService: Pick<TSecretQueueFactory, "syncSecrets">;
|
secretQueueService: Pick<TSecretQueueFactory, "syncSecrets">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TSecretApprovalRequestServiceFactory = ReturnType<
|
export type TSecretApprovalRequestServiceFactory = ReturnType<typeof secretApprovalRequestServiceFactory>;
|
||||||
typeof secretApprovalRequestServiceFactory
|
|
||||||
>;
|
|
||||||
|
|
||||||
export const secretApprovalRequestServiceFactory = ({
|
export const secretApprovalRequestServiceFactory = ({
|
||||||
secretApprovalRequestDAL,
|
secretApprovalRequestDAL,
|
||||||
@@ -79,14 +74,9 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
secretQueueService
|
secretQueueService
|
||||||
}: TSecretApprovalRequestServiceFactoryDep) => {
|
}: TSecretApprovalRequestServiceFactoryDep) => {
|
||||||
const requestCount = async ({ projectId, actor, actorId }: TApprovalRequestCountDTO) => {
|
const requestCount = async ({ projectId, actor, actorId }: TApprovalRequestCountDTO) => {
|
||||||
if (actor === ActorType.SERVICE)
|
if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" });
|
||||||
throw new BadRequestError({ message: "Cannot use service token" });
|
|
||||||
|
|
||||||
const { membership } = await permissionService.getProjectPermission(
|
const { membership } = await permissionService.getProjectPermission(actor as ActorType.USER, actorId, projectId);
|
||||||
actor as ActorType.USER,
|
|
||||||
actorId,
|
|
||||||
projectId
|
|
||||||
);
|
|
||||||
|
|
||||||
const count = await secretApprovalRequestDAL.findProjectRequestCount(projectId, membership.id);
|
const count = await secretApprovalRequestDAL.findProjectRequestCount(projectId, membership.id);
|
||||||
return count;
|
return count;
|
||||||
@@ -102,8 +92,7 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
limit,
|
limit,
|
||||||
offset
|
offset
|
||||||
}: TListApprovalsDTO) => {
|
}: TListApprovalsDTO) => {
|
||||||
if (actor === ActorType.SERVICE)
|
if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" });
|
||||||
throw new BadRequestError({ message: "Cannot use service token" });
|
|
||||||
|
|
||||||
const { membership } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
const { membership } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
const approvals = await secretApprovalRequestDAL.findByProjectId({
|
const approvals = await secretApprovalRequestDAL.findByProjectId({
|
||||||
@@ -119,12 +108,10 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getSecretApprovalDetails = async ({ actor, actorId, id }: TSecretApprovalDetailsDTO) => {
|
const getSecretApprovalDetails = async ({ actor, actorId, id }: TSecretApprovalDetailsDTO) => {
|
||||||
if (actor === ActorType.SERVICE)
|
if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" });
|
||||||
throw new BadRequestError({ message: "Cannot use service token" });
|
|
||||||
|
|
||||||
const secretApprovalRequest = await secretApprovalRequestDAL.findById(id);
|
const secretApprovalRequest = await secretApprovalRequestDAL.findById(id);
|
||||||
if (!secretApprovalRequest)
|
if (!secretApprovalRequest) throw new BadRequestError({ message: "Secret approval request not found" });
|
||||||
throw new BadRequestError({ message: "Secret approval request not found" });
|
|
||||||
|
|
||||||
const { policy } = secretApprovalRequest;
|
const { policy } = secretApprovalRequest;
|
||||||
const { membership } = await permissionService.getProjectPermission(
|
const { membership } = await permissionService.getProjectPermission(
|
||||||
@@ -149,8 +136,7 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
|
|
||||||
const reviewApproval = async ({ approvalId, actor, status, actorId }: TReviewRequestDTO) => {
|
const reviewApproval = async ({ approvalId, actor, status, actorId }: TReviewRequestDTO) => {
|
||||||
const secretApprovalRequest = await secretApprovalRequestDAL.findById(approvalId);
|
const secretApprovalRequest = await secretApprovalRequestDAL.findById(approvalId);
|
||||||
if (!secretApprovalRequest)
|
if (!secretApprovalRequest) throw new BadRequestError({ message: "Secret approval request not found" });
|
||||||
throw new BadRequestError({ message: "Secret approval request not found" });
|
|
||||||
if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" });
|
if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" });
|
||||||
|
|
||||||
const { policy } = secretApprovalRequest;
|
const { policy } = secretApprovalRequest;
|
||||||
@@ -191,8 +177,7 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
|
|
||||||
const updateApprovalStatus = async ({ actorId, status, approvalId, actor }: TStatusChangeDTO) => {
|
const updateApprovalStatus = async ({ actorId, status, approvalId, actor }: TStatusChangeDTO) => {
|
||||||
const secretApprovalRequest = await secretApprovalRequestDAL.findById(approvalId);
|
const secretApprovalRequest = await secretApprovalRequestDAL.findById(approvalId);
|
||||||
if (!secretApprovalRequest)
|
if (!secretApprovalRequest) throw new BadRequestError({ message: "Secret approval request not found" });
|
||||||
throw new BadRequestError({ message: "Secret approval request not found" });
|
|
||||||
if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" });
|
if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" });
|
||||||
|
|
||||||
const { policy } = secretApprovalRequest;
|
const { policy } = secretApprovalRequest;
|
||||||
@@ -209,8 +194,7 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
throw new UnauthorizedError({ message: "User has no access" });
|
throw new UnauthorizedError({ message: "User has no access" });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (secretApprovalRequest.hasMerged)
|
if (secretApprovalRequest.hasMerged) throw new BadRequestError({ message: "Approval request has been merged" });
|
||||||
throw new BadRequestError({ message: "Approval request has been merged" });
|
|
||||||
if (secretApprovalRequest.status === RequestState.Closed && status === RequestState.Closed)
|
if (secretApprovalRequest.status === RequestState.Closed && status === RequestState.Closed)
|
||||||
throw new BadRequestError({ message: "Approval request is already closed" });
|
throw new BadRequestError({ message: "Approval request is already closed" });
|
||||||
if (secretApprovalRequest.status === RequestState.Open && status === RequestState.Open)
|
if (secretApprovalRequest.status === RequestState.Open && status === RequestState.Open)
|
||||||
@@ -223,22 +207,13 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
return { ...secretApprovalRequest, ...updatedRequest };
|
return { ...secretApprovalRequest, ...updatedRequest };
|
||||||
};
|
};
|
||||||
|
|
||||||
const mergeSecretApprovalRequest = async ({
|
const mergeSecretApprovalRequest = async ({ approvalId, actor, actorId }: TMergeSecretApprovalRequestDTO) => {
|
||||||
approvalId,
|
|
||||||
actor,
|
|
||||||
actorId
|
|
||||||
}: TMergeSecretApprovalRequestDTO) => {
|
|
||||||
const secretApprovalRequest = await secretApprovalRequestDAL.findById(approvalId);
|
const secretApprovalRequest = await secretApprovalRequestDAL.findById(approvalId);
|
||||||
if (!secretApprovalRequest)
|
if (!secretApprovalRequest) throw new BadRequestError({ message: "Secret approval request not found" });
|
||||||
throw new BadRequestError({ message: "Secret approval request not found" });
|
|
||||||
if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" });
|
if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" });
|
||||||
|
|
||||||
const { policy, folderId, projectId } = secretApprovalRequest;
|
const { policy, folderId, projectId } = secretApprovalRequest;
|
||||||
const { membership } = await permissionService.getProjectPermission(
|
const { membership } = await permissionService.getProjectPermission(ActorType.USER, actorId, projectId);
|
||||||
ActorType.USER,
|
|
||||||
actorId,
|
|
||||||
projectId
|
|
||||||
);
|
|
||||||
if (
|
if (
|
||||||
membership.role !== ProjectMembershipRole.Admin &&
|
membership.role !== ProjectMembershipRole.Admin &&
|
||||||
secretApprovalRequest.committerId !== membership.id &&
|
secretApprovalRequest.committerId !== membership.id &&
|
||||||
@@ -256,28 +231,24 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
(approverId) => reviewers[approverId.toString()] === ApprovalStatus.APPROVED
|
(approverId) => reviewers[approverId.toString()] === ApprovalStatus.APPROVED
|
||||||
).length;
|
).length;
|
||||||
|
|
||||||
if (!hasMinApproval)
|
if (!hasMinApproval) throw new BadRequestError({ message: "Doesn't have minimum approvals needed" });
|
||||||
throw new BadRequestError({ message: "Doesn't have minimum approvals needed" });
|
const secretApprovalSecrets = await secretApprovalRequestSecretDAL.findByRequestId(secretApprovalRequest.id);
|
||||||
const secretApprovalSecrets = await secretApprovalRequestSecretDAL.findByRequestId(
|
|
||||||
secretApprovalRequest.id
|
|
||||||
);
|
|
||||||
if (!secretApprovalSecrets) throw new BadRequestError({ message: "No secrets found" });
|
if (!secretApprovalSecrets) throw new BadRequestError({ message: "No secrets found" });
|
||||||
|
|
||||||
const conflicts: Array<{ secretId: string; op: CommitType }> = [];
|
const conflicts: Array<{ secretId: string; op: CommitType }> = [];
|
||||||
let secretCreationCommits = secretApprovalSecrets.filter(({ op }) => op === CommitType.Create);
|
let secretCreationCommits = secretApprovalSecrets.filter(({ op }) => op === CommitType.Create);
|
||||||
if (secretCreationCommits.length) {
|
if (secretCreationCommits.length) {
|
||||||
const { secsGroupedByBlindIndex: conflictGroupByBlindIndex } =
|
const { secsGroupedByBlindIndex: conflictGroupByBlindIndex } = await secretService.fnSecretBlindIndexCheckV2({
|
||||||
await secretService.fnSecretBlindIndexCheckV2({
|
folderId,
|
||||||
folderId,
|
inputSecrets: secretCreationCommits.map(({ secretBlindIndex }) => {
|
||||||
inputSecrets: secretCreationCommits.map(({ secretBlindIndex }) => {
|
if (!secretBlindIndex) {
|
||||||
if (!secretBlindIndex) {
|
throw new BadRequestError({
|
||||||
throw new BadRequestError({
|
message: "Missing secret blind index"
|
||||||
message: "Missing secret blind index"
|
});
|
||||||
});
|
}
|
||||||
}
|
return { secretBlindIndex };
|
||||||
return { secretBlindIndex };
|
})
|
||||||
})
|
});
|
||||||
});
|
|
||||||
secretCreationCommits
|
secretCreationCommits
|
||||||
.filter(({ secretBlindIndex }) => conflictGroupByBlindIndex[secretBlindIndex || ""])
|
.filter(({ secretBlindIndex }) => conflictGroupByBlindIndex[secretBlindIndex || ""])
|
||||||
.forEach((el) => {
|
.forEach((el) => {
|
||||||
@@ -290,23 +261,19 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
|
|
||||||
let secretUpdationCommits = secretApprovalSecrets.filter(({ op }) => op === CommitType.Update);
|
let secretUpdationCommits = secretApprovalSecrets.filter(({ op }) => op === CommitType.Update);
|
||||||
if (secretUpdationCommits.length) {
|
if (secretUpdationCommits.length) {
|
||||||
const { secsGroupedByBlindIndex: conflictGroupByBlindIndex } =
|
const { secsGroupedByBlindIndex: conflictGroupByBlindIndex } = await secretService.fnSecretBlindIndexCheckV2({
|
||||||
await secretService.fnSecretBlindIndexCheckV2({
|
folderId,
|
||||||
folderId,
|
inputSecrets: secretUpdationCommits
|
||||||
inputSecrets: secretUpdationCommits
|
.filter(({ secretBlindIndex, secret }) => secret && secret.secretBlindIndex !== secretBlindIndex)
|
||||||
.filter(
|
.map(({ secretBlindIndex }) => {
|
||||||
({ secretBlindIndex, secret }) =>
|
if (!secretBlindIndex) {
|
||||||
secret && secret.secretBlindIndex !== secretBlindIndex
|
throw new BadRequestError({
|
||||||
)
|
message: "Missing secret blind index"
|
||||||
.map(({ secretBlindIndex }) => {
|
});
|
||||||
if (!secretBlindIndex) {
|
}
|
||||||
throw new BadRequestError({
|
return { secretBlindIndex };
|
||||||
message: "Missing secret blind index"
|
})
|
||||||
});
|
});
|
||||||
}
|
|
||||||
return { secretBlindIndex };
|
|
||||||
})
|
|
||||||
});
|
|
||||||
secretUpdationCommits
|
secretUpdationCommits
|
||||||
.filter(
|
.filter(
|
||||||
({ secretBlindIndex, secretId }) =>
|
({ secretBlindIndex, secretId }) =>
|
||||||
@@ -318,14 +285,11 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
|
|
||||||
secretUpdationCommits = secretUpdationCommits.filter(
|
secretUpdationCommits = secretUpdationCommits.filter(
|
||||||
({ secretBlindIndex, secretId }) =>
|
({ secretBlindIndex, secretId }) =>
|
||||||
Boolean(secretId) &&
|
Boolean(secretId) && (secretBlindIndex ? !conflictGroupByBlindIndex[secretBlindIndex] : true)
|
||||||
(secretBlindIndex ? !conflictGroupByBlindIndex[secretBlindIndex] : true)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const secretDeletionCommits = secretApprovalSecrets.filter(
|
const secretDeletionCommits = secretApprovalSecrets.filter(({ op }) => op === CommitType.Delete);
|
||||||
({ op }) => op === CommitType.Delete
|
|
||||||
);
|
|
||||||
|
|
||||||
const mergeStatus = await secretApprovalRequestDAL.transaction(async (tx) => {
|
const mergeStatus = await secretApprovalRequestDAL.transaction(async (tx) => {
|
||||||
const newSecrets = secretCreationCommits.length
|
const newSecrets = secretCreationCommits.length
|
||||||
@@ -442,27 +406,20 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
secretPath,
|
secretPath,
|
||||||
environment
|
environment
|
||||||
}: TGenerateSecretApprovalRequestDTO) => {
|
}: TGenerateSecretApprovalRequestDTO) => {
|
||||||
if (actor === ActorType.SERVICE)
|
if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" });
|
||||||
throw new BadRequestError({ message: "Cannot use service token" });
|
|
||||||
|
|
||||||
const { permission, membership } = await permissionService.getProjectPermission(
|
const { permission, membership } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
actor,
|
|
||||||
actorId,
|
|
||||||
projectId
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
||||||
);
|
);
|
||||||
|
|
||||||
const folder = await folderDAL.findBySecretPath(projectId, environment, secretPath);
|
const folder = await folderDAL.findBySecretPath(projectId, environment, secretPath);
|
||||||
if (!folder)
|
if (!folder) throw new BadRequestError({ message: "Folder not found", name: "GenSecretApproval" });
|
||||||
throw new BadRequestError({ message: "Folder not found", name: "GenSecretApproval" });
|
|
||||||
const folderId = folder.id;
|
const folderId = folder.id;
|
||||||
|
|
||||||
const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId });
|
const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId });
|
||||||
if (!blindIndexCfg)
|
if (!blindIndexCfg) throw new BadRequestError({ message: "Blind index not found", name: "Update secret" });
|
||||||
throw new BadRequestError({ message: "Blind index not found", name: "Update secret" });
|
|
||||||
|
|
||||||
const commits: Omit<TSecretApprovalRequestsSecretsInsert, "requestId">[] = [];
|
const commits: Omit<TSecretApprovalRequestsSecretsInsert, "requestId">[] = [];
|
||||||
const commitTagIds: Record<string, string[]> = {};
|
const commitTagIds: Record<string, string[]> = {};
|
||||||
@@ -496,38 +453,28 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
// get all blind index
|
// get all blind index
|
||||||
// Find all those secrets
|
// Find all those secrets
|
||||||
// if not throw not found
|
// if not throw not found
|
||||||
const { keyName2BlindIndex, secrets: secretsToBeUpdated } =
|
const { keyName2BlindIndex, secrets: secretsToBeUpdated } = await secretService.fnSecretBlindIndexCheck({
|
||||||
await secretService.fnSecretBlindIndexCheck({
|
inputSecrets: updatedSecrets,
|
||||||
inputSecrets: updatedSecrets,
|
folderId,
|
||||||
folderId,
|
isNew: false,
|
||||||
isNew: false,
|
blindIndexCfg
|
||||||
blindIndexCfg
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// now find any secret that needs to update its name
|
// now find any secret that needs to update its name
|
||||||
// same process as above
|
// same process as above
|
||||||
const nameUpdatedSecrets = updatedSecrets.filter(({ newSecretName }) =>
|
const nameUpdatedSecrets = updatedSecrets.filter(({ newSecretName }) => Boolean(newSecretName));
|
||||||
Boolean(newSecretName)
|
const { keyName2BlindIndex: newKeyName2BlindIndex } = await secretService.fnSecretBlindIndexCheck({
|
||||||
);
|
inputSecrets: nameUpdatedSecrets,
|
||||||
const { keyName2BlindIndex: newKeyName2BlindIndex } =
|
folderId,
|
||||||
await secretService.fnSecretBlindIndexCheck({
|
isNew: true,
|
||||||
inputSecrets: nameUpdatedSecrets,
|
blindIndexCfg
|
||||||
folderId,
|
});
|
||||||
isNew: true,
|
|
||||||
blindIndexCfg
|
|
||||||
});
|
|
||||||
|
|
||||||
const secsGroupedByBlindIndex = groupBy(
|
const secsGroupedByBlindIndex = groupBy(secretsToBeUpdated, (el) => el.secretBlindIndex as string);
|
||||||
secretsToBeUpdated,
|
|
||||||
(el) => el.secretBlindIndex as string
|
|
||||||
);
|
|
||||||
const updatedSecretIds = updatedSecrets.map(
|
const updatedSecretIds = updatedSecrets.map(
|
||||||
(el) => secsGroupedByBlindIndex[keyName2BlindIndex[el.secretName]][0].id
|
(el) => secsGroupedByBlindIndex[keyName2BlindIndex[el.secretName]][0].id
|
||||||
);
|
);
|
||||||
const latestSecretVersions = await secretVersionDAL.findLatestVersionMany(
|
const latestSecretVersions = await secretVersionDAL.findLatestVersionMany(folderId, updatedSecretIds);
|
||||||
folderId,
|
|
||||||
updatedSecretIds
|
|
||||||
);
|
|
||||||
commits.push(
|
commits.push(
|
||||||
...updatedSecrets.map(({ newSecretName, secretName, tagIds, ...el }) => {
|
...updatedSecrets.map(({ newSecretName, secretName, tagIds, ...el }) => {
|
||||||
const secretId = secsGroupedByBlindIndex[keyName2BlindIndex[secretName]][0].id;
|
const secretId = secsGroupedByBlindIndex[keyName2BlindIndex[secretName]][0].id;
|
||||||
@@ -562,17 +509,13 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
blindIndexCfg
|
blindIndexCfg
|
||||||
});
|
});
|
||||||
const secretsGroupedByBlindIndex = groupBy(secrets, (i) => {
|
const secretsGroupedByBlindIndex = groupBy(secrets, (i) => {
|
||||||
if (!i.secretBlindIndex)
|
if (!i.secretBlindIndex) throw new BadRequestError({ message: "Missing secret blind index" });
|
||||||
throw new BadRequestError({ message: "Missing secret blind index" });
|
|
||||||
return i.secretBlindIndex;
|
return i.secretBlindIndex;
|
||||||
});
|
});
|
||||||
const deletedSecretIds = deletedSecrets.map(
|
const deletedSecretIds = deletedSecrets.map(
|
||||||
(el) => secretsGroupedByBlindIndex[keyName2BlindIndex[el.secretName]][0].id
|
(el) => secretsGroupedByBlindIndex[keyName2BlindIndex[el.secretName]][0].id
|
||||||
);
|
);
|
||||||
const latestSecretVersions = await secretVersionDAL.findLatestVersionMany(
|
const latestSecretVersions = await secretVersionDAL.findLatestVersionMany(folderId, deletedSecretIds);
|
||||||
folderId,
|
|
||||||
deletedSecretIds
|
|
||||||
);
|
|
||||||
commits.push(
|
commits.push(
|
||||||
...deletedSecrets.map((el) => {
|
...deletedSecrets.map((el) => {
|
||||||
const secretId = secretsGroupedByBlindIndex[keyName2BlindIndex[el.secretName]][0].id;
|
const secretId = secretsGroupedByBlindIndex[keyName2BlindIndex[el.secretName]][0].id;
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
import {
|
import { TImmutableDBKeys, TSecretApprovalPolicies, TSecretApprovalRequestsSecrets } from "@app/db/schemas";
|
||||||
TImmutableDBKeys,
|
|
||||||
TSecretApprovalPolicies,
|
|
||||||
TSecretApprovalRequestsSecrets
|
|
||||||
} from "@app/db/schemas";
|
|
||||||
import { TProjectPermission } from "@app/lib/types";
|
import { TProjectPermission } from "@app/lib/types";
|
||||||
|
|
||||||
export enum CommitType {
|
export enum CommitType {
|
||||||
@@ -24,14 +20,7 @@ export enum ApprovalStatus {
|
|||||||
|
|
||||||
type TApprovalCreateSecret = Omit<
|
type TApprovalCreateSecret = Omit<
|
||||||
TSecretApprovalRequestsSecrets,
|
TSecretApprovalRequestsSecrets,
|
||||||
| TImmutableDBKeys
|
TImmutableDBKeys | "version" | "algorithm" | "keyEncoding" | "requestId" | "op" | "secretVersion" | "secretBlindIndex"
|
||||||
| "version"
|
|
||||||
| "algorithm"
|
|
||||||
| "keyEncoding"
|
|
||||||
| "requestId"
|
|
||||||
| "op"
|
|
||||||
| "secretVersion"
|
|
||||||
| "secretBlindIndex"
|
|
||||||
> & {
|
> & {
|
||||||
secretName: string;
|
secretName: string;
|
||||||
tagIds?: string[];
|
tagIds?: string[];
|
||||||
|
|||||||
@@ -14,21 +14,13 @@ export const secretRotationDALFactory = (db: TDbClient) => {
|
|||||||
const findQuery = (filter: TFindFilter<TSecretRotations & { projectId: string }>, tx: Knex) =>
|
const findQuery = (filter: TFindFilter<TSecretRotations & { projectId: string }>, tx: Knex) =>
|
||||||
tx(TableName.SecretRotation)
|
tx(TableName.SecretRotation)
|
||||||
.where(filter)
|
.where(filter)
|
||||||
.join(
|
.join(TableName.Environment, `${TableName.SecretRotation}.envId`, `${TableName.Environment}.id`)
|
||||||
TableName.Environment,
|
|
||||||
`${TableName.SecretRotation}.envId`,
|
|
||||||
`${TableName.Environment}.id`
|
|
||||||
)
|
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.SecretRotationOutput,
|
TableName.SecretRotationOutput,
|
||||||
`${TableName.SecretRotation}.id`,
|
`${TableName.SecretRotation}.id`,
|
||||||
`${TableName.SecretRotationOutput}.rotationId`
|
`${TableName.SecretRotationOutput}.rotationId`
|
||||||
)
|
)
|
||||||
.join(
|
.join(TableName.Secret, `${TableName.SecretRotationOutput}.secretId`, `${TableName.Secret}.id`)
|
||||||
TableName.Secret,
|
|
||||||
`${TableName.SecretRotationOutput}.secretId`,
|
|
||||||
`${TableName.Secret}.id`
|
|
||||||
)
|
|
||||||
.select(selectAllTableCols(TableName.SecretRotation))
|
.select(selectAllTableCols(TableName.SecretRotation))
|
||||||
.select(tx.ref("name").withSchema(TableName.Environment).as("envName"))
|
.select(tx.ref("name").withSchema(TableName.Environment).as("envName"))
|
||||||
.select(tx.ref("slug").withSchema(TableName.Environment).as("envSlug"))
|
.select(tx.ref("slug").withSchema(TableName.Environment).as("envSlug"))
|
||||||
@@ -102,11 +94,7 @@ export const secretRotationDALFactory = (db: TDbClient) => {
|
|||||||
const findById = async (id: string, tx?: Knex) => {
|
const findById = async (id: string, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const doc = await (tx || db)(TableName.SecretRotation)
|
const doc = await (tx || db)(TableName.SecretRotation)
|
||||||
.join(
|
.join(TableName.Environment, `${TableName.SecretRotation}.envId`, `${TableName.Environment}.id`)
|
||||||
TableName.Environment,
|
|
||||||
`${TableName.SecretRotation}.envId`,
|
|
||||||
`${TableName.Environment}.id`
|
|
||||||
)
|
|
||||||
.where({ [`${TableName.SecretRotation}.id` as "id"]: id })
|
.where({ [`${TableName.SecretRotation}.id` as "id"]: id })
|
||||||
.select(selectAllTableCols(TableName.SecretRotation))
|
.select(selectAllTableCols(TableName.SecretRotation))
|
||||||
.select(
|
.select(
|
||||||
@@ -125,8 +113,7 @@ export const secretRotationDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const findRotationOutputsByRotationId = async (rotationId: string) =>
|
const findRotationOutputsByRotationId = async (rotationId: string) => secretRotationOutputOrm.find({ rotationId });
|
||||||
secretRotationOutputOrm.find({ rotationId });
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...secretRotationOrm,
|
...secretRotationOrm,
|
||||||
|
|||||||
@@ -11,12 +11,7 @@ import knex from "knex";
|
|||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||||
|
|
||||||
import {
|
import { TAssignOp, TDbProviderClients, TDirectAssignOp, THttpProviderFunction } from "../templates/types";
|
||||||
TAssignOp,
|
|
||||||
TDbProviderClients,
|
|
||||||
TDirectAssignOp,
|
|
||||||
THttpProviderFunction
|
|
||||||
} from "../templates/types";
|
|
||||||
import { TSecretRotationData, TSecretRotationDbFn } from "./secret-rotation-queue-types";
|
import { TSecretRotationData, TSecretRotationDbFn } from "./secret-rotation-queue-types";
|
||||||
|
|
||||||
const REGEX = /\${([^}]+)}/g;
|
const REGEX = /\${([^}]+)}/g;
|
||||||
@@ -64,10 +59,7 @@ const getInterpolationValue = (variables: TSecretRotationData) => (key: string)
|
|||||||
return variables[type as keyof TSecretRotationData][keyName];
|
return variables[type as keyof TSecretRotationData][keyName];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const secretRotationHttpFn = async (
|
export const secretRotationHttpFn = async (func: THttpProviderFunction, variables: TSecretRotationData) => {
|
||||||
func: THttpProviderFunction,
|
|
||||||
variables: TSecretRotationData
|
|
||||||
) => {
|
|
||||||
// string interpolation
|
// string interpolation
|
||||||
const headers = interpolate(func.header, getInterpolationValue(variables));
|
const headers = interpolate(func.header, getInterpolationValue(variables));
|
||||||
const url = interpolate(func.url, getInterpolationValue(variables));
|
const url = interpolate(func.url, getInterpolationValue(variables));
|
||||||
@@ -117,10 +109,7 @@ export const secretRotationDbFn = async ({
|
|||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const secretRotationPreSetFn = (
|
export const secretRotationPreSetFn = (op: Record<string, TDirectAssignOp>, variables: TSecretRotationData) => {
|
||||||
op: Record<string, TDirectAssignOp>,
|
|
||||||
variables: TSecretRotationData
|
|
||||||
) => {
|
|
||||||
const getValFn = getInterpolationValue(variables);
|
const getValFn = getInterpolationValue(variables);
|
||||||
Object.entries(op || {}).forEach(([key, assignFn]) => {
|
Object.entries(op || {}).forEach(([key, assignFn]) => {
|
||||||
const [type, keyName] = key.split(".") as [keyof TSecretRotationData, string];
|
const [type, keyName] = key.split(".") as [keyof TSecretRotationData, string];
|
||||||
@@ -128,10 +117,7 @@ export const secretRotationPreSetFn = (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const secretRotationHttpSetFn = async (
|
export const secretRotationHttpSetFn = async (func: THttpProviderFunction, variables: TSecretRotationData) => {
|
||||||
func: THttpProviderFunction,
|
|
||||||
variables: TSecretRotationData
|
|
||||||
) => {
|
|
||||||
const getValFn = getInterpolationValue(variables);
|
const getValFn = getInterpolationValue(variables);
|
||||||
// http setter
|
// http setter
|
||||||
const res = await secretRotationHttpFn(func, variables);
|
const res = await secretRotationHttpFn(func, variables);
|
||||||
@@ -145,10 +131,7 @@ export const secretRotationHttpSetFn = async (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getDbSetQuery = (
|
export const getDbSetQuery = (db: TDbProviderClients, variables: { username: string; password: string }) => {
|
||||||
db: TDbProviderClients,
|
|
||||||
variables: { username: string; password: string }
|
|
||||||
) => {
|
|
||||||
if (db === TDbProviderClients.Pg) {
|
if (db === TDbProviderClients.Pg) {
|
||||||
return {
|
return {
|
||||||
query: `ALTER USER ?? WITH PASSWORD '${variables.password}'`,
|
query: `ALTER USER ?? WITH PASSWORD '${variables.password}'`,
|
||||||
|
|||||||
@@ -18,11 +18,7 @@ import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
|
|||||||
|
|
||||||
import { TSecretRotationDALFactory } from "../secret-rotation-dal";
|
import { TSecretRotationDALFactory } from "../secret-rotation-dal";
|
||||||
import { rotationTemplates } from "../templates";
|
import { rotationTemplates } from "../templates";
|
||||||
import {
|
import { TDbProviderClients, TProviderFunctionTypes, TSecretRotationProviderTemplate } from "../templates/types";
|
||||||
TDbProviderClients,
|
|
||||||
TProviderFunctionTypes,
|
|
||||||
TSecretRotationProviderTemplate
|
|
||||||
} from "../templates/types";
|
|
||||||
import {
|
import {
|
||||||
getDbSetQuery,
|
getDbSetQuery,
|
||||||
secretRotationDbFn,
|
secretRotationDbFn,
|
||||||
@@ -30,11 +26,7 @@ import {
|
|||||||
secretRotationHttpSetFn,
|
secretRotationHttpSetFn,
|
||||||
secretRotationPreSetFn
|
secretRotationPreSetFn
|
||||||
} from "./secret-rotation-queue-fn";
|
} from "./secret-rotation-queue-fn";
|
||||||
import {
|
import { TSecretRotationData, TSecretRotationDbFn, TSecretRotationEncData } from "./secret-rotation-queue-types";
|
||||||
TSecretRotationData,
|
|
||||||
TSecretRotationDbFn,
|
|
||||||
TSecretRotationEncData
|
|
||||||
} from "./secret-rotation-queue-types";
|
|
||||||
|
|
||||||
export type TSecretRotationQueueFactory = ReturnType<typeof secretRotationQueueFactory>;
|
export type TSecretRotationQueueFactory = ReturnType<typeof secretRotationQueueFactory>;
|
||||||
|
|
||||||
@@ -78,10 +70,7 @@ export const secretRotationQueueFactory = ({
|
|||||||
jobId: rotationId,
|
jobId: rotationId,
|
||||||
repeat: {
|
repeat: {
|
||||||
// on prod it this will be in days, in development this will be second
|
// on prod it this will be in days, in development this will be second
|
||||||
every:
|
every: appCfg.NODE_ENV === "development" ? secondsToMillis(interval) : daysToMillisecond(interval),
|
||||||
appCfg.NODE_ENV === "development"
|
|
||||||
? secondsToMillis(interval)
|
|
||||||
: daysToMillisecond(interval),
|
|
||||||
immediately: true
|
immediately: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,10 +84,7 @@ export const secretRotationQueueFactory = ({
|
|||||||
QueueJobs.SecretRotation,
|
QueueJobs.SecretRotation,
|
||||||
{
|
{
|
||||||
// on prod it this will be in days, in development this will be second
|
// on prod it this will be in days, in development this will be second
|
||||||
every:
|
every: appCfg.NODE_ENV === "development" ? secondsToMillis(interval) : daysToMillisecond(interval)
|
||||||
appCfg.NODE_ENV === "development"
|
|
||||||
? secondsToMillis(interval)
|
|
||||||
: daysToMillisecond(interval)
|
|
||||||
},
|
},
|
||||||
rotationId
|
rotationId
|
||||||
);
|
);
|
||||||
@@ -108,22 +94,16 @@ export const secretRotationQueueFactory = ({
|
|||||||
const { rotationId } = job.data;
|
const { rotationId } = job.data;
|
||||||
logger.info(`secretRotationQueue.process: [rotationDocument=${rotationId}]`);
|
logger.info(`secretRotationQueue.process: [rotationDocument=${rotationId}]`);
|
||||||
const secretRotation = await secretRotationDAL.findById(rotationId);
|
const secretRotation = await secretRotationDAL.findById(rotationId);
|
||||||
const rotationProvider = rotationTemplates.find(
|
const rotationProvider = rotationTemplates.find(({ name }) => name === secretRotation?.provider);
|
||||||
({ name }) => name === secretRotation?.provider
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!rotationProvider || !secretRotation)
|
if (!rotationProvider || !secretRotation) throw new DisableRotationErrors({ message: "Provider not found" });
|
||||||
throw new DisableRotationErrors({ message: "Provider not found" });
|
|
||||||
|
|
||||||
const rotationOutputs = await secretRotationDAL.findRotationOutputsByRotationId(rotationId);
|
const rotationOutputs = await secretRotationDAL.findRotationOutputsByRotationId(rotationId);
|
||||||
if (!rotationOutputs.length)
|
if (!rotationOutputs.length) throw new DisableRotationErrors({ message: "Secrets not found" });
|
||||||
throw new DisableRotationErrors({ message: "Secrets not found" });
|
|
||||||
|
|
||||||
// deep copy
|
// deep copy
|
||||||
const provider = JSON.parse(
|
const provider = JSON.parse(JSON.stringify(rotationProvider)) as TSecretRotationProviderTemplate;
|
||||||
JSON.stringify(rotationProvider)
|
|
||||||
) as TSecretRotationProviderTemplate;
|
|
||||||
|
|
||||||
// now get the encrypted variable values
|
// now get the encrypted variable values
|
||||||
// in includes the inputs, the previous outputs
|
// in includes the inputs, the previous outputs
|
||||||
@@ -156,20 +136,11 @@ export const secretRotationQueueFactory = ({
|
|||||||
? variables.inputs.username2
|
? variables.inputs.username2
|
||||||
: variables.inputs.username1;
|
: variables.inputs.username1;
|
||||||
} else {
|
} else {
|
||||||
newCredential.internal.username = lastCred
|
newCredential.internal.username = lastCred ? lastCred.internal.username : variables.inputs.username1;
|
||||||
? lastCred.internal.username
|
|
||||||
: variables.inputs.username1;
|
|
||||||
}
|
}
|
||||||
// set a random value for new password
|
// set a random value for new password
|
||||||
newCredential.internal.rotated_password = alphaNumericNanoId(32);
|
newCredential.internal.rotated_password = alphaNumericNanoId(32);
|
||||||
const {
|
const { admin_username: username, admin_password: password, host, database, port, ca } = newCredential.inputs;
|
||||||
admin_username: username,
|
|
||||||
admin_password: password,
|
|
||||||
host,
|
|
||||||
database,
|
|
||||||
port,
|
|
||||||
ca
|
|
||||||
} = newCredential.inputs;
|
|
||||||
const dbFunctionArg = {
|
const dbFunctionArg = {
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
@@ -177,10 +148,7 @@ export const secretRotationQueueFactory = ({
|
|||||||
database,
|
database,
|
||||||
port,
|
port,
|
||||||
ca: ca as string,
|
ca: ca as string,
|
||||||
client:
|
client: provider.template.client === TDbProviderClients.MySql ? "mysql2" : provider.template.client
|
||||||
provider.template.client === TDbProviderClients.MySql
|
|
||||||
? "mysql2"
|
|
||||||
: provider.template.client
|
|
||||||
} as TSecretRotationDbFn;
|
} as TSecretRotationDbFn;
|
||||||
// set function
|
// set function
|
||||||
await secretRotationDbFn({
|
await secretRotationDbFn({
|
||||||
|
|||||||
@@ -47,10 +47,7 @@ export const secretRotationServiceFactory = ({
|
|||||||
}: TSecretRotationServiceFactoryDep) => {
|
}: TSecretRotationServiceFactoryDep) => {
|
||||||
const getProviderTemplates = async ({ actor, actorId, projectId }: TProjectPermission) => {
|
const getProviderTemplates = async ({ actor, actorId, projectId }: TProjectPermission) => {
|
||||||
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRotation);
|
||||||
ProjectPermissionActions.Read,
|
|
||||||
ProjectPermissionSub.SecretRotation
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
custom: [],
|
custom: [],
|
||||||
@@ -93,8 +90,7 @@ export const secretRotationServiceFactory = ({
|
|||||||
const plan = await licenseService.getPlan(project.orgId);
|
const plan = await licenseService.getPlan(project.orgId);
|
||||||
if (!plan.secretRotation)
|
if (!plan.secretRotation)
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message:
|
message: "Failed to add secret rotation due to plan restriction. Upgrade plan to add secret rotation."
|
||||||
"Failed to add secret rotation due to plan restriction. Upgrade plan to add secret rotation."
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const selectedTemplate = rotationTemplates.find(({ name }) => name === provider);
|
const selectedTemplate = rotationTemplates.find(({ name }) => name === provider);
|
||||||
@@ -152,24 +148,14 @@ export const secretRotationServiceFactory = ({
|
|||||||
const [doc] = await secretRotationDAL.find({ id: rotationId });
|
const [doc] = await secretRotationDAL.find({ id: rotationId });
|
||||||
if (!doc) throw new BadRequestError({ message: "Rotation not found" });
|
if (!doc) throw new BadRequestError({ message: "Rotation not found" });
|
||||||
|
|
||||||
const { permission } = await permissionService.getProjectPermission(
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, doc.projectId);
|
||||||
actor,
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRotation);
|
||||||
actorId,
|
|
||||||
doc.projectId
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
ProjectPermissionActions.Read,
|
|
||||||
ProjectPermissionSub.SecretRotation
|
|
||||||
);
|
|
||||||
return doc;
|
return doc;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getByProjectId = async ({ actorId, projectId, actor }: TListByProjectIdDTO) => {
|
const getByProjectId = async ({ actorId, projectId, actor }: TListByProjectIdDTO) => {
|
||||||
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRotation);
|
||||||
ProjectPermissionActions.Read,
|
|
||||||
ProjectPermissionSub.SecretRotation
|
|
||||||
);
|
|
||||||
const doc = await secretRotationDAL.find({ projectId });
|
const doc = await secretRotationDAL.find({ projectId });
|
||||||
return doc;
|
return doc;
|
||||||
};
|
};
|
||||||
@@ -182,19 +168,11 @@ export const secretRotationServiceFactory = ({
|
|||||||
const plan = await licenseService.getPlan(project.orgId);
|
const plan = await licenseService.getPlan(project.orgId);
|
||||||
if (!plan.secretRotation)
|
if (!plan.secretRotation)
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message:
|
message: "Failed to add secret rotation due to plan restriction. Upgrade plan to add secret rotation."
|
||||||
"Failed to add secret rotation due to plan restriction. Upgrade plan to add secret rotation."
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const { permission } = await permissionService.getProjectPermission(
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, doc.projectId);
|
||||||
actor,
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SecretRotation);
|
||||||
actorId,
|
|
||||||
doc.projectId
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
ProjectPermissionActions.Edit,
|
|
||||||
ProjectPermissionSub.SecretRotation
|
|
||||||
);
|
|
||||||
await secretRotationQueue.removeFromQueue(doc.id, doc.interval);
|
await secretRotationQueue.removeFromQueue(doc.id, doc.interval);
|
||||||
await secretRotationQueue.addToQueue(doc.id, doc.interval);
|
await secretRotationQueue.addToQueue(doc.id, doc.interval);
|
||||||
return doc;
|
return doc;
|
||||||
@@ -204,11 +182,7 @@ export const secretRotationServiceFactory = ({
|
|||||||
const doc = await secretRotationDAL.findById(rotationId);
|
const doc = await secretRotationDAL.findById(rotationId);
|
||||||
if (!doc) throw new BadRequestError({ message: "Rotation not found" });
|
if (!doc) throw new BadRequestError({ message: "Rotation not found" });
|
||||||
|
|
||||||
const { permission } = await permissionService.getProjectPermission(
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, doc.projectId);
|
||||||
actor,
|
|
||||||
actorId,
|
|
||||||
doc.projectId
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Delete,
|
ProjectPermissionActions.Delete,
|
||||||
ProjectPermissionSub.SecretRotation
|
ProjectPermissionSub.SecretRotation
|
||||||
|
|||||||
@@ -23,15 +23,7 @@ export const MYSQL_TEMPLATE = {
|
|||||||
},
|
},
|
||||||
ca: { type: "string", desc: "SSL certificate for db auth(string)" }
|
ca: { type: "string", desc: "SSL certificate for db auth(string)" }
|
||||||
},
|
},
|
||||||
required: [
|
required: ["admin_username", "admin_password", "host", "database", "username1", "username2", "port"],
|
||||||
"admin_username",
|
|
||||||
"admin_password",
|
|
||||||
"host",
|
|
||||||
"database",
|
|
||||||
"username1",
|
|
||||||
"username2",
|
|
||||||
"port"
|
|
||||||
],
|
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
},
|
},
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -23,15 +23,7 @@ export const POSTGRES_TEMPLATE = {
|
|||||||
},
|
},
|
||||||
ca: { type: "string", desc: "SSL certificate for db auth(string)" }
|
ca: { type: "string", desc: "SSL certificate for db auth(string)" }
|
||||||
},
|
},
|
||||||
required: [
|
required: ["admin_username", "admin_password", "host", "database", "username1", "username2", "port"],
|
||||||
"admin_username",
|
|
||||||
"admin_password",
|
|
||||||
"host",
|
|
||||||
"database",
|
|
||||||
"username1",
|
|
||||||
"username2",
|
|
||||||
"port"
|
|
||||||
],
|
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
},
|
},
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -12,11 +12,7 @@ export const gitAppDALFactory = (db: TDbClient) => {
|
|||||||
|
|
||||||
const upsert = async (data: TGitAppOrgInsert, tx?: Knex) => {
|
const upsert = async (data: TGitAppOrgInsert, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const [doc] = await (tx || db)(TableName.GitAppOrg)
|
const [doc] = await (tx || db)(TableName.GitAppOrg).insert(data).onConflict("orgId").merge().returning("*");
|
||||||
.insert(data)
|
|
||||||
.onConflict("orgId")
|
|
||||||
.merge()
|
|
||||||
.returning("*");
|
|
||||||
return doc;
|
return doc;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "UpsertGitAppOrm" });
|
throw new DatabaseError({ error, name: "UpsertGitAppOrm" });
|
||||||
|
|||||||
@@ -12,10 +12,7 @@ export const secretScanningDALFactory = (db: TDbClient) => {
|
|||||||
|
|
||||||
const upsert = async (data: TSecretScanningGitRisksInsert[], tx?: Knex) => {
|
const upsert = async (data: TSecretScanningGitRisksInsert[], tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const docs = await (tx || db)(TableName.SecretScanningGitRisk)
|
const docs = await (tx || db)(TableName.SecretScanningGitRisk).insert(data).onConflict("fingerprint").merge();
|
||||||
.insert(data)
|
|
||||||
.onConflict("fingerprint")
|
|
||||||
.merge();
|
|
||||||
return docs;
|
return docs;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "GitRiskUpsert" });
|
throw new DatabaseError({ error, name: "GitRiskUpsert" });
|
||||||
|
|||||||
@@ -10,15 +10,8 @@ import { TTelemetryServiceFactory } from "@app/services/telemetry/telemetry-serv
|
|||||||
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
|
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
|
||||||
|
|
||||||
import { TSecretScanningDALFactory } from "../secret-scanning-dal";
|
import { TSecretScanningDALFactory } from "../secret-scanning-dal";
|
||||||
import {
|
import { scanContentAndGetFindings, scanFullRepoContentAndGetFindings } from "./secret-scanning-fns";
|
||||||
scanContentAndGetFindings,
|
import { SecretMatch, TScanFullRepoEventPayload, TScanPushEventPayload } from "./secret-scanning-queue-types";
|
||||||
scanFullRepoContentAndGetFindings
|
|
||||||
} from "./secret-scanning-fns";
|
|
||||||
import {
|
|
||||||
SecretMatch,
|
|
||||||
TScanFullRepoEventPayload,
|
|
||||||
TScanPushEventPayload
|
|
||||||
} from "./secret-scanning-queue-types";
|
|
||||||
|
|
||||||
type TSecretScanningQueueFactoryDep = {
|
type TSecretScanningQueueFactoryDep = {
|
||||||
queueService: TQueueServiceFactory;
|
queueService: TQueueServiceFactory;
|
||||||
|
|||||||
@@ -4,10 +4,7 @@ import { ForbiddenError } from "@casl/ability";
|
|||||||
import { WebhookEventMap } from "@octokit/webhooks-types";
|
import { WebhookEventMap } from "@octokit/webhooks-types";
|
||||||
import { ProbotOctokit } from "probot";
|
import { ProbotOctokit } from "probot";
|
||||||
|
|
||||||
import {
|
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
OrgPermissionActions,
|
|
||||||
OrgPermissionSubjects
|
|
||||||
} from "@app/ee/services/permission/org-permission";
|
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { UnauthorizedError } from "@app/lib/errors";
|
import { UnauthorizedError } from "@app/lib/errors";
|
||||||
@@ -44,30 +41,19 @@ export const secretScanningServiceFactory = ({
|
|||||||
}: TSecretScanningServiceFactoryDep) => {
|
}: TSecretScanningServiceFactoryDep) => {
|
||||||
const createInstallationSession = async ({ actor, orgId, actorId }: TInstallAppSessionDTO) => {
|
const createInstallationSession = async ({ actor, orgId, actorId }: TInstallAppSessionDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.SecretScanning);
|
||||||
OrgPermissionActions.Create,
|
|
||||||
OrgPermissionSubjects.SecretScanning
|
|
||||||
);
|
|
||||||
|
|
||||||
const sessionId = crypto.randomBytes(16).toString("hex");
|
const sessionId = crypto.randomBytes(16).toString("hex");
|
||||||
await gitAppInstallSessionDAL.upsert({ orgId, sessionId, userId: actorId });
|
await gitAppInstallSessionDAL.upsert({ orgId, sessionId, userId: actorId });
|
||||||
return { sessionId };
|
return { sessionId };
|
||||||
};
|
};
|
||||||
|
|
||||||
const linkInstallationToOrg = async ({
|
const linkInstallationToOrg = async ({ sessionId, actorId, installationId, actor }: TLinkInstallSessionDTO) => {
|
||||||
sessionId,
|
|
||||||
actorId,
|
|
||||||
installationId,
|
|
||||||
actor
|
|
||||||
}: TLinkInstallSessionDTO) => {
|
|
||||||
const session = await gitAppInstallSessionDAL.findOne({ sessionId });
|
const session = await gitAppInstallSessionDAL.findOne({ sessionId });
|
||||||
if (!session) throw new UnauthorizedError({ message: "Session not found" });
|
if (!session) throw new UnauthorizedError({ message: "Session not found" });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, session.orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, session.orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.SecretScanning);
|
||||||
OrgPermissionActions.Create,
|
|
||||||
OrgPermissionSubjects.SecretScanning
|
|
||||||
);
|
|
||||||
const installatedApp = await gitAppOrgDAL.transaction(async (tx) => {
|
const installatedApp = await gitAppOrgDAL.transaction(async (tx) => {
|
||||||
await gitAppInstallSessionDAL.deleteById(session.id, tx);
|
await gitAppInstallSessionDAL.deleteById(session.id, tx);
|
||||||
return gitAppOrgDAL.upsert({ orgId: session.orgId, installationId, userId: actorId }, tx);
|
return gitAppOrgDAL.upsert({ orgId: session.orgId, installationId, userId: actorId }, tx);
|
||||||
@@ -99,10 +85,7 @@ export const secretScanningServiceFactory = ({
|
|||||||
|
|
||||||
const getOrgInstallationStatus = async ({ actorId, orgId, actor }: TGetOrgInstallStatusDTO) => {
|
const getOrgInstallationStatus = async ({ actorId, orgId, actor }: TGetOrgInstallStatusDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.SecretScanning);
|
||||||
OrgPermissionActions.Read,
|
|
||||||
OrgPermissionSubjects.SecretScanning
|
|
||||||
);
|
|
||||||
|
|
||||||
const appInstallation = await gitAppOrgDAL.findOne({ orgId });
|
const appInstallation = await gitAppOrgDAL.findOne({ orgId });
|
||||||
return Boolean(appInstallation);
|
return Boolean(appInstallation);
|
||||||
@@ -110,26 +93,14 @@ export const secretScanningServiceFactory = ({
|
|||||||
|
|
||||||
const getRisksByOrg = async ({ actor, orgId, actorId }: TGetOrgRisksDTO) => {
|
const getRisksByOrg = async ({ actor, orgId, actorId }: TGetOrgRisksDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.SecretScanning);
|
||||||
OrgPermissionActions.Read,
|
|
||||||
OrgPermissionSubjects.SecretScanning
|
|
||||||
);
|
|
||||||
const risks = await secretScanningDAL.find({ orgId }, { sort: [["createdAt", "desc"]] });
|
const risks = await secretScanningDAL.find({ orgId }, { sort: [["createdAt", "desc"]] });
|
||||||
return { risks };
|
return { risks };
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateRiskStatus = async ({
|
const updateRiskStatus = async ({ actorId, orgId, actor, riskId, status }: TUpdateRiskStatusDTO) => {
|
||||||
actorId,
|
|
||||||
orgId,
|
|
||||||
actor,
|
|
||||||
riskId,
|
|
||||||
status
|
|
||||||
}: TUpdateRiskStatusDTO) => {
|
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.SecretScanning);
|
||||||
OrgPermissionActions.Edit,
|
|
||||||
OrgPermissionSubjects.SecretScanning
|
|
||||||
);
|
|
||||||
|
|
||||||
const isRiskResolved = Boolean(
|
const isRiskResolved = Boolean(
|
||||||
[
|
[
|
||||||
@@ -169,9 +140,7 @@ export const secretScanningServiceFactory = ({
|
|||||||
const handleRepoDeleteEvent = async (installationId: string, repositoryIds: string[]) => {
|
const handleRepoDeleteEvent = async (installationId: string, repositoryIds: string[]) => {
|
||||||
await secretScanningDAL.transaction(async (tx) => {
|
await secretScanningDAL.transaction(async (tx) => {
|
||||||
if (repositoryIds.length) {
|
if (repositoryIds.length) {
|
||||||
await Promise.all(
|
await Promise.all(repositoryIds.map((repoId) => secretScanningDAL.delete({ repositoryId: repoId }, tx)));
|
||||||
repositoryIds.map((repoId) => secretScanningDAL.delete({ repositoryId: repoId }, tx))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
await gitAppOrgDAL.delete({ installationId }, tx);
|
await gitAppOrgDAL.delete({ installationId }, tx);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -29,17 +29,11 @@ type TSecretSnapshotServiceFactoryDep = {
|
|||||||
snapshotSecretDAL: TSnapshotSecretDALFactory;
|
snapshotSecretDAL: TSnapshotSecretDALFactory;
|
||||||
snapshotFolderDAL: TSnapshotFolderDALFactory;
|
snapshotFolderDAL: TSnapshotFolderDALFactory;
|
||||||
secretVersionDAL: Pick<TSecretVersionDALFactory, "insertMany" | "findLatestVersionByFolderId">;
|
secretVersionDAL: Pick<TSecretVersionDALFactory, "insertMany" | "findLatestVersionByFolderId">;
|
||||||
folderVersionDAL: Pick<
|
folderVersionDAL: Pick<TSecretFolderVersionDALFactory, "findLatestVersionByFolderId" | "insertMany">;
|
||||||
TSecretFolderVersionDALFactory,
|
|
||||||
"findLatestVersionByFolderId" | "insertMany"
|
|
||||||
>;
|
|
||||||
secretDAL: Pick<TSecretDALFactory, "delete" | "insertMany">;
|
secretDAL: Pick<TSecretDALFactory, "delete" | "insertMany">;
|
||||||
secretTagDAL: Pick<TSecretTagDALFactory, "saveTagsToSecret">;
|
secretTagDAL: Pick<TSecretTagDALFactory, "saveTagsToSecret">;
|
||||||
secretVersionTagDAL: Pick<TSecretVersionTagDALFactory, "insertMany">;
|
secretVersionTagDAL: Pick<TSecretVersionTagDALFactory, "insertMany">;
|
||||||
folderDAL: Pick<
|
folderDAL: Pick<TSecretFolderDALFactory, "findById" | "findBySecretPath" | "delete" | "insertMany">;
|
||||||
TSecretFolderDALFactory,
|
|
||||||
"findById" | "findBySecretPath" | "delete" | "insertMany"
|
|
||||||
>;
|
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||||
licenseService: Pick<TLicenseServiceFactory, "isValidLicense">;
|
licenseService: Pick<TLicenseServiceFactory, "isValidLicense">;
|
||||||
};
|
};
|
||||||
@@ -67,10 +61,7 @@ export const secretSnapshotServiceFactory = ({
|
|||||||
path
|
path
|
||||||
}: TProjectSnapshotCountDTO) => {
|
}: TProjectSnapshotCountDTO) => {
|
||||||
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
|
||||||
ProjectPermissionActions.Read,
|
|
||||||
ProjectPermissionSub.SecretRollback
|
|
||||||
);
|
|
||||||
|
|
||||||
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
|
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
|
||||||
if (!folder) throw new BadRequestError({ message: "Folder not found" });
|
if (!folder) throw new BadRequestError({ message: "Folder not found" });
|
||||||
@@ -89,40 +80,26 @@ export const secretSnapshotServiceFactory = ({
|
|||||||
offset = 0
|
offset = 0
|
||||||
}: TProjectSnapshotListDTO) => {
|
}: TProjectSnapshotListDTO) => {
|
||||||
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
|
||||||
ProjectPermissionActions.Read,
|
|
||||||
ProjectPermissionSub.SecretRollback
|
|
||||||
);
|
|
||||||
|
|
||||||
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
|
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
|
||||||
if (!folder) throw new BadRequestError({ message: "Folder not found" });
|
if (!folder) throw new BadRequestError({ message: "Folder not found" });
|
||||||
|
|
||||||
const snapshots = await snapshotDAL.find(
|
const snapshots = await snapshotDAL.find({ folderId: folder.id }, { limit, offset, sort: [["createdAt", "desc"]] });
|
||||||
{ folderId: folder.id },
|
|
||||||
{ limit, offset, sort: [["createdAt", "desc"]] }
|
|
||||||
);
|
|
||||||
return snapshots;
|
return snapshots;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getSnapshotData = async ({ actorId, actor, id }: TGetSnapshotDataDTO) => {
|
const getSnapshotData = async ({ actorId, actor, id }: TGetSnapshotDataDTO) => {
|
||||||
const snapshot = await snapshotDAL.findSecretSnapshotDataById(id);
|
const snapshot = await snapshotDAL.findSecretSnapshotDataById(id);
|
||||||
if (!snapshot) throw new BadRequestError({ message: "Snapshot not found" });
|
if (!snapshot) throw new BadRequestError({ message: "Snapshot not found" });
|
||||||
const { permission } = await permissionService.getProjectPermission(
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, snapshot.projectId);
|
||||||
actor,
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
|
||||||
actorId,
|
|
||||||
snapshot.projectId
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
ProjectPermissionActions.Read,
|
|
||||||
ProjectPermissionSub.SecretRollback
|
|
||||||
);
|
|
||||||
return snapshot;
|
return snapshot;
|
||||||
};
|
};
|
||||||
|
|
||||||
const performSnapshot = async (folderId: string) => {
|
const performSnapshot = async (folderId: string) => {
|
||||||
try {
|
try {
|
||||||
if (!licenseService.isValidLicense)
|
if (!licenseService.isValidLicense) throw new InternalServerError({ message: "Invalid license" });
|
||||||
throw new InternalServerError({ message: "Invalid license" });
|
|
||||||
|
|
||||||
const snapshot = await snapshotDAL.transaction(async (tx) => {
|
const snapshot = await snapshotDAL.transaction(async (tx) => {
|
||||||
const folder = await folderDAL.findById(folderId, tx);
|
const folder = await folderDAL.findById(folderId, tx);
|
||||||
@@ -170,11 +147,7 @@ export const secretSnapshotServiceFactory = ({
|
|||||||
const snapshot = await snapshotDAL.findById(snapshotId);
|
const snapshot = await snapshotDAL.findById(snapshotId);
|
||||||
if (!snapshot) throw new BadRequestError({ message: "Snapshot not found" });
|
if (!snapshot) throw new BadRequestError({ message: "Snapshot not found" });
|
||||||
|
|
||||||
const { permission } = await permissionService.getProjectPermission(
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, snapshot.projectId);
|
||||||
actor,
|
|
||||||
actorId,
|
|
||||||
snapshot.projectId
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Create,
|
ProjectPermissionActions.Create,
|
||||||
ProjectPermissionSub.SecretRollback
|
ProjectPermissionSub.SecretRollback
|
||||||
@@ -199,9 +172,7 @@ export const secretSnapshotServiceFactory = ({
|
|||||||
id,
|
id,
|
||||||
// this means don't bump up the version if not root folder
|
// this means don't bump up the version if not root folder
|
||||||
// because below ones can be same version as nothing changed
|
// because below ones can be same version as nothing changed
|
||||||
version: deletedTopLevelFolders[folderId]
|
version: deletedTopLevelFolders[folderId] ? latestFolderVersion + 1 : latestFolderVersion,
|
||||||
? latestFolderVersion + 1
|
|
||||||
: latestFolderVersion,
|
|
||||||
name,
|
name,
|
||||||
parentId: folderId
|
parentId: folderId
|
||||||
}))
|
}))
|
||||||
@@ -211,22 +182,10 @@ export const secretSnapshotServiceFactory = ({
|
|||||||
const secrets = await secretDAL.insertMany(
|
const secrets = await secretDAL.insertMany(
|
||||||
rollbackSnaps.flatMap(({ secretVersions, folderId }) =>
|
rollbackSnaps.flatMap(({ secretVersions, folderId }) =>
|
||||||
secretVersions.map(
|
secretVersions.map(
|
||||||
({
|
({ latestSecretVersion, version, updatedAt, createdAt, secretId, envId, id, tags, ...el }) => ({
|
||||||
latestSecretVersion,
|
|
||||||
version,
|
|
||||||
updatedAt,
|
|
||||||
createdAt,
|
|
||||||
secretId,
|
|
||||||
envId,
|
|
||||||
id,
|
|
||||||
tags,
|
|
||||||
...el
|
|
||||||
}) => ({
|
|
||||||
...el,
|
...el,
|
||||||
id: secretId,
|
id: secretId,
|
||||||
version: deletedTopLevelSecsGroupById[secretId]
|
version: deletedTopLevelSecsGroupById[secretId] ? latestSecretVersion + 1 : latestSecretVersion,
|
||||||
? latestSecretVersion + 1
|
|
||||||
: latestSecretVersion,
|
|
||||||
folderId
|
folderId
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@@ -239,8 +198,7 @@ export const secretSnapshotServiceFactory = ({
|
|||||||
secretVersions.forEach((secVer) => {
|
secretVersions.forEach((secVer) => {
|
||||||
secVer.tags.forEach((tag) => {
|
secVer.tags.forEach((tag) => {
|
||||||
secretTagsToBeInsert.push({ secretsId: secVer.secretId, secret_tagsId: tag.id });
|
secretTagsToBeInsert.push({ secretsId: secVer.secretId, secret_tagsId: tag.id });
|
||||||
if (!secretVerTagToBeInsert?.[secVer.secretId])
|
if (!secretVerTagToBeInsert?.[secVer.secretId]) secretVerTagToBeInsert[secVer.secretId] = [];
|
||||||
secretVerTagToBeInsert[secVer.secretId] = [];
|
|
||||||
secretVerTagToBeInsert[secVer.secretId].push(tag.id);
|
secretVerTagToBeInsert[secVer.secretId].push(tag.id);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -57,11 +57,7 @@ export const snapshotDALFactory = (db: TDbClient) => {
|
|||||||
const data = await (tx || db)(TableName.Snapshot)
|
const data = await (tx || db)(TableName.Snapshot)
|
||||||
.where(`${TableName.Snapshot}.id`, snapshotId)
|
.where(`${TableName.Snapshot}.id`, snapshotId)
|
||||||
.join(TableName.Environment, `${TableName.Snapshot}.envId`, `${TableName.Environment}.id`)
|
.join(TableName.Environment, `${TableName.Snapshot}.envId`, `${TableName.Environment}.id`)
|
||||||
.leftJoin(
|
.leftJoin(TableName.SnapshotSecret, `${TableName.Snapshot}.id`, `${TableName.SnapshotSecret}.snapshotId`)
|
||||||
TableName.SnapshotSecret,
|
|
||||||
`${TableName.Snapshot}.id`,
|
|
||||||
`${TableName.SnapshotSecret}.snapshotId`
|
|
||||||
)
|
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.SecretVersion,
|
TableName.SecretVersion,
|
||||||
`${TableName.SnapshotSecret}.secretVersionId`,
|
`${TableName.SnapshotSecret}.secretVersionId`,
|
||||||
@@ -77,11 +73,7 @@ export const snapshotDALFactory = (db: TDbClient) => {
|
|||||||
`${TableName.SecretVersionTag}.${TableName.SecretTag}Id`,
|
`${TableName.SecretVersionTag}.${TableName.SecretTag}Id`,
|
||||||
`${TableName.SecretTag}.id`
|
`${TableName.SecretTag}.id`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(TableName.SnapshotFolder, `${TableName.SnapshotFolder}.snapshotId`, `${TableName.Snapshot}.id`)
|
||||||
TableName.SnapshotFolder,
|
|
||||||
`${TableName.SnapshotFolder}.snapshotId`,
|
|
||||||
`${TableName.Snapshot}.id`
|
|
||||||
)
|
|
||||||
.leftJoin<TSecretFolderVersions>(
|
.leftJoin<TSecretFolderVersions>(
|
||||||
TableName.SecretFolderVersion,
|
TableName.SecretFolderVersion,
|
||||||
`${TableName.SnapshotFolder}.folderVersionId`,
|
`${TableName.SnapshotFolder}.folderVersionId`,
|
||||||
@@ -131,13 +123,13 @@ export const snapshotDALFactory = (db: TDbClient) => {
|
|||||||
{
|
{
|
||||||
key: "tagVersionId",
|
key: "tagVersionId",
|
||||||
label: "tags" as const,
|
label: "tags" as const,
|
||||||
mapper: ({
|
mapper: ({ tagId: id, tagName: name, tagSlug: slug, tagColor: color, tagVersionId: vId }) => ({
|
||||||
tagId: id,
|
id,
|
||||||
tagName: name,
|
name,
|
||||||
tagSlug: slug,
|
slug,
|
||||||
tagColor: color,
|
color,
|
||||||
tagVersionId: vId
|
vId
|
||||||
}) => ({ id, name, slug, color, vId })
|
})
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -192,11 +184,7 @@ export const snapshotDALFactory = (db: TDbClient) => {
|
|||||||
)
|
)
|
||||||
.from(TableName.Snapshot)
|
.from(TableName.Snapshot)
|
||||||
.join<TSecretSnapshots, TSecretSnapshots & { secretId: string; max: number }>(
|
.join<TSecretSnapshots, TSecretSnapshots & { secretId: string; max: number }>(
|
||||||
db(TableName.Snapshot)
|
db(TableName.Snapshot).groupBy("folderId").max("createdAt").select("folderId").as("latestVersion"),
|
||||||
.groupBy("folderId")
|
|
||||||
.max("createdAt")
|
|
||||||
.select("folderId")
|
|
||||||
.as("latestVersion"),
|
|
||||||
`${TableName.Snapshot}.createdAt`,
|
`${TableName.Snapshot}.createdAt`,
|
||||||
"latestVersion.max"
|
"latestVersion.max"
|
||||||
)
|
)
|
||||||
@@ -215,11 +203,7 @@ export const snapshotDALFactory = (db: TDbClient) => {
|
|||||||
})
|
})
|
||||||
.orderBy("depth", "asc")
|
.orderBy("depth", "asc")
|
||||||
.from<TSecretSnapshots & { folderVerId: string; folderVerName: string }>("parent")
|
.from<TSecretSnapshots & { folderVerId: string; folderVerName: string }>("parent")
|
||||||
.leftJoin<TSecretSnapshots>(
|
.leftJoin<TSecretSnapshots>(TableName.SnapshotSecret, `parent.id`, `${TableName.SnapshotSecret}.snapshotId`)
|
||||||
TableName.SnapshotSecret,
|
|
||||||
`parent.id`,
|
|
||||||
`${TableName.SnapshotSecret}.snapshotId`
|
|
||||||
)
|
|
||||||
.leftJoin<TSecretVersions>(
|
.leftJoin<TSecretVersions>(
|
||||||
TableName.SecretVersion,
|
TableName.SecretVersion,
|
||||||
`${TableName.SnapshotSecret}.secretVersionId`,
|
`${TableName.SnapshotSecret}.secretVersionId`,
|
||||||
@@ -272,11 +256,7 @@ export const snapshotDALFactory = (db: TDbClient) => {
|
|||||||
const formated = sqlNestRelationships({
|
const formated = sqlNestRelationships({
|
||||||
data,
|
data,
|
||||||
key: "snapshotId",
|
key: "snapshotId",
|
||||||
parentMapper: ({
|
parentMapper: ({ snapshotId: id, snapshotFolderId: folderId, snapshotParentFolderId: parentFolderId }) => ({
|
||||||
snapshotId: id,
|
|
||||||
snapshotFolderId: folderId,
|
|
||||||
snapshotParentFolderId: parentFolderId
|
|
||||||
}) => ({
|
|
||||||
id,
|
id,
|
||||||
folderId,
|
folderId,
|
||||||
parentFolderId
|
parentFolderId
|
||||||
@@ -293,13 +273,13 @@ export const snapshotDALFactory = (db: TDbClient) => {
|
|||||||
{
|
{
|
||||||
key: "tagVersionId",
|
key: "tagVersionId",
|
||||||
label: "tags" as const,
|
label: "tags" as const,
|
||||||
mapper: ({
|
mapper: ({ tagId: id, tagName: name, tagSlug: slug, tagColor: color, tagVersionId: vId }) => ({
|
||||||
tagId: id,
|
id,
|
||||||
tagName: name,
|
name,
|
||||||
tagSlug: slug,
|
slug,
|
||||||
tagColor: color,
|
color,
|
||||||
tagVersionId: vId
|
vId
|
||||||
}) => ({ id, name, slug, color, vId })
|
})
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -328,11 +308,7 @@ export const snapshotDALFactory = (db: TDbClient) => {
|
|||||||
const docs = await (tx || db)(TableName.Snapshot)
|
const docs = await (tx || db)(TableName.Snapshot)
|
||||||
.where(`${TableName.Snapshot}.folderId`, folderId)
|
.where(`${TableName.Snapshot}.folderId`, folderId)
|
||||||
.join<TSecretSnapshots>(
|
.join<TSecretSnapshots>(
|
||||||
(tx || db)(TableName.Snapshot)
|
(tx || db)(TableName.Snapshot).groupBy("folderId").max("createdAt").select("folderId").as("latestVersion"),
|
||||||
.groupBy("folderId")
|
|
||||||
.max("createdAt")
|
|
||||||
.select("folderId")
|
|
||||||
.as("latestVersion"),
|
|
||||||
(bd) => {
|
(bd) => {
|
||||||
bd.on(`${TableName.Snapshot}.folderId`, "latestVersion.folderId").andOn(
|
bd.on(`${TableName.Snapshot}.folderId`, "latestVersion.folderId").andOn(
|
||||||
`${TableName.Snapshot}.createdAt`,
|
`${TableName.Snapshot}.createdAt`,
|
||||||
|
|||||||
@@ -28,36 +28,22 @@ export const trustedIpServiceFactory = ({
|
|||||||
}: TTrustedIpServiceFactoryDep) => {
|
}: TTrustedIpServiceFactoryDep) => {
|
||||||
const listIpsByProjectId = async ({ projectId, actor, actorId }: TProjectPermission) => {
|
const listIpsByProjectId = async ({ projectId, actor, actorId }: TProjectPermission) => {
|
||||||
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.IpAllowList);
|
||||||
ProjectPermissionActions.Read,
|
|
||||||
ProjectPermissionSub.IpAllowList
|
|
||||||
);
|
|
||||||
const trustedIps = await trustedIpDAL.find({
|
const trustedIps = await trustedIpDAL.find({
|
||||||
projectId
|
projectId
|
||||||
});
|
});
|
||||||
return trustedIps;
|
return trustedIps;
|
||||||
};
|
};
|
||||||
|
|
||||||
const addProjectIp = async ({
|
const addProjectIp = async ({ projectId, actorId, actor, ipAddress: ip, comment, isActive }: TCreateIpDTO) => {
|
||||||
projectId,
|
|
||||||
actorId,
|
|
||||||
actor,
|
|
||||||
ipAddress: ip,
|
|
||||||
comment,
|
|
||||||
isActive
|
|
||||||
}: TCreateIpDTO) => {
|
|
||||||
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList);
|
||||||
ProjectPermissionActions.Create,
|
|
||||||
ProjectPermissionSub.IpAllowList
|
|
||||||
);
|
|
||||||
|
|
||||||
const project = await projectDAL.findById(projectId);
|
const project = await projectDAL.findById(projectId);
|
||||||
const plan = await licenseService.getPlan(project.orgId);
|
const plan = await licenseService.getPlan(project.orgId);
|
||||||
if (!plan.ipAllowlisting)
|
if (!plan.ipAllowlisting)
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message:
|
message: "Failed to add IP access range due to plan restriction. Upgrade plan to add IP access range."
|
||||||
"Failed to add IP access range due to plan restriction. Upgrade plan to add IP access range."
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const isValidIp = isValidIpOrCidr(ip);
|
const isValidIp = isValidIpOrCidr(ip);
|
||||||
@@ -79,26 +65,15 @@ export const trustedIpServiceFactory = ({
|
|||||||
return { trustedIp, project }; // for audit log
|
return { trustedIp, project }; // for audit log
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateProjectIp = async ({
|
const updateProjectIp = async ({ projectId, actorId, actor, ipAddress: ip, comment, trustedIpId }: TUpdateIpDTO) => {
|
||||||
projectId,
|
|
||||||
actorId,
|
|
||||||
actor,
|
|
||||||
ipAddress: ip,
|
|
||||||
comment,
|
|
||||||
trustedIpId
|
|
||||||
}: TUpdateIpDTO) => {
|
|
||||||
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList);
|
||||||
ProjectPermissionActions.Create,
|
|
||||||
ProjectPermissionSub.IpAllowList
|
|
||||||
);
|
|
||||||
|
|
||||||
const project = await projectDAL.findById(projectId);
|
const project = await projectDAL.findById(projectId);
|
||||||
const plan = await licenseService.getPlan(project.orgId);
|
const plan = await licenseService.getPlan(project.orgId);
|
||||||
if (!plan.ipAllowlisting)
|
if (!plan.ipAllowlisting)
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message:
|
message: "Failed to add IP access range due to plan restriction. Upgrade plan to add IP access range."
|
||||||
"Failed to add IP access range due to plan restriction. Upgrade plan to add IP access range."
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const isValidIp = isValidIpOrCidr(ip);
|
const isValidIp = isValidIpOrCidr(ip);
|
||||||
@@ -124,17 +99,13 @@ export const trustedIpServiceFactory = ({
|
|||||||
|
|
||||||
const deleteProjectIp = async ({ projectId, actorId, actor, trustedIpId }: TDeleteIpDTO) => {
|
const deleteProjectIp = async ({ projectId, actorId, actor, trustedIpId }: TDeleteIpDTO) => {
|
||||||
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList);
|
||||||
ProjectPermissionActions.Create,
|
|
||||||
ProjectPermissionSub.IpAllowList
|
|
||||||
);
|
|
||||||
|
|
||||||
const project = await projectDAL.findById(projectId);
|
const project = await projectDAL.findById(projectId);
|
||||||
const plan = await licenseService.getPlan(project.orgId);
|
const plan = await licenseService.getPlan(project.orgId);
|
||||||
if (!plan.ipAllowlisting)
|
if (!plan.ipAllowlisting)
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message:
|
message: "Failed to add IP access range due to plan restriction. Upgrade plan to add IP access range."
|
||||||
"Failed to add IP access range due to plan restriction. Upgrade plan to add IP access range."
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const [trustedIp] = await trustedIpDAL.delete({ projectId, id: trustedIpId });
|
const [trustedIp] = await trustedIpDAL.delete({ projectId, id: trustedIpId });
|
||||||
|
|||||||
@@ -24,9 +24,7 @@ export const conditionsMatcher = buildMongoQueryMatcher({ $glob }, { glob });
|
|||||||
* Extracts and formats permissions from a CASL Ability object or a raw permission set.
|
* Extracts and formats permissions from a CASL Ability object or a raw permission set.
|
||||||
*/
|
*/
|
||||||
const extractPermissions = (ability: MongoAbility) =>
|
const extractPermissions = (ability: MongoAbility) =>
|
||||||
ability.rules.map(
|
ability.rules.map((permission) => `${permission.action as string}_${permission.subject as string}`);
|
||||||
(permission) => `${permission.action as string}_${permission.subject as string}`
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares two sets of permissions to determine if the first set is at least as privileged as the second set.
|
* Compares two sets of permissions to determine if the first set is at least as privileged as the second set.
|
||||||
|
|||||||
@@ -38,9 +38,7 @@ const envSchema = z
|
|||||||
// Telemetry
|
// Telemetry
|
||||||
TELEMETRY_ENABLED: zodStrBool.default("true"),
|
TELEMETRY_ENABLED: zodStrBool.default("true"),
|
||||||
POSTHOG_HOST: zpStr(z.string().optional().default("https://app.posthog.com")),
|
POSTHOG_HOST: zpStr(z.string().optional().default("https://app.posthog.com")),
|
||||||
POSTHOG_PROJECT_API_KEY: zpStr(
|
POSTHOG_PROJECT_API_KEY: zpStr(z.string().optional().default("phc_nSin8j5q2zdhpFDI1ETmFNUIuTG4DwKVyIigrY10XiE")),
|
||||||
z.string().optional().default("phc_nSin8j5q2zdhpFDI1ETmFNUIuTG4DwKVyIigrY10XiE")
|
|
||||||
),
|
|
||||||
LOOPS_API_KEY: zpStr(z.string().optional()),
|
LOOPS_API_KEY: zpStr(z.string().optional()),
|
||||||
// jwt options
|
// jwt options
|
||||||
AUTH_SECRET: zpStr(z.string()).default(process.env.JWT_AUTH_SECRET), // for those still using old JWT_AUTH_SECRET
|
AUTH_SECRET: zpStr(z.string()).default(process.env.JWT_AUTH_SECRET), // for those still using old JWT_AUTH_SECRET
|
||||||
|
|||||||
@@ -20,11 +20,7 @@ export const BLOCK_SIZE_BYTES_16 = 16;
|
|||||||
export const decryptSymmetric = ({ ciphertext, iv, tag, key }: TDecryptSymmetricInput): string => {
|
export const decryptSymmetric = ({ ciphertext, iv, tag, key }: TDecryptSymmetricInput): string => {
|
||||||
const secretKey = crypto.createSecretKey(key, "base64");
|
const secretKey = crypto.createSecretKey(key, "base64");
|
||||||
|
|
||||||
const decipher = crypto.createDecipheriv(
|
const decipher = crypto.createDecipheriv(SecretEncryptionAlgo.AES_256_GCM, secretKey, Buffer.from(iv, "base64"));
|
||||||
SecretEncryptionAlgo.AES_256_GCM,
|
|
||||||
secretKey,
|
|
||||||
Buffer.from(iv, "base64")
|
|
||||||
);
|
|
||||||
decipher.setAuthTag(Buffer.from(tag, "base64"));
|
decipher.setAuthTag(Buffer.from(tag, "base64"));
|
||||||
let cleartext = decipher.update(ciphertext, "base64", "utf8");
|
let cleartext = decipher.update(ciphertext, "base64", "utf8");
|
||||||
cleartext += decipher.final("utf8");
|
cleartext += decipher.final("utf8");
|
||||||
@@ -62,17 +58,8 @@ export const encryptSymmetric128BitHexKeyUTF8 = (plaintext: string, key: string)
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const decryptSymmetric128BitHexKeyUTF8 = ({
|
export const decryptSymmetric128BitHexKeyUTF8 = ({ ciphertext, iv, tag, key }: TDecryptSymmetricInput): string => {
|
||||||
ciphertext,
|
const decipher = crypto.createDecipheriv(SecretEncryptionAlgo.AES_256_GCM, key, Buffer.from(iv, "base64"));
|
||||||
iv,
|
|
||||||
tag,
|
|
||||||
key
|
|
||||||
}: TDecryptSymmetricInput): string => {
|
|
||||||
const decipher = crypto.createDecipheriv(
|
|
||||||
SecretEncryptionAlgo.AES_256_GCM,
|
|
||||||
key,
|
|
||||||
Buffer.from(iv, "base64")
|
|
||||||
);
|
|
||||||
|
|
||||||
decipher.setAuthTag(Buffer.from(tag, "base64"));
|
decipher.setAuthTag(Buffer.from(tag, "base64"));
|
||||||
|
|
||||||
@@ -104,12 +91,7 @@ export type TDecryptAsymmetricInput = {
|
|||||||
privateKey: string;
|
privateKey: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const decryptAsymmetric = ({
|
export const decryptAsymmetric = ({ ciphertext, nonce, publicKey, privateKey }: TDecryptAsymmetricInput) => {
|
||||||
ciphertext,
|
|
||||||
nonce,
|
|
||||||
publicKey,
|
|
||||||
privateKey
|
|
||||||
}: TDecryptAsymmetricInput) => {
|
|
||||||
const plaintext: Uint8Array | null = nacl.box.open(
|
const plaintext: Uint8Array | null = nacl.box.open(
|
||||||
naclUtils.decodeBase64(ciphertext),
|
naclUtils.decodeBase64(ciphertext),
|
||||||
naclUtils.decodeBase64(nonce),
|
naclUtils.decodeBase64(nonce),
|
||||||
|
|||||||
@@ -23,10 +23,7 @@ export const groupBy = <T, Key extends string | number | symbol>(
|
|||||||
* to convert each item in the list to a comparable identity
|
* to convert each item in the list to a comparable identity
|
||||||
* value
|
* value
|
||||||
*/
|
*/
|
||||||
export const unique = <T, K extends string | number | symbol>(
|
export const unique = <T, K extends string | number | symbol>(array: readonly T[], toKey?: (item: T) => K): T[] => {
|
||||||
array: readonly T[],
|
|
||||||
toKey?: (item: T) => K
|
|
||||||
): T[] => {
|
|
||||||
const valueMap = array.reduce(
|
const valueMap = array.reduce(
|
||||||
(acc, item) => {
|
(acc, item) => {
|
||||||
const key = toKey ? toKey(item) : (item as unknown as string | number | symbol);
|
const key = toKey ? toKey(item) : (item as unknown as string | number | symbol);
|
||||||
|
|||||||
@@ -2,10 +2,7 @@
|
|||||||
* Pick a list of properties from an object
|
* Pick a list of properties from an object
|
||||||
* into a new object
|
* into a new object
|
||||||
*/
|
*/
|
||||||
export const pick = <T extends object, TKeys extends keyof T>(
|
export const pick = <T extends object, TKeys extends keyof T>(obj: T, keys: TKeys[]): Pick<T, TKeys> => {
|
||||||
obj: T,
|
|
||||||
keys: TKeys[]
|
|
||||||
): Pick<T, TKeys> => {
|
|
||||||
if (!obj) return {} as Pick<T, TKeys>;
|
if (!obj) return {} as Pick<T, TKeys>;
|
||||||
return keys.reduce(
|
return keys.reduce(
|
||||||
(acc, key) => {
|
(acc, key) => {
|
||||||
|
|||||||
@@ -111,13 +111,7 @@ export type TIp = {
|
|||||||
/**
|
/**
|
||||||
* Validates the IP address [ipAddress] against the trusted IPs [trustedIps].
|
* Validates the IP address [ipAddress] against the trusted IPs [trustedIps].
|
||||||
*/
|
*/
|
||||||
export const checkIPAgainstBlocklist = ({
|
export const checkIPAgainstBlocklist = ({ ipAddress, trustedIps }: { ipAddress: string; trustedIps: TIp[] }) => {
|
||||||
ipAddress,
|
|
||||||
trustedIps
|
|
||||||
}: {
|
|
||||||
ipAddress: string;
|
|
||||||
trustedIps: TIp[];
|
|
||||||
}) => {
|
|
||||||
const blockList = new net.BlockList();
|
const blockList = new net.BlockList();
|
||||||
|
|
||||||
for (const trustedIp of trustedIps) {
|
for (const trustedIp of trustedIps) {
|
||||||
|
|||||||
@@ -41,11 +41,7 @@ export type TFindOpt<R extends object = object> = {
|
|||||||
// What is ormify
|
// What is ormify
|
||||||
// It is to inject typical operations like find, findOne, update, delete, create
|
// It is to inject typical operations like find, findOne, update, delete, create
|
||||||
// This will avoid writing most common ones each time
|
// This will avoid writing most common ones each time
|
||||||
export const ormify = <DbOps extends object, Tname extends keyof Tables>(
|
export const ormify = <DbOps extends object, Tname extends keyof Tables>(db: Knex, tableName: Tname, dal?: DbOps) => ({
|
||||||
db: Knex,
|
|
||||||
tableName: Tname,
|
|
||||||
dal?: DbOps
|
|
||||||
) => ({
|
|
||||||
transaction: async <T>(cb: (tx: Knex) => Promise<T>) =>
|
transaction: async <T>(cb: (tx: Knex) => Promise<T>) =>
|
||||||
db.transaction(async (trx) => {
|
db.transaction(async (trx) => {
|
||||||
const res = await cb(trx);
|
const res = await cb(trx);
|
||||||
@@ -78,9 +74,7 @@ export const ormify = <DbOps extends object, Tname extends keyof Tables>(
|
|||||||
if (limit) void query.limit(limit);
|
if (limit) void query.limit(limit);
|
||||||
if (offset) void query.offset(offset);
|
if (offset) void query.offset(offset);
|
||||||
if (sort) {
|
if (sort) {
|
||||||
void query.orderBy(
|
void query.orderBy(sort.map(([column, order, nulls]) => ({ column: column as string, order, nulls })));
|
||||||
sort.map(([column, order, nulls]) => ({ column: column as string, order, nulls }))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
const res = await query;
|
const res = await query;
|
||||||
return res;
|
return res;
|
||||||
@@ -120,11 +114,7 @@ export const ormify = <DbOps extends object, Tname extends keyof Tables>(
|
|||||||
throw new DatabaseError({ error, name: "Update by id" });
|
throw new DatabaseError({ error, name: "Update by id" });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
update: async (
|
update: async (filter: TFindFilter<Tables[Tname]["base"]>, data: Tables[Tname]["update"], tx?: Knex) => {
|
||||||
filter: TFindFilter<Tables[Tname]["base"]>,
|
|
||||||
data: Tables[Tname]["update"],
|
|
||||||
tx?: Knex
|
|
||||||
) => {
|
|
||||||
try {
|
try {
|
||||||
const res = await (tx || db)(tableName)
|
const res = await (tx || db)(tableName)
|
||||||
.where(buildFindFilter(filter))
|
.where(buildFindFilter(filter))
|
||||||
@@ -148,10 +138,7 @@ export const ormify = <DbOps extends object, Tname extends keyof Tables>(
|
|||||||
},
|
},
|
||||||
delete: async (filter: TFindFilter<Tables[Tname]["base"]>, tx?: Knex) => {
|
delete: async (filter: TFindFilter<Tables[Tname]["base"]>, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const res = await (tx || db)(tableName)
|
const res = await (tx || db)(tableName).where(buildFindFilter(filter)).delete().returning("*");
|
||||||
.where(buildFindFilter(filter))
|
|
||||||
.delete()
|
|
||||||
.returning("*");
|
|
||||||
return res;
|
return res;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Delete" });
|
throw new DatabaseError({ error, name: "Delete" });
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
import { z, ZodTypeAny } from "zod";
|
import { z, ZodTypeAny } from "zod";
|
||||||
|
|
||||||
// this is a patched zod string to remove empty string to undefined
|
// this is a patched zod string to remove empty string to undefined
|
||||||
export const zpStr = <T extends ZodTypeAny>(
|
export const zpStr = <T extends ZodTypeAny>(schema: T, opt: { stripNull: boolean } = { stripNull: true }) =>
|
||||||
schema: T,
|
|
||||||
opt: { stripNull: boolean } = { stripNull: true }
|
|
||||||
) =>
|
|
||||||
z.preprocess((val) => {
|
z.preprocess((val) => {
|
||||||
if (opt.stripNull && val === null) return undefined;
|
if (opt.stripNull && val === null) return undefined;
|
||||||
if (typeof val !== "string") return val;
|
if (typeof val !== "string") return val;
|
||||||
|
|||||||
@@ -74,23 +74,18 @@ export const queueServiceFactory = (redisUrl: string) => {
|
|||||||
|
|
||||||
const start = <T extends QueueName>(
|
const start = <T extends QueueName>(
|
||||||
name: T,
|
name: T,
|
||||||
jobFn: (
|
jobFn: (job: Job<TQueueJobTypes[T]["payload"], void, TQueueJobTypes[T]["name"]>) => Promise<void>
|
||||||
job: Job<TQueueJobTypes[T]["payload"], void, TQueueJobTypes[T]["name"]>
|
|
||||||
) => Promise<void>
|
|
||||||
) => {
|
) => {
|
||||||
if (queueContainer[name]) {
|
if (queueContainer[name]) {
|
||||||
throw new Error(`${name} queue is already initialized`);
|
throw new Error(`${name} queue is already initialized`);
|
||||||
}
|
}
|
||||||
|
|
||||||
queueContainer[name] = new Queue<TQueueJobTypes[T]["payload"], void, TQueueJobTypes[T]["name"]>(
|
queueContainer[name] = new Queue<TQueueJobTypes[T]["payload"], void, TQueueJobTypes[T]["name"]>(name as string, {
|
||||||
name as string,
|
connection
|
||||||
{ connection }
|
});
|
||||||
);
|
workerContainer[name] = new Worker<TQueueJobTypes[T]["payload"], void, TQueueJobTypes[T]["name"]>(name, jobFn, {
|
||||||
workerContainer[name] = new Worker<
|
connection
|
||||||
TQueueJobTypes[T]["payload"],
|
});
|
||||||
void,
|
|
||||||
TQueueJobTypes[T]["name"]
|
|
||||||
>(name, jobFn, { connection });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const listen = <
|
const listen = <
|
||||||
|
|||||||
@@ -5,12 +5,7 @@ import jwt, { JwtPayload } from "jsonwebtoken";
|
|||||||
import { TServiceTokens, TUsers } from "@app/db/schemas";
|
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 { ActorType, AuthMode, AuthModeJwtTokenPayload, AuthTokenType } from "@app/services/auth/auth-type";
|
||||||
ActorType,
|
|
||||||
AuthMode,
|
|
||||||
AuthModeJwtTokenPayload,
|
|
||||||
AuthTokenType
|
|
||||||
} from "@app/services/auth/auth-type";
|
|
||||||
import { TIdentityAccessTokenJwtPayload } from "@app/services/identity-access-token/identity-access-token-types";
|
import { TIdentityAccessTokenJwtPayload } from "@app/services/identity-access-token/identity-access-token-types";
|
||||||
|
|
||||||
export type TAuthMode =
|
export type TAuthMode =
|
||||||
@@ -87,16 +82,12 @@ export const injectIdentity = fp(async (server: FastifyZodProvider) => {
|
|||||||
|
|
||||||
switch (authMode) {
|
switch (authMode) {
|
||||||
case AuthMode.JWT: {
|
case AuthMode.JWT: {
|
||||||
const { user, tokenVersionId } =
|
const { user, tokenVersionId } = await server.services.authToken.fnValidateJwtIdentity(token);
|
||||||
await server.services.authToken.fnValidateJwtIdentity(token);
|
|
||||||
req.auth = { authMode: AuthMode.JWT, user, userId: user.id, tokenVersionId, actor };
|
req.auth = { authMode: AuthMode.JWT, user, userId: user.id, tokenVersionId, actor };
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AuthMode.IDENTITY_ACCESS_TOKEN: {
|
case AuthMode.IDENTITY_ACCESS_TOKEN: {
|
||||||
const identity = await server.services.identityAccessToken.fnValidateIdentityAccessToken(
|
const identity = await server.services.identityAccessToken.fnValidateIdentityAccessToken(token, req.realIp);
|
||||||
token,
|
|
||||||
req.realIp
|
|
||||||
);
|
|
||||||
req.auth = {
|
req.auth = {
|
||||||
authMode: AuthMode.IDENTITY_ACCESS_TOKEN,
|
authMode: AuthMode.IDENTITY_ACCESS_TOKEN,
|
||||||
actor,
|
actor,
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ export const verifyAuth =
|
|||||||
<T extends FastifyRequest>(authStrats: AuthMode[]) =>
|
<T extends FastifyRequest>(authStrats: AuthMode[]) =>
|
||||||
(req: T, _res: FastifyReply, done: HookHandlerDoneFunction) => {
|
(req: T, _res: FastifyReply, done: HookHandlerDoneFunction) => {
|
||||||
if (!Array.isArray(authStrats)) throw new Error("Auth strategy must be array");
|
if (!Array.isArray(authStrats)) throw new Error("Auth strategy must be array");
|
||||||
if (!req.auth)
|
if (!req.auth) throw new UnauthorizedError({ name: "Unauthorized access", message: "Token missing" });
|
||||||
throw new UnauthorizedError({ name: "Unauthorized access", message: "Token missing" });
|
|
||||||
|
|
||||||
const isAccessAllowed = authStrats.some((strat) => strat === req.auth.authMode);
|
const isAccessAllowed = authStrats.some((strat) => strat === req.auth.authMode);
|
||||||
if (!isAccessAllowed) {
|
if (!isAccessAllowed) {
|
||||||
|
|||||||
@@ -2,12 +2,7 @@ import { ForbiddenError } from "@casl/ability";
|
|||||||
import fastifyPlugin from "fastify-plugin";
|
import fastifyPlugin from "fastify-plugin";
|
||||||
import { ZodError } from "zod";
|
import { ZodError } from "zod";
|
||||||
|
|
||||||
import {
|
import { BadRequestError, DatabaseError, InternalServerError, UnauthorizedError } from "@app/lib/errors";
|
||||||
BadRequestError,
|
|
||||||
DatabaseError,
|
|
||||||
InternalServerError,
|
|
||||||
UnauthorizedError
|
|
||||||
} from "@app/lib/errors";
|
|
||||||
|
|
||||||
export const fastifyErrHandler = fastifyPlugin(async (server: FastifyZodProvider) => {
|
export const fastifyErrHandler = fastifyPlugin(async (server: FastifyZodProvider) => {
|
||||||
server.setErrorHandler((error, req, res) => {
|
server.setErrorHandler((error, req, res) => {
|
||||||
@@ -17,13 +12,9 @@ export const fastifyErrHandler = fastifyPlugin(async (server: FastifyZodProvider
|
|||||||
} else if (error instanceof UnauthorizedError) {
|
} else if (error instanceof UnauthorizedError) {
|
||||||
void res.status(403).send({ statusCode: 403, message: error.message, error: error.name });
|
void res.status(403).send({ statusCode: 403, message: error.message, error: error.name });
|
||||||
} else if (error instanceof DatabaseError || error instanceof InternalServerError) {
|
} else if (error instanceof DatabaseError || error instanceof InternalServerError) {
|
||||||
void res
|
void res.status(500).send({ statusCode: 500, message: "Something went wrong", error: error.name });
|
||||||
.status(500)
|
|
||||||
.send({ statusCode: 500, message: "Something went wrong", error: error.name });
|
|
||||||
} else if (error instanceof ZodError) {
|
} else if (error instanceof ZodError) {
|
||||||
void res
|
void res.status(403).send({ statusCode: 403, error: "ValidationFailure", message: error.issues });
|
||||||
.status(403)
|
|
||||||
.send({ statusCode: 403, error: "ValidationFailure", message: error.issues });
|
|
||||||
} else if (error instanceof ForbiddenError) {
|
} else if (error instanceof ForbiddenError) {
|
||||||
void res.status(401).send({
|
void res.status(401).send({
|
||||||
statusCode: 401,
|
statusCode: 401,
|
||||||
|
|||||||
@@ -92,10 +92,7 @@ import { serviceTokenDALFactory } from "@app/services/service-token/service-toke
|
|||||||
import { serviceTokenServiceFactory } from "@app/services/service-token/service-token-service";
|
import { serviceTokenServiceFactory } from "@app/services/service-token/service-token-service";
|
||||||
import { TSmtpService } from "@app/services/smtp/smtp-service";
|
import { TSmtpService } from "@app/services/smtp/smtp-service";
|
||||||
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
import {
|
import { getServerCfg, superAdminServiceFactory } from "@app/services/super-admin/super-admin-service";
|
||||||
getServerCfg,
|
|
||||||
superAdminServiceFactory
|
|
||||||
} from "@app/services/super-admin/super-admin-service";
|
|
||||||
import { telemetryServiceFactory } from "@app/services/telemetry/telemetry-service";
|
import { telemetryServiceFactory } from "@app/services/telemetry/telemetry-service";
|
||||||
import { userDALFactory } from "@app/services/user/user-dal";
|
import { userDALFactory } from "@app/services/user/user-dal";
|
||||||
import { userServiceFactory } from "@app/services/user/user-service";
|
import { userServiceFactory } from "@app/services/user/user-service";
|
||||||
@@ -112,11 +109,7 @@ import { registerV3Routes } from "./v3";
|
|||||||
|
|
||||||
export const registerRoutes = async (
|
export const registerRoutes = async (
|
||||||
server: FastifyZodProvider,
|
server: FastifyZodProvider,
|
||||||
{
|
{ db, smtp: smtpService, queue: queueService }: { db: Knex; smtp: TSmtpService; queue: TQueueServiceFactory }
|
||||||
db,
|
|
||||||
smtp: smtpService,
|
|
||||||
queue: queueService
|
|
||||||
}: { db: Knex; smtp: TSmtpService; queue: TQueueServiceFactory }
|
|
||||||
) => {
|
) => {
|
||||||
await server.register(registerSecretScannerGhApp, { prefix: "/ss-webhook" });
|
await server.register(registerSecretScannerGhApp, { prefix: "/ss-webhook" });
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,7 @@ import { getConfig } from "@app/lib/config/env";
|
|||||||
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
|
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
|
||||||
import { authRateLimit } from "@app/server/config/rateLimiter";
|
import { authRateLimit } from "@app/server/config/rateLimiter";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import {
|
import { AuthMode, AuthModeRefreshJwtTokenPayload, AuthTokenType } from "@app/services/auth/auth-type";
|
||||||
AuthMode,
|
|
||||||
AuthModeRefreshJwtTokenPayload,
|
|
||||||
AuthTokenType
|
|
||||||
} from "@app/services/auth/auth-type";
|
|
||||||
|
|
||||||
export const registerAuthRoutes = async (server: FastifyZodProvider) => {
|
export const registerAuthRoutes = async (server: FastifyZodProvider) => {
|
||||||
server.route({
|
server.route({
|
||||||
@@ -74,10 +70,7 @@ export const registerAuthRoutes = async (server: FastifyZodProvider) => {
|
|||||||
message: "Failed to find refresh token"
|
message: "Failed to find refresh token"
|
||||||
});
|
});
|
||||||
|
|
||||||
const decodedToken = jwt.verify(
|
const decodedToken = jwt.verify(refreshToken, appCfg.AUTH_SECRET) as AuthModeRefreshJwtTokenPayload;
|
||||||
refreshToken,
|
|
||||||
appCfg.AUTH_SECRET
|
|
||||||
) as AuthModeRefreshJwtTokenPayload;
|
|
||||||
if (decodedToken.authTokenType !== AuthTokenType.REFRESH_TOKEN)
|
if (decodedToken.authTokenType !== AuthTokenType.REFRESH_TOKEN)
|
||||||
throw new UnauthorizedError({ message: "Invalid token", name: "Auth token route" });
|
throw new UnauthorizedError({ message: "Invalid token", name: "Auth token route" });
|
||||||
|
|
||||||
@@ -85,8 +78,7 @@ export const registerAuthRoutes = async (server: FastifyZodProvider) => {
|
|||||||
decodedToken.tokenVersionId,
|
decodedToken.tokenVersionId,
|
||||||
decodedToken.userId
|
decodedToken.userId
|
||||||
);
|
);
|
||||||
if (!tokenVersion)
|
if (!tokenVersion) throw new UnauthorizedError({ message: "Invalid token", name: "Auth token route" });
|
||||||
throw new UnauthorizedError({ message: "Invalid token", name: "Auth token route" });
|
|
||||||
|
|
||||||
if (decodedToken.refreshVersion !== tokenVersion.refreshVersion)
|
if (decodedToken.refreshVersion !== tokenVersion.refreshVersion)
|
||||||
throw new UnauthorizedError({ message: "Invalid token", name: "Auth token route" });
|
throw new UnauthorizedError({ message: "Invalid token", name: "Auth token route" });
|
||||||
|
|||||||
@@ -18,10 +18,9 @@ export const registerIdentityAccessTokenRouter = async (server: FastifyZodProvid
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { accessToken, identityAccessToken } =
|
const { accessToken, identityAccessToken } = await server.services.identityAccessToken.renewAccessToken({
|
||||||
await server.services.identityAccessToken.renewAccessToken({
|
accessToken: req.body.accessToken
|
||||||
accessToken: req.body.accessToken
|
});
|
||||||
});
|
|
||||||
return {
|
return {
|
||||||
accessToken,
|
accessToken,
|
||||||
tokenType: "Bearer" as const,
|
tokenType: "Bearer" as const,
|
||||||
|
|||||||
@@ -39,11 +39,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { identityUa, accessToken, identityAccessToken, validClientSecretInfo } =
|
const { identityUa, accessToken, identityAccessToken, validClientSecretInfo } =
|
||||||
await server.services.identityUa.login(
|
await server.services.identityUa.login(req.body.clientId, req.body.clientSecret, req.realIp);
|
||||||
req.body.clientId,
|
|
||||||
req.body.clientSecret,
|
|
||||||
req.realIp
|
|
||||||
);
|
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
@@ -128,10 +124,8 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
|||||||
identityId: identityUniversalAuth.identityId,
|
identityId: identityUniversalAuth.identityId,
|
||||||
accessTokenTTL: identityUniversalAuth.accessTokenTTL,
|
accessTokenTTL: identityUniversalAuth.accessTokenTTL,
|
||||||
accessTokenMaxTTL: identityUniversalAuth.accessTokenMaxTTL,
|
accessTokenMaxTTL: identityUniversalAuth.accessTokenMaxTTL,
|
||||||
accessTokenTrustedIps:
|
accessTokenTrustedIps: identityUniversalAuth.accessTokenTrustedIps as TIdentityTrustedIp[],
|
||||||
identityUniversalAuth.accessTokenTrustedIps as TIdentityTrustedIp[],
|
clientSecretTrustedIps: identityUniversalAuth.clientSecretTrustedIps as TIdentityTrustedIp[],
|
||||||
clientSecretTrustedIps:
|
|
||||||
identityUniversalAuth.clientSecretTrustedIps as TIdentityTrustedIp[],
|
|
||||||
accessTokenNumUsesLimit: identityUniversalAuth.accessTokenNumUsesLimit
|
accessTokenNumUsesLimit: identityUniversalAuth.accessTokenNumUsesLimit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -197,10 +191,8 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
|||||||
identityId: identityUniversalAuth.identityId,
|
identityId: identityUniversalAuth.identityId,
|
||||||
accessTokenTTL: identityUniversalAuth.accessTokenTTL,
|
accessTokenTTL: identityUniversalAuth.accessTokenTTL,
|
||||||
accessTokenMaxTTL: identityUniversalAuth.accessTokenMaxTTL,
|
accessTokenMaxTTL: identityUniversalAuth.accessTokenMaxTTL,
|
||||||
accessTokenTrustedIps:
|
accessTokenTrustedIps: identityUniversalAuth.accessTokenTrustedIps as TIdentityTrustedIp[],
|
||||||
identityUniversalAuth.accessTokenTrustedIps as TIdentityTrustedIp[],
|
clientSecretTrustedIps: identityUniversalAuth.clientSecretTrustedIps as TIdentityTrustedIp[],
|
||||||
clientSecretTrustedIps:
|
|
||||||
identityUniversalAuth.clientSecretTrustedIps as TIdentityTrustedIp[],
|
|
||||||
accessTokenNumUsesLimit: identityUniversalAuth.accessTokenNumUsesLimit
|
accessTokenNumUsesLimit: identityUniversalAuth.accessTokenNumUsesLimit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -267,13 +259,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { clientSecret, clientSecretData, orgId } =
|
const { clientSecret, clientSecretData, orgId } = await server.services.identityUa.createUaClientSecret({
|
||||||
await server.services.identityUa.createUaClientSecret({
|
actor: req.permission.type,
|
||||||
actor: req.permission.type,
|
actorId: req.permission.id,
|
||||||
actorId: req.permission.id,
|
identityId: req.params.identityId,
|
||||||
identityId: req.params.identityId,
|
...req.body
|
||||||
...req.body
|
});
|
||||||
});
|
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
@@ -306,12 +297,11 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { clientSecrets: clientSecretData, orgId } =
|
const { clientSecrets: clientSecretData, orgId } = await server.services.identityUa.getUaClientSecrets({
|
||||||
await server.services.identityUa.getUaClientSecrets({
|
actor: req.permission.type,
|
||||||
actor: req.permission.type,
|
actorId: req.permission.id,
|
||||||
actorId: req.permission.id,
|
identityId: req.params.identityId
|
||||||
identityId: req.params.identityId
|
});
|
||||||
});
|
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import {
|
import { IncidentContactsSchema, OrganizationsSchema, OrgMembershipsSchema, UsersSchema } from "@app/db/schemas";
|
||||||
IncidentContactsSchema,
|
|
||||||
OrganizationsSchema,
|
|
||||||
OrgMembershipsSchema,
|
|
||||||
UsersSchema
|
|
||||||
} from "@app/db/schemas";
|
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
@@ -42,10 +37,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const organization = await server.services.org.findOrganizationById(
|
const organization = await server.services.org.findOrganizationById(req.permission.id, req.params.organizationId);
|
||||||
req.permission.id,
|
|
||||||
req.params.organizationId
|
|
||||||
);
|
|
||||||
return { organization };
|
return { organization };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -76,10 +68,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const users = await server.services.org.findAllOrgMembers(
|
const users = await server.services.org.findAllOrgMembers(req.permission.id, req.params.organizationId);
|
||||||
req.permission.id,
|
|
||||||
req.params.organizationId
|
|
||||||
);
|
|
||||||
return { users };
|
return { users };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -119,10 +119,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { token, user } = await server.services.password.verifyPasswordResetEmail(
|
const { token, user } = await server.services.password.verifyPasswordResetEmail(req.body.email, req.body.code);
|
||||||
req.body.email,
|
|
||||||
req.body.code
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
message: "Successfully verified email",
|
message: "Successfully verified email",
|
||||||
@@ -183,9 +180,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const token = validateSignUpAuthorization(req.headers.authorization as string, "", false)!;
|
const token = validateSignUpAuthorization(req.headers.authorization as string, "", false)!;
|
||||||
const backupPrivateKey = await server.services.password.getBackupPrivateKeyOfUser(
|
const backupPrivateKey = await server.services.password.getBackupPrivateKeyOfUser(token.userId);
|
||||||
token.userId
|
|
||||||
);
|
|
||||||
if (!backupPrivateKey) throw new Error("Failed to find backup key");
|
if (!backupPrivateKey) throw new Error("Failed to find backup key");
|
||||||
|
|
||||||
return { message: "Successfully fetched backup private key", backupPrivateKey };
|
return { message: "Successfully fetched backup private key", backupPrivateKey };
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import {
|
import { OrgMembershipsSchema, ProjectMembershipsSchema, UserEncryptionKeysSchema, UsersSchema } from "@app/db/schemas";
|
||||||
OrgMembershipsSchema,
|
|
||||||
ProjectMembershipsSchema,
|
|
||||||
UserEncryptionKeysSchema,
|
|
||||||
UsersSchema
|
|
||||||
} from "@app/db/schemas";
|
|
||||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|||||||
@@ -25,12 +25,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
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 path = req.body.path || req.body.directory;
|
||||||
const folder = await server.services.folder.createFolder({
|
const folder = await server.services.folder.createFolder({
|
||||||
@@ -79,12 +74,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
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 path = req.body.path || req.body.directory;
|
||||||
const { folder, old } = await server.services.folder.updateFolder({
|
const { folder, old } = await server.services.folder.updateFolder({
|
||||||
@@ -133,12 +123,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
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 path = req.body.path || req.body.directory;
|
||||||
const folder = await server.services.folder.deleteFolder({
|
const folder = await server.services.folder.deleteFolder({
|
||||||
@@ -183,12 +168,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
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 path = req.query.path || req.query.directory;
|
||||||
const folders = await server.services.folder.getFolders({
|
const folders = await server.services.folder.getFolders({
|
||||||
|
|||||||
@@ -31,12 +31,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
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,
|
||||||
@@ -97,12 +92,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
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,
|
||||||
@@ -155,12 +145,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
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,
|
||||||
@@ -211,12 +196,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
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,
|
||||||
@@ -268,12 +248,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
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,
|
||||||
|
|||||||
@@ -27,9 +27,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
await server.register(passport.initialize());
|
await server.register(passport.initialize());
|
||||||
await server.register(passport.secureSession());
|
await server.register(passport.secureSession());
|
||||||
// passport oauth strategy for Google
|
// passport oauth strategy for Google
|
||||||
const isGoogleOauthActive = Boolean(
|
const isGoogleOauthActive = Boolean(appCfg.CLIENT_ID_GOOGLE_LOGIN && appCfg.CLIENT_SECRET_GOOGLE_LOGIN);
|
||||||
appCfg.CLIENT_ID_GOOGLE_LOGIN && appCfg.CLIENT_SECRET_GOOGLE_LOGIN
|
|
||||||
);
|
|
||||||
if (isGoogleOauthActive) {
|
if (isGoogleOauthActive) {
|
||||||
passport.use(
|
passport.use(
|
||||||
new GoogleStrategy(
|
new GoogleStrategy(
|
||||||
@@ -70,9 +68,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Passport strategy for Github
|
// Passport strategy for Github
|
||||||
const isGithubOauthActive = Boolean(
|
const isGithubOauthActive = Boolean(appCfg.CLIENT_SECRET_GITHUB_LOGIN && appCfg.CLIENT_ID_GITHUB_LOGIN);
|
||||||
appCfg.CLIENT_SECRET_GITHUB_LOGIN && appCfg.CLIENT_ID_GITHUB_LOGIN
|
|
||||||
);
|
|
||||||
if (isGithubOauthActive) {
|
if (isGithubOauthActive) {
|
||||||
passport.use(
|
passport.use(
|
||||||
new GitHubStrategy(
|
new GitHubStrategy(
|
||||||
@@ -109,9 +105,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
|
|
||||||
// passport strategy for gitlab
|
// passport strategy for gitlab
|
||||||
const isGitlabOauthActive = Boolean(
|
const isGitlabOauthActive = Boolean(
|
||||||
appCfg.CLIENT_ID_GITLAB_LOGIN &&
|
appCfg.CLIENT_ID_GITLAB_LOGIN && appCfg.CLIENT_SECRET_GITLAB_LOGIN && appCfg.CLIENT_GITLAB_LOGIN_URL
|
||||||
appCfg.CLIENT_SECRET_GITLAB_LOGIN &&
|
|
||||||
appCfg.CLIENT_GITLAB_LOGIN_URL
|
|
||||||
);
|
);
|
||||||
if (isGitlabOauthActive) {
|
if (isGitlabOauthActive) {
|
||||||
passport.use(
|
passport.use(
|
||||||
@@ -180,15 +174,11 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
handler: (req, res) => {
|
handler: (req, res) => {
|
||||||
if (req.passportUser.isUserCompleted) {
|
if (req.passportUser.isUserCompleted) {
|
||||||
return res.redirect(
|
return res.redirect(
|
||||||
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(
|
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
|
||||||
req.passportUser.providerAuthToken
|
|
||||||
)}`
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return res.redirect(
|
return res.redirect(
|
||||||
`${appCfg.SITE_URL}/signup/sso?token=${encodeURIComponent(
|
`${appCfg.SITE_URL}/signup/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
|
||||||
req.passportUser.providerAuthToken
|
|
||||||
)}`
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -225,15 +215,11 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
handler: (req, res) => {
|
handler: (req, res) => {
|
||||||
if (req.passportUser.isUserCompleted) {
|
if (req.passportUser.isUserCompleted) {
|
||||||
return res.redirect(
|
return res.redirect(
|
||||||
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(
|
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
|
||||||
req.passportUser.providerAuthToken
|
|
||||||
)}`
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return res.redirect(
|
return res.redirect(
|
||||||
`${appCfg.SITE_URL}/signup/sso?token=${encodeURIComponent(
|
`${appCfg.SITE_URL}/signup/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
|
||||||
req.passportUser.providerAuthToken
|
|
||||||
)}`
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -272,15 +258,11 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
handler: (req, res) => {
|
handler: (req, res) => {
|
||||||
if (req.passportUser.isUserCompleted) {
|
if (req.passportUser.isUserCompleted) {
|
||||||
return res.redirect(
|
return res.redirect(
|
||||||
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(
|
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
|
||||||
req.passportUser.providerAuthToken
|
|
||||||
)}`
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return res.redirect(
|
return res.redirect(
|
||||||
`${appCfg.SITE_URL}/signup/sso?token=${encodeURIComponent(
|
`${appCfg.SITE_URL}/signup/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
|
||||||
req.passportUser.providerAuthToken
|
|
||||||
)}`
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,10 +21,7 @@ export const registerUserActionRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const userAction = await server.services.user.createUserAction(
|
const userAction = await server.services.user.createUserAction(req.permission.id, req.body.action);
|
||||||
req.permission.id,
|
|
||||||
req.body.action
|
|
||||||
);
|
|
||||||
return { userAction, message: "Successfully recorded user action" };
|
return { userAction, message: "Successfully recorded user action" };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -44,10 +41,7 @@ export const registerUserActionRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const userAction = await server.services.user.getUserAction(
|
const userAction = await server.services.user.getUserAction(req.permission.id, req.query.action);
|
||||||
req.permission.id,
|
|
||||||
req.query.action
|
|
||||||
);
|
|
||||||
return { userAction };
|
return { userAction };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -22,8 +22,7 @@ export const registerMfaRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const decodedToken = jwt.verify(token, cfg.AUTH_SECRET) as AuthModeMfaJwtTokenPayload;
|
const decodedToken = jwt.verify(token, cfg.AUTH_SECRET) as AuthModeMfaJwtTokenPayload;
|
||||||
if (decodedToken.authTokenType !== AuthTokenType.MFA_TOKEN)
|
if (decodedToken.authTokenType !== AuthTokenType.MFA_TOKEN) throw new Error("Unauthorized access");
|
||||||
throw new Error("Unauthorized access");
|
|
||||||
|
|
||||||
const user = await server.store.user.findById(decodedToken.userId);
|
const user = await server.store.user.findById(decodedToken.userId);
|
||||||
if (!user) throw new Error("User not found");
|
if (!user) throw new Error("User not found");
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import {
|
import { OrganizationsSchema, OrgMembershipsSchema, UserEncryptionKeysSchema, UsersSchema } from "@app/db/schemas";
|
||||||
OrganizationsSchema,
|
|
||||||
OrgMembershipsSchema,
|
|
||||||
UserEncryptionKeysSchema,
|
|
||||||
UsersSchema
|
|
||||||
} from "@app/db/schemas";
|
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { ActorType, AuthMode } from "@app/services/auth/auth-type";
|
import { ActorType, AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
@@ -38,10 +33,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
|
|||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
if (req.auth.actor !== ActorType.USER) return;
|
if (req.auth.actor !== ActorType.USER) return;
|
||||||
|
|
||||||
const users = await server.services.org.findAllOrgMembers(
|
const users = await server.services.org.findAllOrgMembers(req.permission.id, req.params.organizationId);
|
||||||
req.permission.id,
|
|
||||||
req.params.organizationId
|
|
||||||
);
|
|
||||||
return { users };
|
return { users };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import {
|
import { AuthTokenSessionsSchema, OrganizationsSchema, UserEncryptionKeysSchema, UsersSchema } from "@app/db/schemas";
|
||||||
AuthTokenSessionsSchema,
|
|
||||||
OrganizationsSchema,
|
|
||||||
UserEncryptionKeysSchema,
|
|
||||||
UsersSchema
|
|
||||||
} from "@app/db/schemas";
|
|
||||||
import { ApiKeysSchema } from "@app/db/schemas/api-keys";
|
import { ApiKeysSchema } from "@app/db/schemas/api-keys";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMethod, AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMethod, AuthMode } from "@app/services/auth/auth-type";
|
||||||
@@ -26,10 +21,7 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
preHandler: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
preHandler: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const user = await server.services.user.toggleUserMfa(
|
const user = await server.services.user.toggleUserMfa(req.permission.id, req.body.isMfaEnabled);
|
||||||
req.permission.id,
|
|
||||||
req.body.isMfaEnabled
|
|
||||||
);
|
|
||||||
return { user };
|
return { user };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -50,11 +42,7 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
preHandler: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
preHandler: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const user = await server.services.user.updateUserName(
|
const user = await server.services.user.updateUserName(req.permission.id, req.body.firstName, req.body.lastName);
|
||||||
req.permission.id,
|
|
||||||
req.body.firstName,
|
|
||||||
req.body.lastName
|
|
||||||
);
|
|
||||||
return { user };
|
return { user };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -74,10 +62,7 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
preHandler: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
preHandler: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const user = await server.services.user.updateAuthMethods(
|
const user = await server.services.user.updateAuthMethods(req.permission.id, req.body.authMethods);
|
||||||
req.permission.id,
|
|
||||||
req.body.authMethods
|
|
||||||
);
|
|
||||||
return { user };
|
return { user };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -131,11 +116,7 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const apiKeys = await server.services.apiKey.createApiKey(
|
const apiKeys = await server.services.apiKey.createApiKey(req.permission.id, req.body.name, req.body.expiresIn);
|
||||||
req.permission.id,
|
|
||||||
req.body.name,
|
|
||||||
req.body.expiresIn
|
|
||||||
);
|
|
||||||
return apiKeys;
|
return apiKeys;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -155,10 +136,7 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const apiKeyData = await server.services.apiKey.deleteApiKey(
|
const apiKeyData = await server.services.apiKey.deleteApiKey(req.permission.id, req.params.apiKeyDataId);
|
||||||
req.permission.id,
|
|
||||||
req.params.apiKeyDataId
|
|
||||||
);
|
|
||||||
return { apiKeyData };
|
return { apiKeyData };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -61,12 +61,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
AuthMode.JWT,
|
|
||||||
AuthMode.API_KEY,
|
|
||||||
AuthMode.SERVICE_TOKEN,
|
|
||||||
AuthMode.IDENTITY_ACCESS_TOKEN
|
|
||||||
]),
|
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
// just for delivery hero usecase
|
// just for delivery hero usecase
|
||||||
let { secretPath, environment, workspaceId } = req.query;
|
let { secretPath, environment, workspaceId } = req.query;
|
||||||
@@ -80,8 +75,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!workspaceId || !environment)
|
if (!workspaceId || !environment) throw new BadRequestError({ message: "Missing workspace id or environment" });
|
||||||
throw new BadRequestError({ message: "Missing workspace id or environment" });
|
|
||||||
|
|
||||||
const { secrets, imports } = await server.services.secret.getSecretsRaw({
|
const { secrets, imports } = await server.services.secret.getSecretsRaw({
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
@@ -144,12 +138,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
AuthMode.JWT,
|
|
||||||
AuthMode.API_KEY,
|
|
||||||
AuthMode.SERVICE_TOKEN,
|
|
||||||
AuthMode.IDENTITY_ACCESS_TOKEN
|
|
||||||
]),
|
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
let { secretPath, environment, workspaceId } = req.query;
|
let { secretPath, environment, workspaceId } = req.query;
|
||||||
if (req.auth.actor === ActorType.SERVICE) {
|
if (req.auth.actor === ActorType.SERVICE) {
|
||||||
@@ -162,8 +151,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!workspaceId || !environment)
|
if (!workspaceId || !environment) throw new BadRequestError({ message: "Missing workspace id or environment" });
|
||||||
throw new BadRequestError({ message: "Missing workspace id or environment" });
|
|
||||||
|
|
||||||
const secret = await server.services.secret.getSecretByNameRaw({
|
const secret = await server.services.secret.getSecretByNameRaw({
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
@@ -218,9 +206,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
workspaceId: z.string().trim(),
|
workspaceId: z.string().trim(),
|
||||||
environment: z.string().trim(),
|
environment: z.string().trim(),
|
||||||
secretPath: z.string().trim().default("/").transform(removeTrailingSlash),
|
secretPath: z.string().trim().default("/").transform(removeTrailingSlash),
|
||||||
secretValue: z
|
secretValue: z.string().transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim())),
|
||||||
.string()
|
|
||||||
.transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim())),
|
|
||||||
secretComment: z.string().trim().optional().default(""),
|
secretComment: z.string().trim().optional().default(""),
|
||||||
skipMultilineEncoding: z.boolean().optional(),
|
skipMultilineEncoding: z.boolean().optional(),
|
||||||
type: z.nativeEnum(SecretType).default(SecretType.Shared)
|
type: z.nativeEnum(SecretType).default(SecretType.Shared)
|
||||||
@@ -231,12 +217,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
AuthMode.JWT,
|
|
||||||
AuthMode.API_KEY,
|
|
||||||
AuthMode.SERVICE_TOKEN,
|
|
||||||
AuthMode.IDENTITY_ACCESS_TOKEN
|
|
||||||
]),
|
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const secret = await server.services.secret.createSecretRaw({
|
const secret = await server.services.secret.createSecretRaw({
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
@@ -293,9 +274,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
body: z.object({
|
body: z.object({
|
||||||
workspaceId: z.string().trim(),
|
workspaceId: z.string().trim(),
|
||||||
environment: z.string().trim(),
|
environment: z.string().trim(),
|
||||||
secretValue: z
|
secretValue: z.string().transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim())),
|
||||||
.string()
|
|
||||||
.transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim())),
|
|
||||||
secretPath: z.string().trim().default("/").transform(removeTrailingSlash),
|
secretPath: z.string().trim().default("/").transform(removeTrailingSlash),
|
||||||
skipMultilineEncoding: z.boolean().optional(),
|
skipMultilineEncoding: z.boolean().optional(),
|
||||||
type: z.nativeEnum(SecretType).default(SecretType.Shared)
|
type: z.nativeEnum(SecretType).default(SecretType.Shared)
|
||||||
@@ -306,12 +285,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
AuthMode.JWT,
|
|
||||||
AuthMode.API_KEY,
|
|
||||||
AuthMode.SERVICE_TOKEN,
|
|
||||||
AuthMode.IDENTITY_ACCESS_TOKEN
|
|
||||||
]),
|
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const secret = await server.services.secret.updateSecretRaw({
|
const secret = await server.services.secret.updateSecretRaw({
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
@@ -375,12 +349,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
AuthMode.JWT,
|
|
||||||
AuthMode.API_KEY,
|
|
||||||
AuthMode.SERVICE_TOKEN,
|
|
||||||
AuthMode.IDENTITY_ACCESS_TOKEN
|
|
||||||
]),
|
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const secret = await server.services.secret.deleteSecretRaw({
|
const secret = await server.services.secret.deleteSecretRaw({
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
@@ -474,12 +443,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
AuthMode.JWT,
|
|
||||||
AuthMode.API_KEY,
|
|
||||||
AuthMode.SERVICE_TOKEN,
|
|
||||||
AuthMode.IDENTITY_ACCESS_TOKEN
|
|
||||||
]),
|
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { secrets, imports } = await server.services.secret.getSecrets({
|
const { secrets, imports } = await server.services.secret.getSecrets({
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
@@ -549,12 +513,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
AuthMode.JWT,
|
|
||||||
AuthMode.API_KEY,
|
|
||||||
AuthMode.SERVICE_TOKEN,
|
|
||||||
AuthMode.IDENTITY_ACCESS_TOKEN
|
|
||||||
]),
|
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const secret = await server.services.secret.getSecretByName({
|
const secret = await server.services.secret.getSecretByName({
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
@@ -634,18 +593,11 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
z
|
z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled")
|
||||||
.object({ approval: SecretApprovalRequestsSchema })
|
|
||||||
.describe("When secret protection policy is enabled")
|
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
AuthMode.JWT,
|
|
||||||
AuthMode.API_KEY,
|
|
||||||
AuthMode.SERVICE_TOKEN,
|
|
||||||
AuthMode.IDENTITY_ACCESS_TOKEN
|
|
||||||
]),
|
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const {
|
const {
|
||||||
workspaceId: projectId,
|
workspaceId: projectId,
|
||||||
@@ -673,32 +625,31 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
projectId
|
projectId
|
||||||
});
|
});
|
||||||
if (policy) {
|
if (policy) {
|
||||||
const approval =
|
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
|
||||||
await server.services.secretApprovalRequest.generateSecretApprovalRequest({
|
actorId: req.permission.id,
|
||||||
actorId: req.permission.id,
|
actor: req.permission.type,
|
||||||
actor: req.permission.type,
|
secretPath,
|
||||||
secretPath,
|
environment,
|
||||||
environment,
|
projectId,
|
||||||
projectId,
|
policy,
|
||||||
policy,
|
data: {
|
||||||
data: {
|
[CommitType.Create]: [
|
||||||
[CommitType.Create]: [
|
{
|
||||||
{
|
secretName: req.params.secretName,
|
||||||
secretName: req.params.secretName,
|
secretValueCiphertext,
|
||||||
secretValueCiphertext,
|
secretValueIV,
|
||||||
secretValueIV,
|
secretValueTag,
|
||||||
secretValueTag,
|
secretCommentIV,
|
||||||
secretCommentIV,
|
secretCommentTag,
|
||||||
secretCommentTag,
|
secretCommentCiphertext,
|
||||||
secretCommentCiphertext,
|
skipMultilineEncoding,
|
||||||
skipMultilineEncoding,
|
secretKeyTag,
|
||||||
secretKeyTag,
|
secretKeyCiphertext,
|
||||||
secretKeyCiphertext,
|
secretKeyIV
|
||||||
secretKeyIV
|
}
|
||||||
}
|
]
|
||||||
]
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
projectId: req.body.workspaceId,
|
projectId: req.body.workspaceId,
|
||||||
@@ -810,18 +761,11 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
z
|
z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled")
|
||||||
.object({ approval: SecretApprovalRequestsSchema })
|
|
||||||
.describe("When secret protection policy is enabled")
|
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
AuthMode.JWT,
|
|
||||||
AuthMode.API_KEY,
|
|
||||||
AuthMode.SERVICE_TOKEN,
|
|
||||||
AuthMode.IDENTITY_ACCESS_TOKEN
|
|
||||||
]),
|
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const {
|
const {
|
||||||
secretValueCiphertext,
|
secretValueCiphertext,
|
||||||
@@ -854,34 +798,33 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
projectId
|
projectId
|
||||||
});
|
});
|
||||||
if (policy) {
|
if (policy) {
|
||||||
const approval =
|
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
|
||||||
await server.services.secretApprovalRequest.generateSecretApprovalRequest({
|
actorId: req.permission.id,
|
||||||
actorId: req.permission.id,
|
actor: req.permission.type,
|
||||||
actor: req.permission.type,
|
secretPath,
|
||||||
secretPath,
|
environment,
|
||||||
environment,
|
projectId,
|
||||||
projectId,
|
policy,
|
||||||
policy,
|
data: {
|
||||||
data: {
|
[CommitType.Update]: [
|
||||||
[CommitType.Update]: [
|
{
|
||||||
{
|
secretName: req.params.secretName,
|
||||||
secretName: req.params.secretName,
|
newSecretName,
|
||||||
newSecretName,
|
secretValueCiphertext,
|
||||||
secretValueCiphertext,
|
secretValueIV,
|
||||||
secretValueIV,
|
secretValueTag,
|
||||||
secretValueTag,
|
secretCommentIV,
|
||||||
secretCommentIV,
|
secretCommentTag,
|
||||||
secretCommentTag,
|
secretCommentCiphertext,
|
||||||
secretCommentCiphertext,
|
skipMultilineEncoding,
|
||||||
skipMultilineEncoding,
|
secretKeyTag,
|
||||||
secretKeyTag,
|
secretKeyCiphertext,
|
||||||
secretKeyCiphertext,
|
secretKeyIV,
|
||||||
secretKeyIV,
|
tagIds: tags
|
||||||
tagIds: tags
|
}
|
||||||
}
|
]
|
||||||
]
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
projectId: req.body.workspaceId,
|
projectId: req.body.workspaceId,
|
||||||
@@ -980,18 +923,11 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
z
|
z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled")
|
||||||
.object({ approval: SecretApprovalRequestsSchema })
|
|
||||||
.describe("When secret protection policy is enabled")
|
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
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) {
|
||||||
@@ -1003,22 +939,21 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
projectId
|
projectId
|
||||||
});
|
});
|
||||||
if (policy) {
|
if (policy) {
|
||||||
const approval =
|
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
|
||||||
await server.services.secretApprovalRequest.generateSecretApprovalRequest({
|
actorId: req.permission.id,
|
||||||
actorId: req.permission.id,
|
actor: req.permission.type,
|
||||||
actor: req.permission.type,
|
secretPath,
|
||||||
secretPath,
|
environment,
|
||||||
environment,
|
projectId,
|
||||||
projectId,
|
policy,
|
||||||
policy,
|
data: {
|
||||||
data: {
|
[CommitType.Delete]: [
|
||||||
[CommitType.Delete]: [
|
{
|
||||||
{
|
secretName: req.params.secretName
|
||||||
secretName: req.params.secretName
|
}
|
||||||
}
|
]
|
||||||
]
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
projectId: req.body.workspaceId,
|
projectId: req.body.workspaceId,
|
||||||
@@ -1110,18 +1045,11 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
z.object({
|
z.object({
|
||||||
secrets: SecretsSchema.omit({ secretBlindIndex: true }).array()
|
secrets: SecretsSchema.omit({ secretBlindIndex: true }).array()
|
||||||
}),
|
}),
|
||||||
z
|
z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled")
|
||||||
.object({ approval: SecretApprovalRequestsSchema })
|
|
||||||
.describe("When secret protection policy is enabled")
|
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
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) {
|
||||||
@@ -1133,18 +1061,17 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
projectId
|
projectId
|
||||||
});
|
});
|
||||||
if (policy) {
|
if (policy) {
|
||||||
const approval =
|
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
|
||||||
await server.services.secretApprovalRequest.generateSecretApprovalRequest({
|
actorId: req.permission.id,
|
||||||
actorId: req.permission.id,
|
actor: req.permission.type,
|
||||||
actor: req.permission.type,
|
secretPath,
|
||||||
secretPath,
|
environment,
|
||||||
environment,
|
projectId,
|
||||||
projectId,
|
policy,
|
||||||
policy,
|
data: {
|
||||||
data: {
|
[CommitType.Create]: inputSecrets.filter(({ type }) => type === "shared")
|
||||||
[CommitType.Create]: inputSecrets.filter(({ type }) => type === "shared")
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
projectId: req.body.workspaceId,
|
projectId: req.body.workspaceId,
|
||||||
@@ -1236,18 +1163,11 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
z.object({
|
z.object({
|
||||||
secrets: SecretsSchema.omit({ secretBlindIndex: true }).array()
|
secrets: SecretsSchema.omit({ secretBlindIndex: true }).array()
|
||||||
}),
|
}),
|
||||||
z
|
z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled")
|
||||||
.object({ approval: SecretApprovalRequestsSchema })
|
|
||||||
.describe("When secret protection policy is enabled")
|
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
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) {
|
||||||
@@ -1259,18 +1179,17 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
projectId
|
projectId
|
||||||
});
|
});
|
||||||
if (policy) {
|
if (policy) {
|
||||||
const approval =
|
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
|
||||||
await server.services.secretApprovalRequest.generateSecretApprovalRequest({
|
actorId: req.permission.id,
|
||||||
actorId: req.permission.id,
|
actor: req.permission.type,
|
||||||
actor: req.permission.type,
|
secretPath,
|
||||||
secretPath,
|
environment,
|
||||||
environment,
|
projectId,
|
||||||
projectId,
|
policy,
|
||||||
policy,
|
data: {
|
||||||
data: {
|
[CommitType.Update]: inputSecrets.filter(({ type }) => type === "shared")
|
||||||
[CommitType.Update]: inputSecrets.filter(({ type }) => type === "shared")
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
projectId: req.body.workspaceId,
|
projectId: req.body.workspaceId,
|
||||||
@@ -1350,18 +1269,11 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
z.object({
|
z.object({
|
||||||
secrets: SecretsSchema.omit({ secretBlindIndex: true }).array()
|
secrets: SecretsSchema.omit({ secretBlindIndex: true }).array()
|
||||||
}),
|
}),
|
||||||
z
|
z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled")
|
||||||
.object({ approval: SecretApprovalRequestsSchema })
|
|
||||||
.describe("When secret protection policy is enabled")
|
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
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) {
|
||||||
@@ -1373,18 +1285,17 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
projectId
|
projectId
|
||||||
});
|
});
|
||||||
if (policy) {
|
if (policy) {
|
||||||
const approval =
|
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
|
||||||
await server.services.secretApprovalRequest.generateSecretApprovalRequest({
|
actorId: req.permission.id,
|
||||||
actorId: req.permission.id,
|
actor: req.permission.type,
|
||||||
actor: req.permission.type,
|
secretPath,
|
||||||
secretPath,
|
environment,
|
||||||
environment,
|
projectId,
|
||||||
projectId,
|
policy,
|
||||||
policy,
|
data: {
|
||||||
data: {
|
[CommitType.Delete]: inputSecrets.filter(({ type }) => type === "shared")
|
||||||
[CommitType.Delete]: inputSecrets.filter(({ type }) => type === "shared")
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
projectId: req.body.workspaceId,
|
projectId: req.body.workspaceId,
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
|
|||||||
@@ -48,10 +48,7 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { token, user } = await server.services.signup.verifyEmailSignup(
|
const { token, user } = await server.services.signup.verifyEmailSignup(req.body.email, req.body.code);
|
||||||
req.body.email,
|
|
||||||
req.body.code
|
|
||||||
);
|
|
||||||
return { message: "Successfuly verified email", token, user };
|
return { message: "Successfuly verified email", token, user };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -93,19 +90,14 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => {
|
|||||||
if (!userAgent) throw new Error("user agent header is required");
|
if (!userAgent) throw new Error("user agent header is required");
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
|
|
||||||
const { user, accessToken, refreshToken } =
|
const { user, accessToken, refreshToken } = await server.services.signup.completeEmailAccountSignup({
|
||||||
await server.services.signup.completeEmailAccountSignup({
|
...req.body,
|
||||||
...req.body,
|
ip: req.realIp,
|
||||||
ip: req.realIp,
|
userAgent,
|
||||||
userAgent,
|
authorization: req.headers.authorization as string
|
||||||
authorization: req.headers.authorization as string
|
});
|
||||||
});
|
|
||||||
|
|
||||||
void server.services.telemetry.sendLoopsEvent(
|
void server.services.telemetry.sendLoopsEvent(user.email, user.firstName || "", user.lastName || "");
|
||||||
user.email,
|
|
||||||
user.firstName || "",
|
|
||||||
user.lastName || ""
|
|
||||||
);
|
|
||||||
|
|
||||||
void server.services.telemetry.sendPostHogEvents({
|
void server.services.telemetry.sendPostHogEvents({
|
||||||
event: PostHogEventTypes.UserSignedUp,
|
event: PostHogEventTypes.UserSignedUp,
|
||||||
@@ -161,12 +153,11 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => {
|
|||||||
if (!userAgent) throw new Error("user agent header is required");
|
if (!userAgent) throw new Error("user agent header is required");
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
|
|
||||||
const { user, accessToken, refreshToken } =
|
const { user, accessToken, refreshToken } = await server.services.signup.completeAccountInvite({
|
||||||
await server.services.signup.completeAccountInvite({
|
...req.body,
|
||||||
...req.body,
|
ip: req.realIp,
|
||||||
ip: req.realIp,
|
userAgent
|
||||||
userAgent
|
});
|
||||||
});
|
|
||||||
|
|
||||||
await res.setCookie("jid", refreshToken, {
|
await res.setCookie("jid", refreshToken, {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
|
|||||||
@@ -45,8 +45,7 @@ export const apiKeyServiceFactory = ({ apiKeyDAL, userDAL }: TApiKeyServiceFacto
|
|||||||
|
|
||||||
const deleteApiKey = async (userId: string, apiKeyId: string) => {
|
const deleteApiKey = async (userId: string, apiKeyId: string) => {
|
||||||
const [apiKeyData] = await apiKeyDAL.delete({ id: apiKeyId, userId });
|
const [apiKeyData] = await apiKeyDAL.delete({ id: apiKeyId, userId });
|
||||||
if (!apiKeyData)
|
if (!apiKeyData) throw new BadRequestError({ message: "Failed to find api key", name: "delete api key" });
|
||||||
throw new BadRequestError({ message: "Failed to find api key", name: "delete api key" });
|
|
||||||
return formatApiKey(apiKeyData);
|
return formatApiKey(apiKeyData);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,7 @@ export type TTokenDALFactory = ReturnType<typeof tokenDALFactory>;
|
|||||||
export const tokenDALFactory = (db: TDbClient) => {
|
export const tokenDALFactory = (db: TDbClient) => {
|
||||||
const authOrm = ormify(db, TableName.AuthTokens);
|
const authOrm = ormify(db, TableName.AuthTokens);
|
||||||
|
|
||||||
const findOneTokenSession = async (
|
const findOneTokenSession = async (filter: Partial<TAuthTokenSessions>): Promise<TAuthTokenSessions | undefined> => {
|
||||||
filter: Partial<TAuthTokenSessions>
|
|
||||||
): Promise<TAuthTokenSessions | undefined> => {
|
|
||||||
try {
|
try {
|
||||||
const doc = await db(TableName.AuthTokenSession).where(filter).first();
|
const doc = await db(TableName.AuthTokenSession).where(filter).first();
|
||||||
return doc;
|
return doc;
|
||||||
@@ -29,20 +27,14 @@ export const tokenDALFactory = (db: TDbClient) => {
|
|||||||
orgId
|
orgId
|
||||||
}: TDeleteTokenForUserDALDTO): Promise<TAuthTokens[] | undefined> => {
|
}: TDeleteTokenForUserDALDTO): Promise<TAuthTokens[] | undefined> => {
|
||||||
try {
|
try {
|
||||||
const doc = await db(TableName.AuthTokens)
|
const doc = await db(TableName.AuthTokens).where({ userId, type, orgId }).delete().returning("*");
|
||||||
.where({ userId, type, orgId })
|
|
||||||
.delete()
|
|
||||||
.returning("*");
|
|
||||||
return doc;
|
return doc;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "DeleteTokenForUser" });
|
throw new DatabaseError({ error, name: "DeleteTokenForUser" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const decrementTriesField = async ({
|
const decrementTriesField = async ({ userId, type }: TDeleteTokenForUserDALDTO): Promise<void> => {
|
||||||
userId,
|
|
||||||
type
|
|
||||||
}: TDeleteTokenForUserDALDTO): Promise<void> => {
|
|
||||||
try {
|
try {
|
||||||
await db(TableName.AuthTokens).where({ userId, type }).decrement("triesLeft", 1);
|
await db(TableName.AuthTokens).where({ userId, type }).decrement("triesLeft", 1);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -99,10 +91,7 @@ export const tokenDALFactory = (db: TDbClient) => {
|
|||||||
|
|
||||||
const deleteTokenSession = async (filter: Partial<TAuthTokenSessions>, tx?: Knex) => {
|
const deleteTokenSession = async (filter: Partial<TAuthTokenSessions>, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const sessions = await (tx || db)(TableName.AuthTokenSession)
|
const sessions = await (tx || db)(TableName.AuthTokenSession).where(filter).del().returning("*");
|
||||||
.where(filter)
|
|
||||||
.del()
|
|
||||||
.returning("*");
|
|
||||||
return sessions;
|
return sessions;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ name: "Delete token session", error });
|
throw new DatabaseError({ name: "Delete token session", error });
|
||||||
|
|||||||
@@ -9,12 +9,7 @@ import { UnauthorizedError } from "@app/lib/errors";
|
|||||||
import { AuthModeJwtTokenPayload } from "../auth/auth-type";
|
import { AuthModeJwtTokenPayload } from "../auth/auth-type";
|
||||||
import { TUserDALFactory } from "../user/user-dal";
|
import { TUserDALFactory } from "../user/user-dal";
|
||||||
import { TTokenDALFactory } from "./auth-token-dal";
|
import { TTokenDALFactory } from "./auth-token-dal";
|
||||||
import {
|
import { TCreateTokenForUserDTO, TIssueAuthTokenDTO, TokenType, TValidateTokenForUserDTO } from "./auth-token-types";
|
||||||
TCreateTokenForUserDTO,
|
|
||||||
TIssueAuthTokenDTO,
|
|
||||||
TokenType,
|
|
||||||
TValidateTokenForUserDTO
|
|
||||||
} from "./auth-token-types";
|
|
||||||
|
|
||||||
type TAuthTokenServiceFactoryDep = {
|
type TAuthTokenServiceFactoryDep = {
|
||||||
tokenDAL: TTokenDALFactory;
|
tokenDAL: TTokenDALFactory;
|
||||||
@@ -125,14 +120,10 @@ export const tokenServiceFactory = ({ tokenDAL, userDAL }: TAuthTokenServiceFact
|
|||||||
return session;
|
return session;
|
||||||
};
|
};
|
||||||
|
|
||||||
const clearTokenSessionById = async (
|
const clearTokenSessionById = async (userId: string, sessionId: string): Promise<TAuthTokenSessions | undefined> =>
|
||||||
userId: string,
|
|
||||||
sessionId: string
|
|
||||||
): Promise<TAuthTokenSessions | undefined> =>
|
|
||||||
tokenDAL.incrementTokenSessionVersion(userId, sessionId);
|
tokenDAL.incrementTokenSessionVersion(userId, sessionId);
|
||||||
|
|
||||||
const getUserTokenSessionById = async (id: string, userId: string) =>
|
const getUserTokenSessionById = async (id: string, userId: string) => tokenDAL.findOneTokenSession({ id, userId });
|
||||||
tokenDAL.findOneTokenSession({ id, userId });
|
|
||||||
|
|
||||||
const getTokenSessionByUser = async (userId: string) => tokenDAL.findTokenSessions({ userId });
|
const getTokenSessionByUser = async (userId: string) => tokenDAL.findTokenSessions({ userId });
|
||||||
|
|
||||||
@@ -145,8 +136,7 @@ export const tokenServiceFactory = ({ tokenDAL, userDAL }: TAuthTokenServiceFact
|
|||||||
userId: token.userId
|
userId: token.userId
|
||||||
});
|
});
|
||||||
if (!session) throw new UnauthorizedError({ name: "Session not found" });
|
if (!session) throw new UnauthorizedError({ name: "Session not found" });
|
||||||
if (token.accessVersion !== session.accessVersion)
|
if (token.accessVersion !== session.accessVersion) throw new UnauthorizedError({ name: "Stale session" });
|
||||||
throw new UnauthorizedError({ name: "Stale session" });
|
|
||||||
|
|
||||||
const user = await userDAL.findById(session.userId);
|
const user = await userDAL.findById(session.userId);
|
||||||
if (!user || !user.isAccepted) throw new UnauthorizedError({ name: "Token user not found" });
|
if (!user || !user.isAccepted) throw new UnauthorizedError({ name: "Token user not found" });
|
||||||
|
|||||||
@@ -3,19 +3,12 @@ import jwt from "jsonwebtoken";
|
|||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
|
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
|
||||||
|
|
||||||
import {
|
import { AuthModeProviderJwtTokenPayload, AuthModeProviderSignUpTokenPayload, AuthTokenType } from "./auth-type";
|
||||||
AuthModeProviderJwtTokenPayload,
|
|
||||||
AuthModeProviderSignUpTokenPayload,
|
|
||||||
AuthTokenType
|
|
||||||
} from "./auth-type";
|
|
||||||
|
|
||||||
export const validateProviderAuthToken = (providerToken: string, email: string) => {
|
export const validateProviderAuthToken = (providerToken: string, email: string) => {
|
||||||
if (!providerToken) throw new UnauthorizedError();
|
if (!providerToken) throw new UnauthorizedError();
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
const decodedToken = jwt.verify(
|
const decodedToken = jwt.verify(providerToken, appCfg.AUTH_SECRET) as AuthModeProviderJwtTokenPayload;
|
||||||
providerToken,
|
|
||||||
appCfg.AUTH_SECRET
|
|
||||||
) as AuthModeProviderJwtTokenPayload;
|
|
||||||
|
|
||||||
if (decodedToken.authTokenType !== AuthTokenType.PROVIDER_TOKEN) throw new UnauthorizedError();
|
if (decodedToken.authTokenType !== AuthTokenType.PROVIDER_TOKEN) throw new UnauthorizedError();
|
||||||
if (decodedToken.email !== email) throw new Error("Invalid auth credentials");
|
if (decodedToken.email !== email) throw new Error("Invalid auth credentials");
|
||||||
@@ -23,10 +16,7 @@ export const validateProviderAuthToken = (providerToken: string, email: string)
|
|||||||
|
|
||||||
export const validateSignUpAuthorization = (token: string, userId: string, validate = true) => {
|
export const validateSignUpAuthorization = (token: string, userId: string, validate = true) => {
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
const [AUTH_TOKEN_TYPE, AUTH_TOKEN_VALUE] = <[string, string]>token?.split(" ", 2) ?? [
|
const [AUTH_TOKEN_TYPE, AUTH_TOKEN_VALUE] = <[string, string]>token?.split(" ", 2) ?? [null, null];
|
||||||
null,
|
|
||||||
null
|
|
||||||
];
|
|
||||||
if (AUTH_TOKEN_TYPE === null) {
|
if (AUTH_TOKEN_TYPE === null) {
|
||||||
throw new BadRequestError({ message: "Missing Authorization Header in the request header." });
|
throw new BadRequestError({ message: "Missing Authorization Header in the request header." });
|
||||||
}
|
}
|
||||||
@@ -41,10 +31,7 @@ export const validateSignUpAuthorization = (token: string, userId: string, valid
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const decodedToken = jwt.verify(
|
const decodedToken = jwt.verify(AUTH_TOKEN_VALUE, appCfg.AUTH_SECRET) as AuthModeProviderSignUpTokenPayload;
|
||||||
AUTH_TOKEN_VALUE,
|
|
||||||
appCfg.AUTH_SECRET
|
|
||||||
) as AuthModeProviderSignUpTokenPayload;
|
|
||||||
if (!validate) return decodedToken;
|
if (!validate) return decodedToken;
|
||||||
|
|
||||||
if (decodedToken.authTokenType !== AuthTokenType.SIGNUP_TOKEN) throw new UnauthorizedError();
|
if (decodedToken.authTokenType !== AuthTokenType.SIGNUP_TOKEN) throw new UnauthorizedError();
|
||||||
|
|||||||
@@ -25,11 +25,7 @@ type TAuthLoginServiceFactoryDep = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type TAuthLoginFactory = ReturnType<typeof authLoginServiceFactory>;
|
export type TAuthLoginFactory = ReturnType<typeof authLoginServiceFactory>;
|
||||||
export const authLoginServiceFactory = ({
|
export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }: TAuthLoginServiceFactoryDep) => {
|
||||||
userDAL,
|
|
||||||
tokenService,
|
|
||||||
smtpService
|
|
||||||
}: TAuthLoginServiceFactoryDep) => {
|
|
||||||
/*
|
/*
|
||||||
* Private
|
* Private
|
||||||
* Not exported. This is to update user device list
|
* Not exported. This is to update user device list
|
||||||
@@ -37,9 +33,7 @@ export const authLoginServiceFactory = ({
|
|||||||
*/
|
*/
|
||||||
const updateUserDeviceSession = async (user: TUsers, ip: string, userAgent: string) => {
|
const updateUserDeviceSession = async (user: TUsers, ip: string, userAgent: string) => {
|
||||||
const devices = await UserDeviceSchema.parseAsync(user.devices || []);
|
const devices = await UserDeviceSchema.parseAsync(user.devices || []);
|
||||||
const isDeviceSeen = devices.some(
|
const isDeviceSeen = devices.some((device) => device.ip === ip && device.userAgent === userAgent);
|
||||||
(device) => device.ip === ip && device.userAgent === userAgent
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!isDeviceSeen) {
|
if (!isDeviceSeen) {
|
||||||
const newDeviceList = devices.concat([{ ip, userAgent }]);
|
const newDeviceList = devices.concat([{ ip, userAgent }]);
|
||||||
@@ -159,8 +153,7 @@ export const authLoginServiceFactory = ({
|
|||||||
validateProviderAuthToken(providerAuthToken as string, email);
|
validateProviderAuthToken(providerAuthToken as string, email);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!userEnc.serverPrivateKey || !userEnc.clientPublicKey)
|
if (!userEnc.serverPrivateKey || !userEnc.clientPublicKey) throw new Error("Failed to authenticate. Try again?");
|
||||||
throw new Error("Failed to authenticate. Try again?");
|
|
||||||
const isValidClientProof = await srpCheckClientProof(
|
const isValidClientProof = await srpCheckClientProof(
|
||||||
userEnc.salt,
|
userEnc.salt,
|
||||||
userEnc.verifier,
|
userEnc.verifier,
|
||||||
@@ -176,11 +169,9 @@ export const authLoginServiceFactory = ({
|
|||||||
});
|
});
|
||||||
// send multi factor auth token if they it enabled
|
// send multi factor auth token if they it enabled
|
||||||
if (userEnc.isMfaEnabled) {
|
if (userEnc.isMfaEnabled) {
|
||||||
const mfaToken = jwt.sign(
|
const mfaToken = jwt.sign({ authTokenType: AuthTokenType.MFA_TOKEN, userId: userEnc.userId }, cfg.AUTH_SECRET, {
|
||||||
{ authTokenType: AuthTokenType.MFA_TOKEN, userId: userEnc.userId },
|
expiresIn: cfg.JWT_MFA_LIFETIME
|
||||||
cfg.AUTH_SECRET,
|
});
|
||||||
{ expiresIn: cfg.JWT_MFA_LIFETIME }
|
|
||||||
);
|
|
||||||
await sendUserMfaCode(userEnc.userId, userEnc.email);
|
await sendUserMfaCode(userEnc.userId, userEnc.email);
|
||||||
|
|
||||||
return { isMfaEnabled: true, token: mfaToken } as const;
|
return { isMfaEnabled: true, token: mfaToken } as const;
|
||||||
@@ -230,8 +221,7 @@ export const authLoginServiceFactory = ({
|
|||||||
let user = await userDAL.findUserByEmail(email);
|
let user = await userDAL.findUserByEmail(email);
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
const isOauthSignUpDisabled = !isSignupAllowed && !user;
|
const isOauthSignUpDisabled = !isSignupAllowed && !user;
|
||||||
if (isOauthSignUpDisabled)
|
if (isOauthSignUpDisabled) throw new BadRequestError({ message: "User signup disabled", name: "Oauth 2 login" });
|
||||||
throw new BadRequestError({ message: "User signup disabled", name: "Oauth 2 login" });
|
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
user = await userDAL.create({ email, firstName, lastName, authMethods: [authMethod] });
|
user = await userDAL.create({ email, firstName, lastName, authMethods: [authMethod] });
|
||||||
|
|||||||
@@ -9,11 +9,7 @@ import { TokenType } from "../auth-token/auth-token-types";
|
|||||||
import { SmtpTemplates, TSmtpService } from "../smtp/smtp-service";
|
import { SmtpTemplates, TSmtpService } from "../smtp/smtp-service";
|
||||||
import { TUserDALFactory } from "../user/user-dal";
|
import { TUserDALFactory } from "../user/user-dal";
|
||||||
import { TAuthDALFactory } from "./auth-dal";
|
import { TAuthDALFactory } from "./auth-dal";
|
||||||
import {
|
import { TChangePasswordDTO, TCreateBackupPrivateKeyDTO, TResetPasswordViaBackupKeyDTO } from "./auth-password-type";
|
||||||
TChangePasswordDTO,
|
|
||||||
TCreateBackupPrivateKeyDTO,
|
|
||||||
TResetPasswordViaBackupKeyDTO
|
|
||||||
} from "./auth-password-type";
|
|
||||||
import { AuthTokenType } from "./auth-type";
|
import { AuthTokenType } from "./auth-type";
|
||||||
|
|
||||||
type TAuthPasswordServiceFactoryDep = {
|
type TAuthPasswordServiceFactoryDep = {
|
||||||
@@ -70,8 +66,7 @@ export const authPaswordServiceFactory = ({
|
|||||||
serverPrivateKey: null,
|
serverPrivateKey: null,
|
||||||
clientPublicKey: null
|
clientPublicKey: null
|
||||||
});
|
});
|
||||||
if (!userEnc.serverPrivateKey || !userEnc.clientPublicKey)
|
if (!userEnc.serverPrivateKey || !userEnc.clientPublicKey) throw new Error("Failed to authenticate. Try again?");
|
||||||
throw new Error("Failed to authenticate. Try again?");
|
|
||||||
const isValidClientProof = await srpCheckClientProof(
|
const isValidClientProof = await srpCheckClientProof(
|
||||||
userEnc.salt,
|
userEnc.salt,
|
||||||
userEnc.verifier,
|
userEnc.verifier,
|
||||||
@@ -200,8 +195,7 @@ export const authPaswordServiceFactory = ({
|
|||||||
throw new Error("Failed to find user");
|
throw new Error("Failed to find user");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!userEnc.clientPublicKey || !userEnc.serverPrivateKey)
|
if (!userEnc.clientPublicKey || !userEnc.serverPrivateKey) throw new Error("failed to create backup key");
|
||||||
throw new Error("failed to create backup key");
|
|
||||||
const isValidClientProff = await srpCheckClientProof(
|
const isValidClientProff = await srpCheckClientProof(
|
||||||
userEnc.salt,
|
userEnc.salt,
|
||||||
userEnc.verifier,
|
userEnc.verifier,
|
||||||
|
|||||||
@@ -148,9 +148,7 @@ export const authSignupServiceFactory = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const hasSamlEnabled = user?.authMethods?.some((authMethod) =>
|
const hasSamlEnabled = user?.authMethods?.some((authMethod) =>
|
||||||
[AuthMethod.OKTA_SAML, AuthMethod.AZURE_SAML, AuthMethod.JUMPCLOUD_SAML].includes(
|
[AuthMethod.OKTA_SAML, AuthMethod.AZURE_SAML, AuthMethod.JUMPCLOUD_SAML].includes(authMethod as AuthMethod)
|
||||||
authMethod as AuthMethod
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!hasSamlEnabled) {
|
if (!hasSamlEnabled) {
|
||||||
@@ -162,9 +160,7 @@ export const authSignupServiceFactory = ({
|
|||||||
{ userId: user.id, status: OrgMembershipStatus.Accepted }
|
{ userId: user.id, status: OrgMembershipStatus.Accepted }
|
||||||
);
|
);
|
||||||
const uniqueOrgId = [...new Set(updatedMembersips.map(({ orgId }) => orgId))];
|
const uniqueOrgId = [...new Set(updatedMembersips.map(({ orgId }) => orgId))];
|
||||||
await Promise.allSettled(
|
await Promise.allSettled(uniqueOrgId.map((orgId) => licenseService.updateSubscriptionOrgMemberCount(orgId)));
|
||||||
uniqueOrgId.map((orgId) => licenseService.updateSubscriptionOrgMemberCount(orgId))
|
|
||||||
);
|
|
||||||
|
|
||||||
const tokenSession = await tokenService.getUserTokenSession({
|
const tokenSession = await tokenService.getUserTokenSession({
|
||||||
userAgent,
|
userAgent,
|
||||||
@@ -259,9 +255,7 @@ export const authSignupServiceFactory = ({
|
|||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
const uniqueOrgId = [...new Set(updatedMembersips.map(({ orgId }) => orgId))];
|
const uniqueOrgId = [...new Set(updatedMembersips.map(({ orgId }) => orgId))];
|
||||||
await Promise.allSettled(
|
await Promise.allSettled(uniqueOrgId.map((orgId) => licenseService.updateSubscriptionOrgMemberCount(orgId)));
|
||||||
uniqueOrgId.map((orgId) => licenseService.updateSubscriptionOrgMemberCount(orgId))
|
|
||||||
);
|
|
||||||
|
|
||||||
return { info: us, key: userEncKey };
|
return { info: us, key: userEncKey };
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,11 +14,7 @@ export const identityAccessTokenDALFactory = (db: TDbClient) => {
|
|||||||
try {
|
try {
|
||||||
const doc = await (tx || db)(TableName.IdentityAccessToken)
|
const doc = await (tx || db)(TableName.IdentityAccessToken)
|
||||||
.where(filter)
|
.where(filter)
|
||||||
.join(
|
.join(TableName.Identity, `${TableName.Identity}.id`, `${TableName.IdentityAccessToken}.identityId`)
|
||||||
TableName.Identity,
|
|
||||||
`${TableName.Identity}.id`,
|
|
||||||
`${TableName.IdentityAccessToken}.identityId`
|
|
||||||
)
|
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.IdentityUaClientSecret,
|
TableName.IdentityUaClientSecret,
|
||||||
`${TableName.IdentityAccessToken}.identityUAClientSecretId`,
|
`${TableName.IdentityAccessToken}.identityUAClientSecretId`,
|
||||||
|
|||||||
@@ -7,18 +7,13 @@ 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 {
|
import { TIdentityAccessTokenJwtPayload, TRenewAccessTokenDTO } from "./identity-access-token-types";
|
||||||
TIdentityAccessTokenJwtPayload,
|
|
||||||
TRenewAccessTokenDTO
|
|
||||||
} from "./identity-access-token-types";
|
|
||||||
|
|
||||||
type TIdentityAccessTokenServiceFactoryDep = {
|
type TIdentityAccessTokenServiceFactoryDep = {
|
||||||
identityAccessTokenDAL: TIdentityAccessTokenDALFactory;
|
identityAccessTokenDAL: TIdentityAccessTokenDALFactory;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TIdentityAccessTokenServiceFactory = ReturnType<
|
export type TIdentityAccessTokenServiceFactory = ReturnType<typeof identityAccessTokenServiceFactory>;
|
||||||
typeof identityAccessTokenServiceFactory
|
|
||||||
>;
|
|
||||||
|
|
||||||
export const identityAccessTokenServiceFactory = ({
|
export const identityAccessTokenServiceFactory = ({
|
||||||
identityAccessTokenDAL
|
identityAccessTokenDAL
|
||||||
@@ -33,11 +28,7 @@ export const identityAccessTokenServiceFactory = ({
|
|||||||
createdAt: accessTokenCreatedAt
|
createdAt: accessTokenCreatedAt
|
||||||
} = identityAccessToken;
|
} = identityAccessToken;
|
||||||
|
|
||||||
if (
|
if (accessTokenNumUsesLimit > 0 && accessTokenNumUses > 0 && accessTokenNumUses >= accessTokenNumUsesLimit) {
|
||||||
accessTokenNumUsesLimit > 0 &&
|
|
||||||
accessTokenNumUses > 0 &&
|
|
||||||
accessTokenNumUses >= accessTokenNumUsesLimit
|
|
||||||
) {
|
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "Unable to renew because access token number of uses limit reached"
|
message: "Unable to renew because access token number of uses limit reached"
|
||||||
});
|
});
|
||||||
@@ -95,8 +86,7 @@ export const identityAccessTokenServiceFactory = ({
|
|||||||
const decodedToken = jwt.verify(accessToken, appCfg.AUTH_SECRET) as JwtPayload & {
|
const decodedToken = jwt.verify(accessToken, appCfg.AUTH_SECRET) as JwtPayload & {
|
||||||
identityAccessTokenId: string;
|
identityAccessTokenId: string;
|
||||||
};
|
};
|
||||||
if (decodedToken.authTokenType !== AuthTokenType.IDENTITY_ACCESS_TOKEN)
|
if (decodedToken.authTokenType !== AuthTokenType.IDENTITY_ACCESS_TOKEN) throw new UnauthorizedError();
|
||||||
throw new UnauthorizedError();
|
|
||||||
|
|
||||||
const identityAccessToken = await identityAccessTokenDAL.findOne({
|
const identityAccessToken = await identityAccessTokenDAL.findOne({
|
||||||
[`${TableName.IdentityAccessToken}.id` as "id"]: decodedToken.identityAccessTokenId,
|
[`${TableName.IdentityAccessToken}.id` as "id"]: decodedToken.identityAccessTokenId,
|
||||||
@@ -106,20 +96,14 @@ export const identityAccessTokenServiceFactory = ({
|
|||||||
|
|
||||||
validateAccessTokenExp(identityAccessToken);
|
validateAccessTokenExp(identityAccessToken);
|
||||||
|
|
||||||
const updatedIdentityAccessToken = await identityAccessTokenDAL.updateById(
|
const updatedIdentityAccessToken = await identityAccessTokenDAL.updateById(identityAccessToken.id, {
|
||||||
identityAccessToken.id,
|
accessTokenLastRenewedAt: new Date()
|
||||||
{
|
});
|
||||||
accessTokenLastRenewedAt: new Date()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return { accessToken, identityAccessToken: updatedIdentityAccessToken };
|
return { accessToken, identityAccessToken: updatedIdentityAccessToken };
|
||||||
};
|
};
|
||||||
|
|
||||||
const fnValidateIdentityAccessToken = async (
|
const fnValidateIdentityAccessToken = async (token: TIdentityAccessTokenJwtPayload, ipAddress?: string) => {
|
||||||
token: TIdentityAccessTokenJwtPayload,
|
|
||||||
ipAddress?: string
|
|
||||||
) => {
|
|
||||||
const identityAccessToken = await identityAccessTokenDAL.findOne({
|
const identityAccessToken = await identityAccessTokenDAL.findOne({
|
||||||
[`${TableName.IdentityAccessToken}.id` as "id"]: token.identityAccessTokenId,
|
[`${TableName.IdentityAccessToken}.id` as "id"]: token.identityAccessTokenId,
|
||||||
isAccessTokenRevoked: false
|
isAccessTokenRevoked: false
|
||||||
|
|||||||
@@ -14,11 +14,7 @@ export const identityProjectDALFactory = (db: TDbClient) => {
|
|||||||
try {
|
try {
|
||||||
const docs = await (tx || db)(TableName.IdentityProjectMembership)
|
const docs = await (tx || db)(TableName.IdentityProjectMembership)
|
||||||
.where(`${TableName.IdentityProjectMembership}.projectId`, projectId)
|
.where(`${TableName.IdentityProjectMembership}.projectId`, projectId)
|
||||||
.join(
|
.join(TableName.Identity, `${TableName.IdentityProjectMembership}.identityId`, `${TableName.Identity}.id`)
|
||||||
TableName.Identity,
|
|
||||||
`${TableName.IdentityProjectMembership}.identityId`,
|
|
||||||
`${TableName.Identity}.id`
|
|
||||||
)
|
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.ProjectRoles,
|
TableName.ProjectRoles,
|
||||||
`${TableName.IdentityProjectMembership}.roleId`,
|
`${TableName.IdentityProjectMembership}.roleId`,
|
||||||
|
|||||||
@@ -2,10 +2,7 @@ import { ForbiddenError } from "@casl/ability";
|
|||||||
|
|
||||||
import { ProjectMembershipRole, TProjectRoles } from "@app/db/schemas";
|
import { ProjectMembershipRole, TProjectRoles } from "@app/db/schemas";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||||
import {
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
||||||
ProjectPermissionActions,
|
|
||||||
ProjectPermissionSub
|
|
||||||
} from "@app/ee/services/permission/project-permission";
|
|
||||||
import { isAtLeastAsPrivileged } from "@app/lib/casl";
|
import { isAtLeastAsPrivileged } from "@app/lib/casl";
|
||||||
import { BadRequestError, ForbiddenRequestError } from "@app/lib/errors";
|
import { BadRequestError, ForbiddenRequestError } from "@app/lib/errors";
|
||||||
|
|
||||||
@@ -24,10 +21,7 @@ type TIdentityProjectServiceFactoryDep = {
|
|||||||
identityProjectDAL: TIdentityProjectDALFactory;
|
identityProjectDAL: TIdentityProjectDALFactory;
|
||||||
projectDAL: Pick<TProjectDALFactory, "findById">;
|
projectDAL: Pick<TProjectDALFactory, "findById">;
|
||||||
identityOrgMembershipDAL: Pick<TIdentityOrgDALFactory, "findOne">;
|
identityOrgMembershipDAL: Pick<TIdentityOrgDALFactory, "findOne">;
|
||||||
permissionService: Pick<
|
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getProjectPermissionByRole">;
|
||||||
TPermissionServiceFactory,
|
|
||||||
"getProjectPermission" | "getProjectPermissionByRole"
|
|
||||||
>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TIdentityProjectServiceFactory = ReturnType<typeof identityProjectServiceFactory>;
|
export type TIdentityProjectServiceFactory = ReturnType<typeof identityProjectServiceFactory>;
|
||||||
@@ -38,18 +32,9 @@ export const identityProjectServiceFactory = ({
|
|||||||
identityOrgMembershipDAL,
|
identityOrgMembershipDAL,
|
||||||
projectDAL
|
projectDAL
|
||||||
}: TIdentityProjectServiceFactoryDep) => {
|
}: TIdentityProjectServiceFactoryDep) => {
|
||||||
const createProjectIdentity = async ({
|
const createProjectIdentity = async ({ identityId, actor, actorId, projectId, role }: TCreateProjectIdentityDTO) => {
|
||||||
identityId,
|
|
||||||
actor,
|
|
||||||
actorId,
|
|
||||||
projectId,
|
|
||||||
role
|
|
||||||
}: TCreateProjectIdentityDTO) => {
|
|
||||||
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Identity);
|
||||||
ProjectPermissionActions.Create,
|
|
||||||
ProjectPermissionSub.Identity
|
|
||||||
);
|
|
||||||
|
|
||||||
const existingIdentity = await identityProjectDAL.findOne({ identityId, projectId });
|
const existingIdentity = await identityProjectDAL.findOne({ identityId, projectId });
|
||||||
if (existingIdentity)
|
if (existingIdentity)
|
||||||
@@ -67,8 +52,10 @@ export const identityProjectServiceFactory = ({
|
|||||||
message: `Failed to find identity with id ${identityId}`
|
message: `Failed to find identity with id ${identityId}`
|
||||||
});
|
});
|
||||||
|
|
||||||
const { permission: rolePermission, role: customRole } =
|
const { permission: rolePermission, role: customRole } = await permissionService.getProjectPermissionByRole(
|
||||||
await permissionService.getProjectPermissionByRole(role, project.id);
|
role,
|
||||||
|
project.id
|
||||||
|
);
|
||||||
const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission);
|
const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission);
|
||||||
if (!hasPriviledge)
|
if (!hasPriviledge)
|
||||||
throw new ForbiddenRequestError({
|
throw new ForbiddenRequestError({
|
||||||
@@ -85,18 +72,9 @@ export const identityProjectServiceFactory = ({
|
|||||||
return projectIdentity;
|
return projectIdentity;
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateProjectIdentity = async ({
|
const updateProjectIdentity = async ({ projectId, identityId, role, actor, actorId }: TUpdateProjectIdentityDTO) => {
|
||||||
projectId,
|
|
||||||
identityId,
|
|
||||||
role,
|
|
||||||
actor,
|
|
||||||
actorId
|
|
||||||
}: TUpdateProjectIdentityDTO) => {
|
|
||||||
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Identity);
|
||||||
ProjectPermissionActions.Edit,
|
|
||||||
ProjectPermissionSub.Identity
|
|
||||||
);
|
|
||||||
|
|
||||||
const projectIdentity = await identityProjectDAL.findOne({ identityId, projectId });
|
const projectIdentity = await identityProjectDAL.findOne({ identityId, projectId });
|
||||||
if (!projectIdentity)
|
if (!projectIdentity)
|
||||||
@@ -115,8 +93,10 @@ export const identityProjectServiceFactory = ({
|
|||||||
|
|
||||||
let customRole: TProjectRoles | undefined;
|
let customRole: TProjectRoles | undefined;
|
||||||
if (role) {
|
if (role) {
|
||||||
const { permission: rolePermission, role: customOrgRole } =
|
const { permission: rolePermission, role: customOrgRole } = await permissionService.getProjectPermissionByRole(
|
||||||
await permissionService.getProjectPermissionByRole(role, projectIdentity.projectId);
|
role,
|
||||||
|
projectIdentity.projectId
|
||||||
|
);
|
||||||
|
|
||||||
const isCustomRole = Boolean(customOrgRole);
|
const isCustomRole = Boolean(customOrgRole);
|
||||||
const hasRequiredNewRolePermission = isAtLeastAsPrivileged(permission, rolePermission);
|
const hasRequiredNewRolePermission = isAtLeastAsPrivileged(permission, rolePermission);
|
||||||
@@ -135,12 +115,7 @@ export const identityProjectServiceFactory = ({
|
|||||||
return updatedProjectIdentity;
|
return updatedProjectIdentity;
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteProjectIdentity = async ({
|
const deleteProjectIdentity = async ({ identityId, actorId, actor, projectId }: TDeleteProjectIdentityDTO) => {
|
||||||
identityId,
|
|
||||||
actorId,
|
|
||||||
actor,
|
|
||||||
projectId
|
|
||||||
}: TDeleteProjectIdentityDTO) => {
|
|
||||||
const identityProjectMembership = await identityProjectDAL.findOne({ identityId, projectId });
|
const identityProjectMembership = await identityProjectDAL.findOne({ identityId, projectId });
|
||||||
if (!identityProjectMembership)
|
if (!identityProjectMembership)
|
||||||
throw new BadRequestError({ message: `Failed to find identity with id ${identityId}` });
|
throw new BadRequestError({ message: `Failed to find identity with id ${identityId}` });
|
||||||
@@ -150,10 +125,7 @@ export const identityProjectServiceFactory = ({
|
|||||||
actorId,
|
actorId,
|
||||||
identityProjectMembership.projectId
|
identityProjectMembership.projectId
|
||||||
);
|
);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Identity);
|
||||||
ProjectPermissionActions.Delete,
|
|
||||||
ProjectPermissionSub.Identity
|
|
||||||
);
|
|
||||||
const { permission: identityRolePermission } = await permissionService.getProjectPermission(
|
const { permission: identityRolePermission } = await permissionService.getProjectPermission(
|
||||||
ActorType.IDENTITY,
|
ActorType.IDENTITY,
|
||||||
identityId,
|
identityId,
|
||||||
@@ -169,10 +141,7 @@ export const identityProjectServiceFactory = ({
|
|||||||
|
|
||||||
const listProjectIdentities = async ({ projectId, actor, actorId }: TListProjectIdentityDTO) => {
|
const listProjectIdentities = async ({ projectId, actor, actorId }: TListProjectIdentityDTO) => {
|
||||||
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Identity);
|
||||||
ProjectPermissionActions.Read,
|
|
||||||
ProjectPermissionSub.Identity
|
|
||||||
);
|
|
||||||
|
|
||||||
const identityMemberhips = await identityProjectDAL.findByProjectId(projectId);
|
const identityMemberhips = await identityProjectDAL.findByProjectId(projectId);
|
||||||
return identityMemberhips;
|
return identityMemberhips;
|
||||||
|
|||||||
@@ -6,10 +6,7 @@ import jwt from "jsonwebtoken";
|
|||||||
|
|
||||||
import { IdentityAuthMethod } from "@app/db/schemas";
|
import { IdentityAuthMethod } from "@app/db/schemas";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import {
|
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
OrgPermissionActions,
|
|
||||||
OrgPermissionSubjects
|
|
||||||
} from "@app/ee/services/permission/org-permission";
|
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||||
import { isAtLeastAsPrivileged } from "@app/lib/casl";
|
import { isAtLeastAsPrivileged } from "@app/lib/casl";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
@@ -71,8 +68,7 @@ export const identityUaServiceFactory = ({
|
|||||||
);
|
);
|
||||||
if (!validClientSecretInfo) throw new UnauthorizedError();
|
if (!validClientSecretInfo) throw new UnauthorizedError();
|
||||||
|
|
||||||
const { clientSecretTTL, clientSecretNumUses, clientSecretNumUsesLimit } =
|
const { clientSecretTTL, clientSecretNumUses, clientSecretNumUsesLimit } = validClientSecretInfo;
|
||||||
validClientSecretInfo;
|
|
||||||
if (clientSecretTTL > 0) {
|
if (clientSecretTTL > 0) {
|
||||||
const clientSecretCreated = new Date(validClientSecretInfo.createdAt);
|
const clientSecretCreated = new Date(validClientSecretInfo.createdAt);
|
||||||
const ttlInMilliseconds = clientSecretTTL * 1000;
|
const ttlInMilliseconds = clientSecretTTL * 1000;
|
||||||
@@ -97,16 +93,12 @@ export const identityUaServiceFactory = ({
|
|||||||
isClientSecretRevoked: true
|
isClientSecretRevoked: true
|
||||||
});
|
});
|
||||||
throw new UnauthorizedError({
|
throw new UnauthorizedError({
|
||||||
message:
|
message: "Failed to authenticate identity credentials due to client secret number of uses limit reached"
|
||||||
"Failed to authenticate identity credentials due to client secret number of uses limit reached"
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const identityAccessToken = await identityUaDAL.transaction(async (tx) => {
|
const identityAccessToken = await identityUaDAL.transaction(async (tx) => {
|
||||||
const uaClientSecretDoc = await identityUaClientSecretDAL.incrementUsage(
|
const uaClientSecretDoc = await identityUaClientSecretDAL.incrementUsage(validClientSecretInfo.id, tx);
|
||||||
validClientSecretInfo.id,
|
|
||||||
tx
|
|
||||||
);
|
|
||||||
const newToken = await identityAccessTokenDAL.create(
|
const newToken = await identityAccessTokenDAL.create(
|
||||||
{
|
{
|
||||||
identityId: identityUa.identityId,
|
identityId: identityUa.identityId,
|
||||||
@@ -132,10 +124,7 @@ export const identityUaServiceFactory = ({
|
|||||||
} as TIdentityAccessTokenJwtPayload,
|
} as TIdentityAccessTokenJwtPayload,
|
||||||
appCfg.AUTH_SECRET,
|
appCfg.AUTH_SECRET,
|
||||||
{
|
{
|
||||||
expiresIn:
|
expiresIn: identityAccessToken.accessTokenMaxTTL === 0 ? undefined : identityAccessToken.accessTokenMaxTTL
|
||||||
identityAccessToken.accessTokenMaxTTL === 0
|
|
||||||
? undefined
|
|
||||||
: identityAccessToken.accessTokenMaxTTL
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return { accessToken, identityUa, validClientSecretInfo, identityAccessToken };
|
return { accessToken, identityUa, validClientSecretInfo, identityAccessToken };
|
||||||
@@ -162,35 +151,26 @@ export const identityUaServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId);
|
||||||
actor,
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity);
|
||||||
actorId,
|
|
||||||
identityMembershipOrg.orgId
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
OrgPermissionActions.Create,
|
|
||||||
OrgPermissionSubjects.Identity
|
|
||||||
);
|
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(identityMembershipOrg.orgId);
|
const plan = await licenseService.getPlan(identityMembershipOrg.orgId);
|
||||||
const reformattedClientSecretTrustedIps = clientSecretTrustedIps.map(
|
const reformattedClientSecretTrustedIps = clientSecretTrustedIps.map((clientSecretTrustedIp) => {
|
||||||
(clientSecretTrustedIp) => {
|
if (
|
||||||
if (
|
!plan.ipAllowlisting &&
|
||||||
!plan.ipAllowlisting &&
|
clientSecretTrustedIp.ipAddress !== "0.0.0.0/0" &&
|
||||||
clientSecretTrustedIp.ipAddress !== "0.0.0.0/0" &&
|
clientSecretTrustedIp.ipAddress !== "::/0"
|
||||||
clientSecretTrustedIp.ipAddress !== "::/0"
|
)
|
||||||
)
|
throw new BadRequestError({
|
||||||
throw new BadRequestError({
|
message:
|
||||||
message:
|
"Failed to add IP access range to service token due to plan restriction. Upgrade plan to add IP access range."
|
||||||
"Failed to add IP access range to service token due to plan restriction. Upgrade plan to add IP access range."
|
});
|
||||||
});
|
if (!isValidIpOrCidr(clientSecretTrustedIp.ipAddress))
|
||||||
if (!isValidIpOrCidr(clientSecretTrustedIp.ipAddress))
|
throw new BadRequestError({
|
||||||
throw new BadRequestError({
|
message: "The IP is not a valid IPv4, IPv6, or CIDR block"
|
||||||
message: "The IP is not a valid IPv4, IPv6, or CIDR block"
|
});
|
||||||
});
|
return extractIPDetails(clientSecretTrustedIp.ipAddress);
|
||||||
return extractIPDetails(clientSecretTrustedIp.ipAddress);
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
const reformattedAccessTokenTrustedIps = accessTokenTrustedIps.map((accessTokenTrustedIp) => {
|
const reformattedAccessTokenTrustedIps = accessTokenTrustedIps.map((accessTokenTrustedIp) => {
|
||||||
if (
|
if (
|
||||||
!plan.ipAllowlisting &&
|
!plan.ipAllowlisting &&
|
||||||
@@ -254,41 +234,31 @@ export const identityUaServiceFactory = ({
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
(accessTokenMaxTTL || uaIdentityAuth.accessTokenMaxTTL) > 0 &&
|
(accessTokenMaxTTL || uaIdentityAuth.accessTokenMaxTTL) > 0 &&
|
||||||
(accessTokenTTL || uaIdentityAuth.accessTokenMaxTTL) >
|
(accessTokenTTL || uaIdentityAuth.accessTokenMaxTTL) > (accessTokenMaxTTL || uaIdentityAuth.accessTokenMaxTTL)
|
||||||
(accessTokenMaxTTL || uaIdentityAuth.accessTokenMaxTTL)
|
|
||||||
) {
|
) {
|
||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId);
|
||||||
actor,
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
actorId,
|
|
||||||
identityMembershipOrg.orgId
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
OrgPermissionActions.Edit,
|
|
||||||
OrgPermissionSubjects.Identity
|
|
||||||
);
|
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(identityMembershipOrg.orgId);
|
const plan = await licenseService.getPlan(identityMembershipOrg.orgId);
|
||||||
const reformattedClientSecretTrustedIps = clientSecretTrustedIps?.map(
|
const reformattedClientSecretTrustedIps = clientSecretTrustedIps?.map((clientSecretTrustedIp) => {
|
||||||
(clientSecretTrustedIp) => {
|
if (
|
||||||
if (
|
!plan.ipAllowlisting &&
|
||||||
!plan.ipAllowlisting &&
|
clientSecretTrustedIp.ipAddress !== "0.0.0.0/0" &&
|
||||||
clientSecretTrustedIp.ipAddress !== "0.0.0.0/0" &&
|
clientSecretTrustedIp.ipAddress !== "::/0"
|
||||||
clientSecretTrustedIp.ipAddress !== "::/0"
|
)
|
||||||
)
|
throw new BadRequestError({
|
||||||
throw new BadRequestError({
|
message:
|
||||||
message:
|
"Failed to add IP access range to service token due to plan restriction. Upgrade plan to add IP access range."
|
||||||
"Failed to add IP access range to service token due to plan restriction. Upgrade plan to add IP access range."
|
});
|
||||||
});
|
if (!isValidIpOrCidr(clientSecretTrustedIp.ipAddress))
|
||||||
if (!isValidIpOrCidr(clientSecretTrustedIp.ipAddress))
|
throw new BadRequestError({
|
||||||
throw new BadRequestError({
|
message: "The IP is not a valid IPv4, IPv6, or CIDR block"
|
||||||
message: "The IP is not a valid IPv4, IPv6, or CIDR block"
|
});
|
||||||
});
|
return extractIPDetails(clientSecretTrustedIp.ipAddress);
|
||||||
return extractIPDetails(clientSecretTrustedIp.ipAddress);
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
const reformattedAccessTokenTrustedIps = accessTokenTrustedIps?.map((accessTokenTrustedIp) => {
|
const reformattedAccessTokenTrustedIps = accessTokenTrustedIps?.map((accessTokenTrustedIp) => {
|
||||||
if (
|
if (
|
||||||
!plan.ipAllowlisting &&
|
!plan.ipAllowlisting &&
|
||||||
@@ -330,15 +300,8 @@ export const identityUaServiceFactory = ({
|
|||||||
|
|
||||||
const uaIdentityAuth = await identityUaDAL.findOne({ identityId });
|
const uaIdentityAuth = await identityUaDAL.findOne({ identityId });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId);
|
||||||
actor,
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Identity);
|
||||||
actorId,
|
|
||||||
identityMembershipOrg.orgId
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
OrgPermissionActions.Read,
|
|
||||||
OrgPermissionSubjects.Identity
|
|
||||||
);
|
|
||||||
return { ...uaIdentityAuth, orgId: identityMembershipOrg.orgId };
|
return { ...uaIdentityAuth, orgId: identityMembershipOrg.orgId };
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -356,15 +319,8 @@ export const identityUaServiceFactory = ({
|
|||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "The identity does not have universal auth"
|
message: "The identity does not have universal auth"
|
||||||
});
|
});
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId);
|
||||||
actor,
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity);
|
||||||
actorId,
|
|
||||||
identityMembershipOrg.orgId
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
OrgPermissionActions.Create,
|
|
||||||
OrgPermissionSubjects.Identity
|
|
||||||
);
|
|
||||||
|
|
||||||
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
||||||
ActorType.IDENTITY,
|
ActorType.IDENTITY,
|
||||||
@@ -409,15 +365,8 @@ export const identityUaServiceFactory = ({
|
|||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "The identity does not have universal auth"
|
message: "The identity does not have universal auth"
|
||||||
});
|
});
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId);
|
||||||
actor,
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Identity);
|
||||||
actorId,
|
|
||||||
identityMembershipOrg.orgId
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
OrgPermissionActions.Read,
|
|
||||||
OrgPermissionSubjects.Identity
|
|
||||||
);
|
|
||||||
|
|
||||||
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
||||||
ActorType.IDENTITY,
|
ActorType.IDENTITY,
|
||||||
@@ -441,27 +390,15 @@ export const identityUaServiceFactory = ({
|
|||||||
return { clientSecrets, orgId: identityMembershipOrg.orgId };
|
return { clientSecrets, orgId: identityMembershipOrg.orgId };
|
||||||
};
|
};
|
||||||
|
|
||||||
const revokeUaClientSecret = async ({
|
const revokeUaClientSecret = async ({ identityId, actorId, actor, clientSecretId }: TRevokeUaClientSecretDTO) => {
|
||||||
identityId,
|
|
||||||
actorId,
|
|
||||||
actor,
|
|
||||||
clientSecretId
|
|
||||||
}: TRevokeUaClientSecretDTO) => {
|
|
||||||
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
|
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
|
||||||
if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" });
|
if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" });
|
||||||
if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.Univeral)
|
if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.Univeral)
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "The identity does not have universal auth"
|
message: "The identity does not have universal auth"
|
||||||
});
|
});
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId);
|
||||||
actor,
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Identity);
|
||||||
actorId,
|
|
||||||
identityMembershipOrg.orgId
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
OrgPermissionActions.Delete,
|
|
||||||
OrgPermissionSubjects.Identity
|
|
||||||
);
|
|
||||||
|
|
||||||
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
||||||
ActorType.IDENTITY,
|
ActorType.IDENTITY,
|
||||||
|
|||||||
@@ -14,11 +14,7 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
try {
|
try {
|
||||||
const [data] = await (tx || db)(TableName.IdentityOrgMembership)
|
const [data] = await (tx || db)(TableName.IdentityOrgMembership)
|
||||||
.where(filter)
|
.where(filter)
|
||||||
.join(
|
.join(TableName.Identity, `${TableName.IdentityOrgMembership}.identityId`, `${TableName.Identity}.id`)
|
||||||
TableName.Identity,
|
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
|
||||||
`${TableName.Identity}.id`
|
|
||||||
)
|
|
||||||
.select(selectAllTableCols(TableName.IdentityOrgMembership))
|
.select(selectAllTableCols(TableName.IdentityOrgMembership))
|
||||||
.select(db.ref("name").withSchema(TableName.Identity))
|
.select(db.ref("name").withSchema(TableName.Identity))
|
||||||
.select(db.ref("authMethod").withSchema(TableName.Identity));
|
.select(db.ref("authMethod").withSchema(TableName.Identity));
|
||||||
@@ -35,16 +31,8 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
try {
|
try {
|
||||||
const docs = await (tx || db)(TableName.IdentityOrgMembership)
|
const docs = await (tx || db)(TableName.IdentityOrgMembership)
|
||||||
.where(`${TableName.IdentityOrgMembership}.orgId`, orgId)
|
.where(`${TableName.IdentityOrgMembership}.orgId`, orgId)
|
||||||
.join(
|
.join(TableName.Identity, `${TableName.IdentityOrgMembership}.identityId`, `${TableName.Identity}.id`)
|
||||||
TableName.Identity,
|
.leftJoin(TableName.OrgRoles, `${TableName.IdentityOrgMembership}.roleId`, `${TableName.OrgRoles}.id`)
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
|
||||||
`${TableName.Identity}.id`
|
|
||||||
)
|
|
||||||
.leftJoin(
|
|
||||||
TableName.OrgRoles,
|
|
||||||
`${TableName.IdentityOrgMembership}.roleId`,
|
|
||||||
`${TableName.OrgRoles}.id`
|
|
||||||
)
|
|
||||||
.select(selectAllTableCols(TableName.IdentityOrgMembership))
|
.select(selectAllTableCols(TableName.IdentityOrgMembership))
|
||||||
// cr stands for custom role
|
// cr stands for custom role
|
||||||
.select(db.ref("id").as("crId").withSchema(TableName.OrgRoles))
|
.select(db.ref("id").as("crId").withSchema(TableName.OrgRoles))
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
import { OrgMembershipRole, TOrgRoles } from "@app/db/schemas";
|
import { OrgMembershipRole, TOrgRoles } from "@app/db/schemas";
|
||||||
import {
|
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
OrgPermissionActions,
|
|
||||||
OrgPermissionSubjects
|
|
||||||
} from "@app/ee/services/permission/org-permission";
|
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||||
import { isAtLeastAsPrivileged } from "@app/lib/casl";
|
import { isAtLeastAsPrivileged } from "@app/lib/casl";
|
||||||
import { BadRequestError, ForbiddenRequestError } from "@app/lib/errors";
|
import { BadRequestError, ForbiddenRequestError } from "@app/lib/errors";
|
||||||
@@ -30,17 +27,15 @@ export const identityServiceFactory = ({
|
|||||||
}: TIdentityServiceFactoryDep) => {
|
}: TIdentityServiceFactoryDep) => {
|
||||||
const createIdentity = async ({ name, role, actor, orgId, actorId }: TCreateIdentityDTO) => {
|
const createIdentity = async ({ name, role, actor, orgId, actorId }: TCreateIdentityDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity);
|
||||||
OrgPermissionActions.Create,
|
|
||||||
OrgPermissionSubjects.Identity
|
|
||||||
);
|
|
||||||
|
|
||||||
const { permission: rolePermission, role: customRole } =
|
const { permission: rolePermission, role: customRole } = await permissionService.getOrgPermissionByRole(
|
||||||
await permissionService.getOrgPermissionByRole(role, orgId);
|
role,
|
||||||
|
orgId
|
||||||
|
);
|
||||||
const isCustomRole = Boolean(customRole);
|
const isCustomRole = Boolean(customRole);
|
||||||
const hasRequiredPriviledges = isAtLeastAsPrivileged(permission, rolePermission);
|
const hasRequiredPriviledges = isAtLeastAsPrivileged(permission, rolePermission);
|
||||||
if (!hasRequiredPriviledges)
|
if (!hasRequiredPriviledges) throw new BadRequestError({ message: "Failed to create a more privileged identity" });
|
||||||
throw new BadRequestError({ message: "Failed to create a more privileged identity" });
|
|
||||||
|
|
||||||
const identity = await identityDAL.transaction(async (tx) => {
|
const identity = await identityDAL.transaction(async (tx) => {
|
||||||
const newIdentity = await identityDAL.create({ name }, tx);
|
const newIdentity = await identityDAL.create({ name }, tx);
|
||||||
@@ -61,18 +56,10 @@ export const identityServiceFactory = ({
|
|||||||
|
|
||||||
const updateIdentity = async ({ id, role, name, actor, actorId }: TUpdateIdentityDTO) => {
|
const updateIdentity = async ({ id, role, name, actor, actorId }: TUpdateIdentityDTO) => {
|
||||||
const identityOrgMembership = await identityOrgMembershipDAL.findOne({ identityId: id });
|
const identityOrgMembership = await identityOrgMembershipDAL.findOne({ identityId: id });
|
||||||
if (!identityOrgMembership)
|
if (!identityOrgMembership) throw new BadRequestError({ message: `Failed to find identity with id ${id}` });
|
||||||
throw new BadRequestError({ message: `Failed to find identity with id ${id}` });
|
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityOrgMembership.orgId);
|
||||||
actor,
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
actorId,
|
|
||||||
identityOrgMembership.orgId
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
OrgPermissionActions.Edit,
|
|
||||||
OrgPermissionSubjects.Identity
|
|
||||||
);
|
|
||||||
|
|
||||||
const { permission: identityRolePermission } = await permissionService.getOrgPermission(
|
const { permission: identityRolePermission } = await permissionService.getOrgPermission(
|
||||||
ActorType.IDENTITY,
|
ActorType.IDENTITY,
|
||||||
@@ -85,8 +72,10 @@ export const identityServiceFactory = ({
|
|||||||
|
|
||||||
let customRole: TOrgRoles | undefined;
|
let customRole: TOrgRoles | undefined;
|
||||||
if (role) {
|
if (role) {
|
||||||
const { permission: rolePermission, role: customOrgRole } =
|
const { permission: rolePermission, role: customOrgRole } = await permissionService.getOrgPermissionByRole(
|
||||||
await permissionService.getOrgPermissionByRole(role, identityOrgMembership.orgId);
|
role,
|
||||||
|
identityOrgMembership.orgId
|
||||||
|
);
|
||||||
|
|
||||||
const isCustomRole = Boolean(customOrgRole);
|
const isCustomRole = Boolean(customOrgRole);
|
||||||
const hasRequiredNewRolePermission = isAtLeastAsPrivileged(permission, rolePermission);
|
const hasRequiredNewRolePermission = isAtLeastAsPrivileged(permission, rolePermission);
|
||||||
@@ -96,9 +85,7 @@ export const identityServiceFactory = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const identity = await identityDAL.transaction(async (tx) => {
|
const identity = await identityDAL.transaction(async (tx) => {
|
||||||
const newIdentity = name
|
const newIdentity = name ? await identityDAL.updateById(id, { name }, tx) : await identityDAL.findById(id, tx);
|
||||||
? await identityDAL.updateById(id, { name }, tx)
|
|
||||||
: await identityDAL.findById(id, tx);
|
|
||||||
if (role) {
|
if (role) {
|
||||||
await identityOrgMembershipDAL.update(
|
await identityOrgMembershipDAL.update(
|
||||||
{ identityId: id },
|
{ identityId: id },
|
||||||
@@ -117,18 +104,10 @@ export const identityServiceFactory = ({
|
|||||||
|
|
||||||
const deleteIdentity = async ({ actorId, actor, id }: TDeleteIdentityDTO) => {
|
const deleteIdentity = async ({ actorId, actor, id }: TDeleteIdentityDTO) => {
|
||||||
const identityOrgMembership = await identityOrgMembershipDAL.findOne({ identityId: id });
|
const identityOrgMembership = await identityOrgMembershipDAL.findOne({ identityId: id });
|
||||||
if (!identityOrgMembership)
|
if (!identityOrgMembership) throw new BadRequestError({ message: `Failed to find identity with id ${id}` });
|
||||||
throw new BadRequestError({ message: `Failed to find identity with id ${id}` });
|
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityOrgMembership.orgId);
|
||||||
actor,
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Identity);
|
||||||
actorId,
|
|
||||||
identityOrgMembership.orgId
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
OrgPermissionActions.Delete,
|
|
||||||
OrgPermissionSubjects.Identity
|
|
||||||
);
|
|
||||||
const { permission: identityRolePermission } = await permissionService.getOrgPermission(
|
const { permission: identityRolePermission } = await permissionService.getOrgPermission(
|
||||||
ActorType.IDENTITY,
|
ActorType.IDENTITY,
|
||||||
id,
|
id,
|
||||||
@@ -144,10 +123,7 @@ export const identityServiceFactory = ({
|
|||||||
|
|
||||||
const listOrgIdentities = async ({ orgId, actor, actorId }: TOrgPermission) => {
|
const listOrgIdentities = async ({ orgId, actor, actorId }: TOrgPermission) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Identity);
|
||||||
OrgPermissionActions.Read,
|
|
||||||
OrgPermissionSubjects.Identity
|
|
||||||
);
|
|
||||||
|
|
||||||
const identityMemberhips = await identityOrgMembershipDAL.findByOrgId(orgId);
|
const identityMemberhips = await identityOrgMembershipDAL.findByOrgId(orgId);
|
||||||
return identityMemberhips;
|
return identityMemberhips;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user