feat: changed line length to 120

This commit is contained in:
Akhil Mohan
2024-01-30 22:40:10 +05:30
parent 5855cc660a
commit bcbb49ed1b
142 changed files with 1183 additions and 3706 deletions

View File

@@ -1,7 +1,7 @@
{ {
"singleQuote": false, "singleQuote": false,
"printWidth": 100, "printWidth": 120,
"trailingComma": "none", "trailingComma": "none",
"tabWidth": 2, "tabWidth": 2,
"semi": true "semi": true
} }

View File

@@ -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";

View File

@@ -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,

View File

@@ -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> {

View File

@@ -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");

View File

@@ -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);

View File

@@ -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);
}); });
} }

View File

@@ -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);

View File

@@ -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");
}); });
} }
} }

View File

@@ -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);

View File

@@ -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>
>;

View File

@@ -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>
>;

View File

@@ -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>
>;

View File

@@ -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>
>;

View File

@@ -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>
>;

View File

@@ -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>
>;

View File

@@ -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>
>;

View File

@@ -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>
>;

View File

@@ -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>
>;

View File

@@ -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>
>;

View File

@@ -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>
>;

View File

@@ -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>
>;

View File

@@ -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,

View File

@@ -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 }))
);
} }

View File

@@ -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

View File

@@ -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 } };
} }
}); });

View File

@@ -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
)}`
); );
} }
}); });

View File

@@ -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 };
} }
}); });

View File

@@ -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

View File

@@ -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 };
} }
}); });

View File

@@ -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)

View File

@@ -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);
}; };

View File

@@ -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,

View File

@@ -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;
}; };

View File

@@ -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))

View File

@@ -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" });

View File

@@ -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" });

View File

@@ -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);

View File

@@ -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(

View File

@@ -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;
}; };

View File

@@ -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",

View File

@@ -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);

View File

@@ -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

View File

@@ -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;

View File

@@ -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[];

View File

@@ -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,

View File

@@ -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}'`,

View File

@@ -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({

View File

@@ -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

View File

@@ -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: {

View File

@@ -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: {

View File

@@ -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" });

View File

@@ -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" });

View File

@@ -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;

View File

@@ -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);
}); });

View File

@@ -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);
}); });
}); });

View File

@@ -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`,

View File

@@ -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 });

View File

@@ -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.

View File

@@ -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

View File

@@ -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),

View File

@@ -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);

View File

@@ -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) => {

View File

@@ -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) {

View File

@@ -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" });

View File

@@ -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;

View File

@@ -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 = <

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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" });

View File

@@ -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" });

View File

@@ -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,

View File

@@ -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,

View File

@@ -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 };
} }
}); });

View File

@@ -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 };

View File

@@ -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";

View File

@@ -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({

View File

@@ -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,

View File

@@ -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
)}`
); );
} }
}); });

View File

@@ -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 };
} }
}); });

View File

@@ -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");

View File

@@ -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 };
} }
}); });

View File

@@ -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 };
} }
}); });

View File

@@ -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,

View File

@@ -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,

View File

@@ -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);
}; };

View File

@@ -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 });

View File

@@ -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" });

View File

@@ -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();

View File

@@ -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] });

View File

@@ -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,

View File

@@ -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 };
}); });

View File

@@ -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`,

View File

@@ -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

View File

@@ -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`,

View File

@@ -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;

View File

@@ -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,

View File

@@ -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))

View File

@@ -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