mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-08 05:27:52 +00:00
feat(infisical-pg): first setup for postgres migration script
This commit is contained in:
Vendored
+1
-5
@@ -12,6 +12,7 @@ import {
|
|||||||
TAuthTokenSessions,
|
TAuthTokenSessions,
|
||||||
TAuthTokenSessionsInsert,
|
TAuthTokenSessionsInsert,
|
||||||
TAuthTokenSessionsUpdate,
|
TAuthTokenSessionsUpdate,
|
||||||
|
TAuthTokensInsert,
|
||||||
TAuthTokensUpdate,
|
TAuthTokensUpdate,
|
||||||
TBackupPrivateKey,
|
TBackupPrivateKey,
|
||||||
TBackupPrivateKeyInsert,
|
TBackupPrivateKeyInsert,
|
||||||
@@ -272,11 +273,6 @@ declare module "knex/types/tables" {
|
|||||||
TSecretImportsInsert,
|
TSecretImportsInsert,
|
||||||
TSecretImportsUpdate
|
TSecretImportsUpdate
|
||||||
>;
|
>;
|
||||||
[TableName.SecretSnapshot]: Knex.CompositeTableType<
|
|
||||||
TSecretSnapshots,
|
|
||||||
TSecretSnapshotsInsert,
|
|
||||||
TSecretSnapshotsUpdate
|
|
||||||
>;
|
|
||||||
[TableName.Integration]: Knex.CompositeTableType<
|
[TableName.Integration]: Knex.CompositeTableType<
|
||||||
TIntegrations,
|
TIntegrations,
|
||||||
TIntegrationsInsert,
|
TIntegrationsInsert,
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ import { TSuperAdmin, TSuperAdminUpdate } from "@app/db/schemas";
|
|||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
|
|
||||||
import { TAuthLoginFactory } from "../auth/auth-login-service";
|
import { TAuthLoginFactory } from "../auth/auth-login-service";
|
||||||
|
import { AuthMethod } from "../auth/auth-type";
|
||||||
|
import { TOrgServiceFactory } from "../org/org-service";
|
||||||
import { TUserDalFactory } from "../user/user-dal";
|
import { TUserDalFactory } from "../user/user-dal";
|
||||||
import { TSuperAdminDalFactory } from "./super-admin-dal";
|
import { TSuperAdminDalFactory } from "./super-admin-dal";
|
||||||
import { TAdminSignUpDTO } from "./super-admin-types";
|
import { TAdminSignUpDTO } from "./super-admin-types";
|
||||||
import { TOrgServiceFactory } from "../org/org-service";
|
|
||||||
import { AuthMethod } from "../auth/auth-type";
|
|
||||||
|
|
||||||
type TSuperAdminServiceFactoryDep = {
|
type TSuperAdminServiceFactoryDep = {
|
||||||
serverCfgDal: TSuperAdminDalFactory;
|
serverCfgDal: TSuperAdminDalFactory;
|
||||||
|
|||||||
Generated
+1365
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"name": "pg-migrator",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"migration": "tsx src/index.ts"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^20.11.0",
|
||||||
|
"@types/prompt-sync": "^4.2.3",
|
||||||
|
"tsx": "^4.7.0",
|
||||||
|
"typescript": "^5.3.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"dotenv": "^16.3.1",
|
||||||
|
"knex": "^3.1.0",
|
||||||
|
"level": "^8.0.0",
|
||||||
|
"mongoose": "^8.0.4",
|
||||||
|
"pg": "^8.11.3",
|
||||||
|
"prompt-sync": "^4.2.0",
|
||||||
|
"zod": "^3.22.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
db
|
||||||
Vendored
+443
@@ -0,0 +1,443 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import {
|
||||||
|
TableName,
|
||||||
|
TApiKeys,
|
||||||
|
TApiKeysInsert,
|
||||||
|
TApiKeysUpdate,
|
||||||
|
TAuditLogs,
|
||||||
|
TAuditLogsInsert,
|
||||||
|
TAuditLogsUpdate,
|
||||||
|
TAuthTokens,
|
||||||
|
TAuthTokenSessions,
|
||||||
|
TAuthTokenSessionsInsert,
|
||||||
|
TAuthTokenSessionsUpdate,
|
||||||
|
TAuthTokensUpdate,
|
||||||
|
TBackupPrivateKey,
|
||||||
|
TBackupPrivateKeyInsert,
|
||||||
|
TBackupPrivateKeyUpdate,
|
||||||
|
TGitAppInstallSessions,
|
||||||
|
TGitAppInstallSessionsInsert,
|
||||||
|
TGitAppInstallSessionsUpdate,
|
||||||
|
TGitAppOrg,
|
||||||
|
TGitAppOrgInsert,
|
||||||
|
TGitAppOrgUpdate,
|
||||||
|
TIdentities,
|
||||||
|
TIdentitiesInsert,
|
||||||
|
TIdentitiesUpdate,
|
||||||
|
TIdentityAccessTokens,
|
||||||
|
TIdentityAccessTokensInsert,
|
||||||
|
TIdentityAccessTokensUpdate,
|
||||||
|
TIdentityOrgMemberships,
|
||||||
|
TIdentityOrgMembershipsInsert,
|
||||||
|
TIdentityOrgMembershipsUpdate,
|
||||||
|
TIdentityProjectMemberships,
|
||||||
|
TIdentityProjectMembershipsInsert,
|
||||||
|
TIdentityProjectMembershipsUpdate,
|
||||||
|
TIdentityUaClientSecrets,
|
||||||
|
TIdentityUaClientSecretsInsert,
|
||||||
|
TIdentityUaClientSecretsUpdate,
|
||||||
|
TIdentityUniversalAuths,
|
||||||
|
TIdentityUniversalAuthsInsert,
|
||||||
|
TIdentityUniversalAuthsUpdate,
|
||||||
|
TIncidentContacts,
|
||||||
|
TIncidentContactsInsert,
|
||||||
|
TIncidentContactsUpdate,
|
||||||
|
TIntegrationAuths,
|
||||||
|
TIntegrationAuthsInsert,
|
||||||
|
TIntegrationAuthsUpdate,
|
||||||
|
TIntegrations,
|
||||||
|
TIntegrationsInsert,
|
||||||
|
TIntegrationsUpdate,
|
||||||
|
TOrganizations,
|
||||||
|
TOrganizationsInsert,
|
||||||
|
TOrganizationsUpdate,
|
||||||
|
TOrgBots,
|
||||||
|
TOrgBotsInsert,
|
||||||
|
TOrgBotsUpdate,
|
||||||
|
TOrgMemberships,
|
||||||
|
TOrgMembershipsInsert,
|
||||||
|
TOrgMembershipsUpdate,
|
||||||
|
TOrgRoles,
|
||||||
|
TOrgRolesInsert,
|
||||||
|
TOrgRolesUpdate,
|
||||||
|
TProjectBots,
|
||||||
|
TProjectBotsInsert,
|
||||||
|
TProjectBotsUpdate,
|
||||||
|
TProjectEnvironments,
|
||||||
|
TProjectEnvironmentsInsert,
|
||||||
|
TProjectEnvironmentsUpdate,
|
||||||
|
TProjectKeys,
|
||||||
|
TProjectKeysInsert,
|
||||||
|
TProjectKeysUpdate,
|
||||||
|
TProjectMemberships,
|
||||||
|
TProjectMembershipsInsert,
|
||||||
|
TProjectMembershipsUpdate,
|
||||||
|
TProjectRoles,
|
||||||
|
TProjectRolesInsert,
|
||||||
|
TProjectRolesUpdate,
|
||||||
|
TProjects,
|
||||||
|
TProjectsInsert,
|
||||||
|
TProjectsUpdate,
|
||||||
|
TSamlConfigs,
|
||||||
|
TSamlConfigsInsert,
|
||||||
|
TSamlConfigsUpdate,
|
||||||
|
TSapApprovers,
|
||||||
|
TSapApproversInsert,
|
||||||
|
TSapApproversUpdate,
|
||||||
|
TSaRequestSecrets,
|
||||||
|
TSaRequestSecretsInsert,
|
||||||
|
TSaRequestSecretsUpdate,
|
||||||
|
TSaRequestSecretTags,
|
||||||
|
TSaRequestSecretTagsInsert,
|
||||||
|
TSaRequestSecretTagsUpdate,
|
||||||
|
TSarReviewers,
|
||||||
|
TSarReviewersInsert,
|
||||||
|
TSarReviewersUpdate,
|
||||||
|
TSecretApprovalPolicies,
|
||||||
|
TSecretApprovalPoliciesInsert,
|
||||||
|
TSecretApprovalPoliciesUpdate,
|
||||||
|
TSecretApprovalRequests,
|
||||||
|
TSecretApprovalRequestsInsert,
|
||||||
|
TSecretApprovalRequestsUpdate,
|
||||||
|
TSecretBlindIndexes,
|
||||||
|
TSecretBlindIndexesInsert,
|
||||||
|
TSecretBlindIndexesUpdate,
|
||||||
|
TSecretFolders,
|
||||||
|
TSecretFoldersInsert,
|
||||||
|
TSecretFoldersUpdate,
|
||||||
|
TSecretFolderVersions,
|
||||||
|
TSecretFolderVersionsInsert,
|
||||||
|
TSecretFolderVersionsUpdate,
|
||||||
|
TSecretImports,
|
||||||
|
TSecretImportsInsert,
|
||||||
|
TSecretImportsUpdate,
|
||||||
|
TSecretRotationOutputs,
|
||||||
|
TSecretRotationOutputsInsert,
|
||||||
|
TSecretRotationOutputsUpdate,
|
||||||
|
TSecretRotations,
|
||||||
|
TSecretRotationsInsert,
|
||||||
|
TSecretRotationsUpdate,
|
||||||
|
TSecrets,
|
||||||
|
TSecretScanningGitRisks,
|
||||||
|
TSecretScanningGitRisksInsert,
|
||||||
|
TSecretScanningGitRisksUpdate,
|
||||||
|
TSecretsInsert,
|
||||||
|
TSecretSnapshotFolders,
|
||||||
|
TSecretSnapshotFoldersInsert,
|
||||||
|
TSecretSnapshotFoldersUpdate,
|
||||||
|
TSecretSnapshots,
|
||||||
|
TSecretSnapshotSecrets,
|
||||||
|
TSecretSnapshotSecretsInsert,
|
||||||
|
TSecretSnapshotSecretsUpdate,
|
||||||
|
TSecretSnapshotsInsert,
|
||||||
|
TSecretSnapshotsUpdate,
|
||||||
|
TSecretsUpdate,
|
||||||
|
TSecretTagJunction,
|
||||||
|
TSecretTagJunctionInsert,
|
||||||
|
TSecretTagJunctionUpdate,
|
||||||
|
TSecretTags,
|
||||||
|
TSecretTagsInsert,
|
||||||
|
TSecretTagsUpdate,
|
||||||
|
TSecretVersions,
|
||||||
|
TSecretVersionsInsert,
|
||||||
|
TSecretVersionsUpdate,
|
||||||
|
TServiceTokens,
|
||||||
|
TServiceTokensInsert,
|
||||||
|
TServiceTokensUpdate,
|
||||||
|
TSuperAdmin,
|
||||||
|
TSuperAdminInsert,
|
||||||
|
TSuperAdminUpdate,
|
||||||
|
TTrustedIps,
|
||||||
|
TTrustedIpsInsert,
|
||||||
|
TTrustedIpsUpdate,
|
||||||
|
TUserActions,
|
||||||
|
TUserActionsInsert,
|
||||||
|
TUserActionsUpdate,
|
||||||
|
TUserEncryptionKeys,
|
||||||
|
TUserEncryptionKeysInsert,
|
||||||
|
TUserEncryptionKeysUpdate,
|
||||||
|
TUsers,
|
||||||
|
TUsersInsert,
|
||||||
|
TUsersUpdate,
|
||||||
|
TWebhooks,
|
||||||
|
TWebhooksInsert,
|
||||||
|
TWebhooksUpdate,
|
||||||
|
TAuthTokensInsert,
|
||||||
|
} from "../schemas";
|
||||||
|
|
||||||
|
declare module "knex/types/tables" {
|
||||||
|
interface Tables {
|
||||||
|
[TableName.Users]: Knex.CompositeTableType<
|
||||||
|
TUsers,
|
||||||
|
TUsersInsert,
|
||||||
|
TUsersUpdate
|
||||||
|
>;
|
||||||
|
[TableName.UserEncryptionKey]: Knex.CompositeTableType<
|
||||||
|
TUserEncryptionKeys,
|
||||||
|
TUserEncryptionKeysInsert,
|
||||||
|
TUserEncryptionKeysUpdate
|
||||||
|
>;
|
||||||
|
[TableName.AuthTokens]: Knex.CompositeTableType<
|
||||||
|
TAuthTokens,
|
||||||
|
TAuthTokensInsert,
|
||||||
|
TAuthTokensUpdate
|
||||||
|
>;
|
||||||
|
[TableName.AuthTokenSession]: Knex.CompositeTableType<
|
||||||
|
TAuthTokenSessions,
|
||||||
|
TAuthTokenSessionsInsert,
|
||||||
|
TAuthTokenSessionsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.BackupPrivateKey]: Knex.CompositeTableType<
|
||||||
|
TBackupPrivateKey,
|
||||||
|
TBackupPrivateKeyInsert,
|
||||||
|
TBackupPrivateKeyUpdate
|
||||||
|
>;
|
||||||
|
[TableName.Organization]: Knex.CompositeTableType<
|
||||||
|
TOrganizations,
|
||||||
|
TOrganizationsInsert,
|
||||||
|
TOrganizationsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.OrgMembership]: Knex.CompositeTableType<
|
||||||
|
TOrgMemberships,
|
||||||
|
TOrgMembershipsInsert,
|
||||||
|
TOrgMembershipsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.OrgRoles]: Knex.CompositeTableType<
|
||||||
|
TOrgRoles,
|
||||||
|
TOrgRolesInsert,
|
||||||
|
TOrgRolesUpdate
|
||||||
|
>;
|
||||||
|
[TableName.IncidentContact]: Knex.CompositeTableType<
|
||||||
|
TIncidentContacts,
|
||||||
|
TIncidentContactsInsert,
|
||||||
|
TIncidentContactsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.UserAction]: Knex.CompositeTableType<
|
||||||
|
TUserActions,
|
||||||
|
TUserActionsInsert,
|
||||||
|
TUserActionsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.SuperAdmin]: Knex.CompositeTableType<
|
||||||
|
TSuperAdmin,
|
||||||
|
TSuperAdminInsert,
|
||||||
|
TSuperAdminUpdate
|
||||||
|
>;
|
||||||
|
[TableName.ApiKey]: Knex.CompositeTableType<
|
||||||
|
TApiKeys,
|
||||||
|
TApiKeysInsert,
|
||||||
|
TApiKeysUpdate
|
||||||
|
>;
|
||||||
|
[TableName.Project]: Knex.CompositeTableType<
|
||||||
|
TProjects,
|
||||||
|
TProjectsInsert,
|
||||||
|
TProjectsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.ProjectMembership]: Knex.CompositeTableType<
|
||||||
|
TProjectMemberships,
|
||||||
|
TProjectMembershipsInsert,
|
||||||
|
TProjectMembershipsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.Environment]: Knex.CompositeTableType<
|
||||||
|
TProjectEnvironments,
|
||||||
|
TProjectEnvironmentsInsert,
|
||||||
|
TProjectEnvironmentsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.ProjectBot]: Knex.CompositeTableType<
|
||||||
|
TProjectBots,
|
||||||
|
TProjectBotsInsert,
|
||||||
|
TProjectBotsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.ProjectRoles]: Knex.CompositeTableType<
|
||||||
|
TProjectRoles,
|
||||||
|
TProjectRolesInsert,
|
||||||
|
TProjectRolesUpdate
|
||||||
|
>;
|
||||||
|
[TableName.ProjectKeys]: Knex.CompositeTableType<
|
||||||
|
TProjectKeys,
|
||||||
|
TProjectKeysInsert,
|
||||||
|
TProjectKeysUpdate
|
||||||
|
>;
|
||||||
|
[TableName.Secret]: Knex.CompositeTableType<
|
||||||
|
TSecrets,
|
||||||
|
TSecretsInsert,
|
||||||
|
TSecretsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.SecretBlindIndex]: Knex.CompositeTableType<
|
||||||
|
TSecretBlindIndexes,
|
||||||
|
TSecretBlindIndexesInsert,
|
||||||
|
TSecretBlindIndexesUpdate
|
||||||
|
>;
|
||||||
|
[TableName.SecretVersion]: Knex.CompositeTableType<
|
||||||
|
TSecretVersions,
|
||||||
|
TSecretVersionsInsert,
|
||||||
|
TSecretVersionsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.SecretFolder]: Knex.CompositeTableType<
|
||||||
|
TSecretFolders,
|
||||||
|
TSecretFoldersInsert,
|
||||||
|
TSecretFoldersUpdate
|
||||||
|
>;
|
||||||
|
[TableName.SecretFolderVersion]: Knex.CompositeTableType<
|
||||||
|
TSecretFolderVersions,
|
||||||
|
TSecretFolderVersionsInsert,
|
||||||
|
TSecretFolderVersionsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.SecretTag]: Knex.CompositeTableType<
|
||||||
|
TSecretTags,
|
||||||
|
TSecretTagsInsert,
|
||||||
|
TSecretTagsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.SecretImport]: Knex.CompositeTableType<
|
||||||
|
TSecretImports,
|
||||||
|
TSecretImportsInsert,
|
||||||
|
TSecretImportsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.Integration]: Knex.CompositeTableType<
|
||||||
|
TIntegrations,
|
||||||
|
TIntegrationsInsert,
|
||||||
|
TIntegrationsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.Webhook]: Knex.CompositeTableType<
|
||||||
|
TWebhooks,
|
||||||
|
TWebhooksInsert,
|
||||||
|
TWebhooksUpdate
|
||||||
|
>;
|
||||||
|
[TableName.ServiceToken]: Knex.CompositeTableType<
|
||||||
|
TServiceTokens,
|
||||||
|
TServiceTokensInsert,
|
||||||
|
TServiceTokensUpdate
|
||||||
|
>;
|
||||||
|
[TableName.IntegrationAuth]: Knex.CompositeTableType<
|
||||||
|
TIntegrationAuths,
|
||||||
|
TIntegrationAuthsInsert,
|
||||||
|
TIntegrationAuthsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.Identity]: Knex.CompositeTableType<
|
||||||
|
TIdentities,
|
||||||
|
TIdentitiesInsert,
|
||||||
|
TIdentitiesUpdate
|
||||||
|
>;
|
||||||
|
[TableName.IdentityUniversalAuth]: Knex.CompositeTableType<
|
||||||
|
TIdentityUniversalAuths,
|
||||||
|
TIdentityUniversalAuthsInsert,
|
||||||
|
TIdentityUniversalAuthsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.IdentityUaClientSecret]: Knex.CompositeTableType<
|
||||||
|
TIdentityUaClientSecrets,
|
||||||
|
TIdentityUaClientSecretsInsert,
|
||||||
|
TIdentityUaClientSecretsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.IdentityAccessToken]: Knex.CompositeTableType<
|
||||||
|
TIdentityAccessTokens,
|
||||||
|
TIdentityAccessTokensInsert,
|
||||||
|
TIdentityAccessTokensUpdate
|
||||||
|
>;
|
||||||
|
[TableName.IdentityOrgMembership]: Knex.CompositeTableType<
|
||||||
|
TIdentityOrgMemberships,
|
||||||
|
TIdentityOrgMembershipsInsert,
|
||||||
|
TIdentityOrgMembershipsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.IdentityProjectMembership]: Knex.CompositeTableType<
|
||||||
|
TIdentityProjectMemberships,
|
||||||
|
TIdentityProjectMembershipsInsert,
|
||||||
|
TIdentityProjectMembershipsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.SecretApprovalPolicy]: Knex.CompositeTableType<
|
||||||
|
TSecretApprovalPolicies,
|
||||||
|
TSecretApprovalPoliciesInsert,
|
||||||
|
TSecretApprovalPoliciesUpdate
|
||||||
|
>;
|
||||||
|
[TableName.SapApprover]: Knex.CompositeTableType<
|
||||||
|
TSapApprovers,
|
||||||
|
TSapApproversInsert,
|
||||||
|
TSapApproversUpdate
|
||||||
|
>;
|
||||||
|
[TableName.SecretApprovalRequest]: Knex.CompositeTableType<
|
||||||
|
TSecretApprovalRequests,
|
||||||
|
TSecretApprovalRequestsInsert,
|
||||||
|
TSecretApprovalRequestsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.SarReviewer]: Knex.CompositeTableType<
|
||||||
|
TSarReviewers,
|
||||||
|
TSarReviewersInsert,
|
||||||
|
TSarReviewersUpdate
|
||||||
|
>;
|
||||||
|
[TableName.SarSecret]: Knex.CompositeTableType<
|
||||||
|
TSaRequestSecrets,
|
||||||
|
TSaRequestSecretsInsert,
|
||||||
|
TSaRequestSecretsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.SarSecretTag]: Knex.CompositeTableType<
|
||||||
|
TSaRequestSecretTags,
|
||||||
|
TSaRequestSecretTagsInsert,
|
||||||
|
TSaRequestSecretTagsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.SecretRotation]: Knex.CompositeTableType<
|
||||||
|
TSecretRotations,
|
||||||
|
TSecretRotationsInsert,
|
||||||
|
TSecretRotationsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.SecretRotationOutput]: Knex.CompositeTableType<
|
||||||
|
TSecretRotationOutputs,
|
||||||
|
TSecretRotationOutputsInsert,
|
||||||
|
TSecretRotationOutputsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.Snapshot]: Knex.CompositeTableType<
|
||||||
|
TSecretSnapshots,
|
||||||
|
TSecretSnapshotsInsert,
|
||||||
|
TSecretSnapshotsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.SnapshotSecret]: Knex.CompositeTableType<
|
||||||
|
TSecretSnapshotSecrets,
|
||||||
|
TSecretSnapshotSecretsInsert,
|
||||||
|
TSecretSnapshotSecretsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.SnapshotFolder]: Knex.CompositeTableType<
|
||||||
|
TSecretSnapshotFolders,
|
||||||
|
TSecretSnapshotFoldersInsert,
|
||||||
|
TSecretSnapshotFoldersUpdate
|
||||||
|
>;
|
||||||
|
[TableName.SamlConfig]: Knex.CompositeTableType<
|
||||||
|
TSamlConfigs,
|
||||||
|
TSamlConfigsInsert,
|
||||||
|
TSamlConfigsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.OrgBot]: Knex.CompositeTableType<
|
||||||
|
TOrgBots,
|
||||||
|
TOrgBotsInsert,
|
||||||
|
TOrgBotsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.AuditLog]: Knex.CompositeTableType<
|
||||||
|
TAuditLogs,
|
||||||
|
TAuditLogsInsert,
|
||||||
|
TAuditLogsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.GitAppInstallSession]: Knex.CompositeTableType<
|
||||||
|
TGitAppInstallSessions,
|
||||||
|
TGitAppInstallSessionsInsert,
|
||||||
|
TGitAppInstallSessionsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.GitAppOrg]: Knex.CompositeTableType<
|
||||||
|
TGitAppOrg,
|
||||||
|
TGitAppOrgInsert,
|
||||||
|
TGitAppOrgUpdate
|
||||||
|
>;
|
||||||
|
[TableName.SecretScanningGitRisk]: Knex.CompositeTableType<
|
||||||
|
TSecretScanningGitRisks,
|
||||||
|
TSecretScanningGitRisksInsert,
|
||||||
|
TSecretScanningGitRisksUpdate
|
||||||
|
>;
|
||||||
|
[TableName.TrustedIps]: Knex.CompositeTableType<
|
||||||
|
TTrustedIps,
|
||||||
|
TTrustedIpsInsert,
|
||||||
|
TTrustedIpsUpdate
|
||||||
|
>;
|
||||||
|
// Junction tables
|
||||||
|
[TableName.JnSecretTag]: Knex.CompositeTableType<
|
||||||
|
TSecretTagJunction,
|
||||||
|
TSecretTagJunctionInsert,
|
||||||
|
TSecretTagJunctionUpdate
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
import promptSync from "prompt-sync";
|
||||||
|
import mongoose from "mongoose";
|
||||||
|
import dotenv from "dotenv";
|
||||||
|
import knex from "knex";
|
||||||
|
import path from "path";
|
||||||
|
import { Level } from "level";
|
||||||
|
import { IUser, User } from "./models";
|
||||||
|
import { TUsers, TUsersInsert, TableName } from "./schemas";
|
||||||
|
|
||||||
|
const kdb = new Level<string, any>("./db", { valueEncoding: "json" });
|
||||||
|
|
||||||
|
const main = async () => {
|
||||||
|
try {
|
||||||
|
dotenv.config();
|
||||||
|
const prompt = promptSync({ sigint: true });
|
||||||
|
|
||||||
|
let mongodb_url = process.env.MONGO_DB_URL;
|
||||||
|
if (!mongodb_url) {
|
||||||
|
mongodb_url = prompt("Type the mongodb url: ");
|
||||||
|
}
|
||||||
|
console.log("Checking mongoose connection...");
|
||||||
|
await mongoose.connect(mongodb_url);
|
||||||
|
console.log("Connected successfully to mongo");
|
||||||
|
|
||||||
|
let postgres_url = process.env.POSTGRES_DB_URL;
|
||||||
|
if (!postgres_url) {
|
||||||
|
postgres_url = prompt("Type the mongodb url: ");
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Checking postgres connection...");
|
||||||
|
const db = knex({
|
||||||
|
client: "pg",
|
||||||
|
connection: postgres_url,
|
||||||
|
migrations: {
|
||||||
|
directory: path.join(__dirname, "./migrations"),
|
||||||
|
extension: "ts",
|
||||||
|
tableName: "infisical_migrations",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
console.log("Connected successfully to postgres");
|
||||||
|
await db.raw("select 1+1 as result");
|
||||||
|
|
||||||
|
console.log("Executing migration");
|
||||||
|
await db.migrate.latest();
|
||||||
|
|
||||||
|
console.log("Starting to insert users");
|
||||||
|
const users: IUser[] = [];
|
||||||
|
const newUsers: TUsersInsert[] = [];
|
||||||
|
for await (const doc of User.find().cursor({ batchSize: 100 })) {
|
||||||
|
users.push(doc);
|
||||||
|
newUsers.push({
|
||||||
|
firstName: doc.firstName,
|
||||||
|
email: doc.email,
|
||||||
|
devices: doc.devices,
|
||||||
|
lastName: doc.lastName,
|
||||||
|
isAccepted: Boolean(doc.publicKey),
|
||||||
|
superAdmin: doc.superAdmin,
|
||||||
|
authMethods: doc.authMethods,
|
||||||
|
isMfaEnabled: doc.isMfaEnabled,
|
||||||
|
});
|
||||||
|
if (users.length >= 1000) {
|
||||||
|
const newUserIds = await db.transaction(async (tx) => {
|
||||||
|
return await tx
|
||||||
|
.batchInsert<TUsers>(TableName.Users, newUsers)
|
||||||
|
.returning("id");
|
||||||
|
});
|
||||||
|
console.log(newUserIds.length);
|
||||||
|
users.slice(0, users.length);
|
||||||
|
newUsers.slice(0, newUsers.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
process.exit(1);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
main();
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import {
|
||||||
|
createOnUpdateTrigger,
|
||||||
|
createUpdateAtTriggerFunction,
|
||||||
|
dropOnUpdateTrigger,
|
||||||
|
dropUpdatedAtTriggerFunction
|
||||||
|
} from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const isTablePresent = await knex.schema.hasTable(TableName.Users);
|
||||||
|
if (!isTablePresent) {
|
||||||
|
await knex.schema.createTable(TableName.Users, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("email").notNullable();
|
||||||
|
t.specificType("authMethods", "text[]");
|
||||||
|
t.boolean("superAdmin").defaultTo(false);
|
||||||
|
t.string("firstName");
|
||||||
|
t.string("lastName");
|
||||||
|
t.boolean("isAccepted").defaultTo(false);
|
||||||
|
t.boolean("isMfaEnabled").defaultTo(false);
|
||||||
|
t.specificType("mfaMethods", "text[]");
|
||||||
|
t.jsonb("devices");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// this is a one time function
|
||||||
|
await createUpdateAtTriggerFunction(knex);
|
||||||
|
await createOnUpdateTrigger(knex, TableName.Users);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.Users);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.Users);
|
||||||
|
await dropUpdatedAtTriggerFunction(knex);
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const isTablePresent = await knex.schema.hasTable(TableName.UserEncryptionKey);
|
||||||
|
if (!isTablePresent) {
|
||||||
|
await knex.schema.createTable(TableName.UserEncryptionKey, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.text("clientPublicKey");
|
||||||
|
t.text("serverPrivateKey");
|
||||||
|
t.integer("encryptionVersion").defaultTo(2);
|
||||||
|
t.text("protectedKey").notNullable();
|
||||||
|
t.text("protectedKeyIV").notNullable();
|
||||||
|
t.text("protectedKeyTag").notNullable();
|
||||||
|
t.text("publicKey").notNullable();
|
||||||
|
t.text("encryptedPrivateKey").notNullable();
|
||||||
|
t.text("iv").notNullable();
|
||||||
|
t.text("tag").notNullable();
|
||||||
|
t.text("salt").notNullable();
|
||||||
|
t.text("verifier").notNullable();
|
||||||
|
// one to one relationship
|
||||||
|
t.uuid("userId").notNullable().unique();
|
||||||
|
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.UserEncryptionKey);
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const isTablePresent = await knex.schema.hasTable(TableName.AuthTokens);
|
||||||
|
if (!isTablePresent) {
|
||||||
|
await knex.schema.createTable(TableName.AuthTokens, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("type").notNullable();
|
||||||
|
t.string("phoneNumber");
|
||||||
|
t.string("tokenHash").notNullable();
|
||||||
|
t.integer("triesLeft");
|
||||||
|
t.datetime("expiresAt").notNullable();
|
||||||
|
// does not need update trigger we will do it manually
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.uuid("userId");
|
||||||
|
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.AuthTokens);
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const isTablePresent = await knex.schema.hasTable(TableName.AuthTokenSession);
|
||||||
|
if (!isTablePresent) {
|
||||||
|
await knex.schema.createTable(TableName.AuthTokenSession, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("ip").notNullable();
|
||||||
|
t.string("userAgent");
|
||||||
|
t.integer("refreshVersion").notNullable().defaultTo(1);
|
||||||
|
t.integer("accessVersion").notNullable().defaultTo(1);
|
||||||
|
t.datetime("lastUsed").notNullable();
|
||||||
|
// does not need update trigger we will do it manually
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.uuid("userId").notNullable();
|
||||||
|
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// this is a one time function
|
||||||
|
await createOnUpdateTrigger(knex, TableName.AuthTokenSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.AuthTokenSession);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.AuthTokenSession);
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const doesTableExist = await knex.schema.hasTable(TableName.BackupPrivateKey);
|
||||||
|
if (!doesTableExist) {
|
||||||
|
await knex.schema.createTable(TableName.BackupPrivateKey, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.text("encryptedPrivateKey").notNullable();
|
||||||
|
t.text("iv").notNullable();
|
||||||
|
t.text("tag").notNullable();
|
||||||
|
t.string("algorithm").notNullable();
|
||||||
|
t.string("keyEncoding").notNullable();
|
||||||
|
t.text("salt").notNullable();
|
||||||
|
t.text("verifier").notNullable();
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.uuid("userId").notNullable().unique();
|
||||||
|
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.BackupPrivateKey);
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const isTablePresent = await knex.schema.hasTable(TableName.Organization);
|
||||||
|
if (!isTablePresent) {
|
||||||
|
await knex.schema.createTable(TableName.Organization, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("name").notNullable();
|
||||||
|
t.string("customerId");
|
||||||
|
// does not need update trigger we will do it manually
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
await knex.schema.alterTable(TableName.AuthTokens, (t) => {
|
||||||
|
t.uuid("orgId");
|
||||||
|
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// this is a one time function
|
||||||
|
await createOnUpdateTrigger(knex, TableName.Organization);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
if (await knex.schema.hasColumn(TableName.AuthTokens, "orgId")) {
|
||||||
|
await knex.schema.alterTable(TableName.AuthTokens, (t) => {
|
||||||
|
t.dropColumn("orgId");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await knex.schema.dropTableIfExists(TableName.Organization);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.Organization);
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { OrgMembershipStatus } from "../schemas/models";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const isOrgRolePresent = await knex.schema.hasTable(TableName.OrgRoles);
|
||||||
|
if (!isOrgRolePresent) {
|
||||||
|
await knex.schema.createTable(TableName.OrgRoles, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("name").notNullable();
|
||||||
|
t.string("description");
|
||||||
|
t.string("slug").notNullable();
|
||||||
|
t.jsonb("permissions").notNullable();
|
||||||
|
// does not need update trigger we will do it manually
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.uuid("orgId").notNullable();
|
||||||
|
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const isOrgTablePresent = await knex.schema.hasTable(TableName.OrgMembership);
|
||||||
|
if (!isOrgTablePresent) {
|
||||||
|
await knex.schema.createTable(TableName.OrgMembership, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("role").notNullable();
|
||||||
|
t.string("status").notNullable().defaultTo(OrgMembershipStatus.Invited);
|
||||||
|
t.string("inviteEmail");
|
||||||
|
// does not need update trigger we will do it manually
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.uuid("userId");
|
||||||
|
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||||
|
t.uuid("orgId").notNullable();
|
||||||
|
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
|
t.uuid("roleId");
|
||||||
|
t.foreign("roleId").references("id").inTable(TableName.OrgRoles);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// this is a one time function
|
||||||
|
await createOnUpdateTrigger(knex, TableName.OrgMembership);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.OrgMembership);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.OrgRoles);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.OrgMembership);
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const isTablePresent = await knex.schema.hasTable(TableName.IncidentContact);
|
||||||
|
if (!isTablePresent) {
|
||||||
|
await knex.schema.createTable(TableName.IncidentContact, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("email").notNullable();
|
||||||
|
// does not need update trigger we will do it manually
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.uuid("orgId").notNullable();
|
||||||
|
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// this is a one time function
|
||||||
|
await createOnUpdateTrigger(knex, TableName.IncidentContact);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.IncidentContact);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.IncidentContact);
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const isTablePresent = await knex.schema.hasTable(TableName.UserAction);
|
||||||
|
if (!isTablePresent) {
|
||||||
|
await knex.schema.createTable(TableName.UserAction, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("action").notNullable();
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.uuid("userId").notNullable();
|
||||||
|
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.UserAction);
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const isTablePresent = await knex.schema.hasTable(TableName.SuperAdmin);
|
||||||
|
if (!isTablePresent) {
|
||||||
|
await knex.schema.createTable(TableName.SuperAdmin, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.boolean("initialized").defaultTo(false);
|
||||||
|
t.boolean("allowSignUp").defaultTo(true);
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// this is a one time function
|
||||||
|
await createOnUpdateTrigger(knex, TableName.SuperAdmin);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SuperAdmin);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.SuperAdmin);
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const isTablePresent = await knex.schema.hasTable(TableName.ApiKey);
|
||||||
|
if (!isTablePresent) {
|
||||||
|
await knex.schema.createTable(TableName.ApiKey, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("name").notNullable();
|
||||||
|
t.datetime("lastUsed");
|
||||||
|
t.datetime("expiresAt");
|
||||||
|
t.string("secretHash").notNullable();
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.uuid("userId").notNullable();
|
||||||
|
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.ApiKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.ApiKey);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.ApiKey);
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.Project))) {
|
||||||
|
await knex.schema.createTable(TableName.Project, (t) => {
|
||||||
|
t.string("id", 36).primary().defaultTo(knex.fn.uuid());
|
||||||
|
t.string("name").notNullable();
|
||||||
|
t.boolean("autoCapitalization").defaultTo(true);
|
||||||
|
t.uuid("orgId").notNullable();
|
||||||
|
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.Project);
|
||||||
|
// environments
|
||||||
|
if (!(await knex.schema.hasTable(TableName.Environment))) {
|
||||||
|
await knex.schema.createTable(TableName.Environment, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("name").notNullable();
|
||||||
|
t.string("slug").notNullable();
|
||||||
|
t.integer("position").notNullable();
|
||||||
|
t.string("projectId").notNullable();
|
||||||
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
|
// this will ensure ever env has its position
|
||||||
|
t.unique(["projectId", "position"], {
|
||||||
|
indexName: "env_pos_composite_uniqe",
|
||||||
|
deferrable: "deferred"
|
||||||
|
});
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// project key
|
||||||
|
if (!(await knex.schema.hasTable(TableName.ProjectKeys))) {
|
||||||
|
await knex.schema.createTable(TableName.ProjectKeys, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.text("encryptedKey").notNullable();
|
||||||
|
t.text("nonce").notNullable();
|
||||||
|
t.uuid("receiverId").notNullable();
|
||||||
|
t.foreign("receiverId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||||
|
t.uuid("senderId");
|
||||||
|
// if sender is deleted just don't do anything to this record
|
||||||
|
t.foreign("senderId").references("id").inTable(TableName.Users).onDelete("SET NULL");
|
||||||
|
t.string("projectId").notNullable();
|
||||||
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.ProjectKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.Environment);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.ProjectKeys);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.Project);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.ProjectKeys);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.Project);
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.ProjectRoles))) {
|
||||||
|
await knex.schema.createTable(TableName.ProjectRoles, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("name").notNullable();
|
||||||
|
t.string("description");
|
||||||
|
t.string("slug").notNullable();
|
||||||
|
t.jsonb("permissions").notNullable();
|
||||||
|
// does not need update trigger we will do it manually
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.string("projectId").notNullable();
|
||||||
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.ProjectMembership))) {
|
||||||
|
await knex.schema.createTable(TableName.ProjectMembership, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("role").notNullable();
|
||||||
|
// does not need update trigger we will do it manually
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.uuid("userId").notNullable();
|
||||||
|
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||||
|
t.string("projectId").notNullable();
|
||||||
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
|
// until role is changed/removed the role should not deleted
|
||||||
|
t.uuid("roleId");
|
||||||
|
t.foreign("roleId").references("id").inTable(TableName.ProjectRoles);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.ProjectMembership);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.ProjectMembership);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.ProjectRoles);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.ProjectMembership);
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SecretFolder))) {
|
||||||
|
await knex.schema.createTable(TableName.SecretFolder, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("name").notNullable();
|
||||||
|
t.integer("version").defaultTo(1);
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.uuid("envId").notNullable();
|
||||||
|
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||||
|
t.uuid("parentId");
|
||||||
|
t.foreign("parentId").references("id").inTable(TableName.SecretFolder).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.SecretFolder);
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SecretFolderVersion))) {
|
||||||
|
await knex.schema.createTable(TableName.SecretFolderVersion, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("name").notNullable();
|
||||||
|
t.integer("version").defaultTo(1);
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.uuid("envId").notNullable();
|
||||||
|
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||||
|
t.uuid("folderId").notNullable();
|
||||||
|
// t.foreign("folderId").references("id").inTable(TableName.SecretFolder).onDelete("SET NULL");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await createOnUpdateTrigger(knex, TableName.SecretFolderVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SecretFolderVersion);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SecretFolder);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.SecretFolder);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.SecretFolderVersion);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SecretImport))) {
|
||||||
|
await knex.schema.createTable(TableName.SecretImport, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.integer("version").defaultTo(1);
|
||||||
|
t.string("importPath").notNullable();
|
||||||
|
t.uuid("importEnv").notNullable();
|
||||||
|
t.foreign("importEnv").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||||
|
t.integer("position").notNullable();
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.uuid("folderId").notNullable();
|
||||||
|
t.foreign("folderId").references("id").inTable(TableName.SecretFolder).onDelete("CASCADE");
|
||||||
|
t.unique(["folderId", "position"], {
|
||||||
|
indexName: "import_pos_composite_uniqe",
|
||||||
|
deferrable: "deferred"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.SecretImport);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SecretImport);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.SecretImport);
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SecretTag))) {
|
||||||
|
await knex.schema.createTable(TableName.SecretTag, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("name").notNullable();
|
||||||
|
t.string("slug").notNullable();
|
||||||
|
t.string("color");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.uuid("createdBy");
|
||||||
|
t.foreign("createdBy").references("id").inTable(TableName.Users).onDelete("SET NULL");
|
||||||
|
t.string("projectId").notNullable();
|
||||||
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.SecretTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SecretTag);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.SecretTag);
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { SecretEncryptionAlgo, SecretKeyEncoding, SecretType, TableName } from "../schemas";
|
||||||
|
import { createJunctionTable, createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SecretBlindIndex))) {
|
||||||
|
await knex.schema.createTable(TableName.SecretBlindIndex, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.text("encryptedSaltCipherText").notNullable();
|
||||||
|
t.text("saltIV").notNullable();
|
||||||
|
t.text("saltTag").notNullable();
|
||||||
|
t.string("algorithm").notNullable().defaultTo(SecretEncryptionAlgo.AES_256_GCM);
|
||||||
|
t.string("keyEncoding").notNullable().defaultTo(SecretKeyEncoding.UTF8);
|
||||||
|
t.string("projectId").notNullable().unique();
|
||||||
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.SecretBlindIndex);
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.Secret))) {
|
||||||
|
await knex.schema.createTable(TableName.Secret, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.integer("version").defaultTo(1).notNullable();
|
||||||
|
t.string("type").notNullable().defaultTo(SecretType.Shared);
|
||||||
|
// t.text("secretKeyHash").notNullable();
|
||||||
|
// t.text("secretValueHash");
|
||||||
|
// t.text("secretCommentHash");
|
||||||
|
t.text("secretBlindIndex").notNullable();
|
||||||
|
t.text("secretKeyCiphertext").notNullable();
|
||||||
|
t.text("secretKeyIV").notNullable();
|
||||||
|
t.text("secretKeyTag").notNullable();
|
||||||
|
t.text("secretValueCiphertext").notNullable();
|
||||||
|
t.text("secretValueIV").notNullable(); // symmetric encryption
|
||||||
|
t.text("secretValueTag").notNullable();
|
||||||
|
t.text("secretCommentCiphertext");
|
||||||
|
t.text("secretCommentIV");
|
||||||
|
t.text("secretCommentTag");
|
||||||
|
t.string("secretReminderNote");
|
||||||
|
t.integer("secretReminderRepeatDays");
|
||||||
|
t.boolean("skipMultilineEncoding").defaultTo(false);
|
||||||
|
t.string("algorithm").notNullable().defaultTo(SecretEncryptionAlgo.AES_256_GCM);
|
||||||
|
t.string("keyEncoding").notNullable().defaultTo(SecretKeyEncoding.UTF8);
|
||||||
|
t.jsonb("metadata");
|
||||||
|
t.uuid("userId");
|
||||||
|
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||||
|
t.uuid("folderId").notNullable();
|
||||||
|
t.foreign("folderId").references("id").inTable(TableName.SecretFolder).onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.Secret);
|
||||||
|
// many to many relation between tags
|
||||||
|
await createJunctionTable(knex, TableName.JnSecretTag, TableName.Secret, TableName.SecretTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SecretBlindIndex);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.SecretBlindIndex);
|
||||||
|
|
||||||
|
await knex.schema.dropTableIfExists(TableName.JnSecretTag);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.Secret);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.Secret);
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { SecretEncryptionAlgo, SecretKeyEncoding, SecretType, TableName } from "../schemas";
|
||||||
|
import { createJunctionTable, createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SecretVersion))) {
|
||||||
|
await knex.schema.createTable(TableName.SecretVersion, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.integer("version").defaultTo(1).notNullable();
|
||||||
|
t.string("type").notNullable().defaultTo(SecretType.Shared);
|
||||||
|
t.text("secretBlindIndex").notNullable();
|
||||||
|
t.text("secretKeyCiphertext").notNullable();
|
||||||
|
t.text("secretKeyIV").notNullable();
|
||||||
|
t.text("secretKeyTag").notNullable();
|
||||||
|
t.text("secretValueCiphertext").notNullable();
|
||||||
|
t.text("secretValueIV").notNullable(); // symmetric encryption
|
||||||
|
t.text("secretValueTag").notNullable();
|
||||||
|
t.text("secretCommentCiphertext");
|
||||||
|
t.text("secretCommentIV");
|
||||||
|
t.text("secretCommentTag");
|
||||||
|
t.string("secretReminderNote");
|
||||||
|
t.integer("secretReminderRepeatDays");
|
||||||
|
t.boolean("skipMultilineEncoding").defaultTo(false);
|
||||||
|
t.string("algorithm").notNullable().defaultTo(SecretEncryptionAlgo.AES_256_GCM);
|
||||||
|
t.string("keyEncoding").notNullable().defaultTo(SecretKeyEncoding.UTF8);
|
||||||
|
t.jsonb("metadata");
|
||||||
|
// to avoid orphan rows
|
||||||
|
t.uuid("envId");
|
||||||
|
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||||
|
t.uuid("secretId").notNullable();
|
||||||
|
t.uuid("folderId").notNullable();
|
||||||
|
// t.foreign("secretId").references("id").inTable(TableName.Secret).onDelete("SET NULL");
|
||||||
|
t.uuid("userId");
|
||||||
|
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.SecretVersion);
|
||||||
|
// many to many relation between tags
|
||||||
|
await createJunctionTable(
|
||||||
|
knex,
|
||||||
|
TableName.JnSecretVersionTag,
|
||||||
|
TableName.SecretVersion,
|
||||||
|
TableName.SecretTag
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.JnSecretVersionTag);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SecretVersion);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.SecretVersion);
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.ProjectBot))) {
|
||||||
|
await knex.schema.createTable(TableName.ProjectBot, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("name").notNullable();
|
||||||
|
t.boolean("isActive").defaultTo(false).notNullable();
|
||||||
|
t.text("encryptedPrivateKey").notNullable();
|
||||||
|
t.text("publicKey").notNullable();
|
||||||
|
t.text("iv").notNullable();
|
||||||
|
t.text("tag").notNullable();
|
||||||
|
t.string("algorithm").notNullable();
|
||||||
|
t.string("keyEncoding").notNullable();
|
||||||
|
t.text("encryptedProjectKey");
|
||||||
|
t.text("encryptedProjectKeyNonce");
|
||||||
|
// one to one relationship
|
||||||
|
t.string("projectId").notNullable().unique();
|
||||||
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
|
t.uuid("senderId");
|
||||||
|
t.foreign("senderId").references("id").inTable(TableName.Users).onDelete("SET NULL");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await createOnUpdateTrigger(knex, TableName.ProjectBot);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.ProjectBot);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.ProjectBot);
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.IntegrationAuth))) {
|
||||||
|
await knex.schema.createTable(TableName.IntegrationAuth, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("integration").notNullable();
|
||||||
|
t.string("teamId"); // vercel-specific
|
||||||
|
t.string("url"); // for self hosted
|
||||||
|
t.string("namespace"); // hashicorp specific
|
||||||
|
t.string("accountId"); // netlify
|
||||||
|
t.string("refreshCiphertext");
|
||||||
|
t.string("refreshIV");
|
||||||
|
t.string("refreshTag");
|
||||||
|
t.string("accessIdCiphertext");
|
||||||
|
t.string("accessIdIV");
|
||||||
|
t.string("accessIdTag");
|
||||||
|
t.string("accessCiphertext");
|
||||||
|
t.string("accessIV");
|
||||||
|
t.string("accessTag");
|
||||||
|
t.datetime("accessExpiresAt");
|
||||||
|
t.jsonb("metadata");
|
||||||
|
t.string("algorithm").notNullable();
|
||||||
|
t.string("keyEncoding").notNullable();
|
||||||
|
t.string("projectId").notNullable();
|
||||||
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.IntegrationAuth);
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.Integration))) {
|
||||||
|
await knex.schema.createTable(TableName.Integration, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.boolean("isActive").notNullable();
|
||||||
|
t.string("url"); // self hosted
|
||||||
|
t.string("app"); // name of app in provider
|
||||||
|
t.string("appId");
|
||||||
|
t.string("targetEnvironment");
|
||||||
|
t.string("targetEnvironmentId");
|
||||||
|
t.string("targetService"); // railway - qovery specific
|
||||||
|
t.string("targetServiceId");
|
||||||
|
t.string("owner"); // github specific
|
||||||
|
t.string("path"); // aws parameter store / vercel preview branch
|
||||||
|
t.string("region"); // aws
|
||||||
|
t.string("scope"); // qovery specific scope
|
||||||
|
t.string("integration").notNullable();
|
||||||
|
t.jsonb("metadata");
|
||||||
|
t.uuid("integrationAuthId").notNullable();
|
||||||
|
t.foreign("integrationAuthId")
|
||||||
|
.references("id")
|
||||||
|
.inTable(TableName.IntegrationAuth)
|
||||||
|
.onDelete("CASCADE");
|
||||||
|
t.uuid("envId").notNullable();
|
||||||
|
t.string("secretPath").defaultTo("/").notNullable();
|
||||||
|
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.Integration);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.Integration);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.IntegrationAuth);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.IntegrationAuth);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.Integration);
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.ServiceToken))) {
|
||||||
|
await knex.schema.createTable(TableName.ServiceToken, (t) => {
|
||||||
|
t.string("id", 36).primary().defaultTo(knex.fn.uuid());
|
||||||
|
t.string("name").notNullable();
|
||||||
|
t.jsonb("scopes").notNullable();
|
||||||
|
t.specificType("permissions", "text[]").notNullable();
|
||||||
|
t.datetime("lastUsed");
|
||||||
|
t.datetime("expiresAt");
|
||||||
|
t.text("secretHash").notNullable();
|
||||||
|
t.text("encryptedKey");
|
||||||
|
t.text("iv");
|
||||||
|
t.text("tag");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
// user is old one
|
||||||
|
t.string("createdBy").notNullable();
|
||||||
|
t.string("projectId").notNullable();
|
||||||
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.ServiceToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.ServiceToken);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.ServiceToken);
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.Webhook))) {
|
||||||
|
await knex.schema.createTable(TableName.Webhook, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("secretPath").notNullable().defaultTo("/");
|
||||||
|
t.string("url").notNullable();
|
||||||
|
t.string("lastStatus");
|
||||||
|
t.text("lastRunErrorMessage");
|
||||||
|
t.boolean("isDisabled").defaultTo(false).notNullable();
|
||||||
|
// webhook signature
|
||||||
|
t.text("encryptedSecretKey");
|
||||||
|
t.text("iv");
|
||||||
|
t.text("tag");
|
||||||
|
t.string("algorithm");
|
||||||
|
t.string("keyEncoding");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.uuid("envId").notNullable();
|
||||||
|
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.Webhook);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.Webhook);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.Webhook);
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.Identity))) {
|
||||||
|
await knex.schema.createTable(TableName.Identity, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("name").notNullable();
|
||||||
|
t.string("authMethod");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.Identity);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.Identity);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.Identity);
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.IdentityUniversalAuth))) {
|
||||||
|
await knex.schema.createTable(TableName.IdentityUniversalAuth, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("clientId").notNullable();
|
||||||
|
t.integer("accessTokenTTL").defaultTo(7200).notNullable();
|
||||||
|
t.integer("accessTokenMaxTTL").defaultTo(7200).notNullable();
|
||||||
|
t.integer("accessTokenNumUsesLimit").defaultTo(0).notNullable();
|
||||||
|
t.jsonb("clientSecretTrustedIps").notNullable();
|
||||||
|
t.jsonb("accessTokenTrustedIps").notNullable();
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.uuid("identityId").notNullable().unique();
|
||||||
|
t.foreign("identityId").references("id").inTable(TableName.Identity).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!(await knex.schema.hasTable(TableName.IdentityUaClientSecret))) {
|
||||||
|
await knex.schema.createTable(TableName.IdentityUaClientSecret, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("description").notNullable();
|
||||||
|
t.string("clientSecretPrefix").notNullable();
|
||||||
|
t.string("clientSecretHash").notNullable();
|
||||||
|
t.datetime("clientSecretLastUsedAt");
|
||||||
|
t.integer("clientSecretNumUses").defaultTo(0).notNullable();
|
||||||
|
t.integer("clientSecretNumUsesLimit").defaultTo(0).notNullable();
|
||||||
|
t.integer("clientSecretTTL").defaultTo(0).notNullable();
|
||||||
|
t.boolean("isClientSecretRevoked").defaultTo(false).notNullable();
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.uuid("identityUAId").notNullable();
|
||||||
|
t.foreign("identityUAId")
|
||||||
|
.references("id")
|
||||||
|
.inTable(TableName.IdentityUniversalAuth)
|
||||||
|
.onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.IdentityUniversalAuth);
|
||||||
|
await createOnUpdateTrigger(knex, TableName.IdentityUaClientSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.IdentityUaClientSecret);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.IdentityUniversalAuth);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.IdentityUaClientSecret);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.IdentityUniversalAuth);
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.IdentityAccessToken))) {
|
||||||
|
await knex.schema.createTable(TableName.IdentityAccessToken, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("authType").notNullable();
|
||||||
|
t.integer("accessTokenTTL").defaultTo(2592000).notNullable(); // 30 days second
|
||||||
|
t.integer("accessTokenMaxTTL").defaultTo(2592000).notNullable();
|
||||||
|
t.integer("accessTokenNumUses").defaultTo(0).notNullable();
|
||||||
|
t.integer("accessTokenNumUsesLimit").defaultTo(0).notNullable();
|
||||||
|
t.datetime("accessTokenLastUsedAt");
|
||||||
|
t.datetime("accessTokenLastRenewedAt");
|
||||||
|
t.boolean("isAccessTokenRevoked").defaultTo(false).notNullable();
|
||||||
|
t.uuid("identityUAClientSecretId");
|
||||||
|
t.foreign("identityUAClientSecretId")
|
||||||
|
.references("id")
|
||||||
|
.inTable(TableName.IdentityUaClientSecret)
|
||||||
|
.onDelete("CASCADE");
|
||||||
|
t.uuid("identityId").notNullable();
|
||||||
|
t.foreign("identityId").references("id").inTable(TableName.Identity).onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await createOnUpdateTrigger(knex, TableName.IdentityAccessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.IdentityAccessToken);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.IdentityAccessToken);
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.IdentityOrgMembership))) {
|
||||||
|
await knex.schema.createTable(TableName.IdentityOrgMembership, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("role").notNullable();
|
||||||
|
t.uuid("roleId");
|
||||||
|
t.foreign("roleId").references("id").inTable(TableName.OrgRoles);
|
||||||
|
t.uuid("orgId").notNullable();
|
||||||
|
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.uuid("identityId").notNullable();
|
||||||
|
t.foreign("identityId").references("id").inTable(TableName.Identity).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.IdentityOrgMembership);
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.IdentityProjectMembership))) {
|
||||||
|
await knex.schema.createTable(TableName.IdentityProjectMembership, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("role").notNullable();
|
||||||
|
t.uuid("roleId");
|
||||||
|
t.foreign("roleId").references("id").inTable(TableName.ProjectRoles);
|
||||||
|
t.string("projectId").notNullable();
|
||||||
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
|
t.uuid("identityId").notNullable();
|
||||||
|
t.foreign("identityId").references("id").inTable(TableName.Identity).onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.IdentityProjectMembership);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.IdentityOrgMembership);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.IdentityProjectMembership);
|
||||||
|
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.IdentityProjectMembership);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.IdentityOrgMembership);
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SecretApprovalPolicy))) {
|
||||||
|
await knex.schema.createTable(TableName.SecretApprovalPolicy, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("name").notNullable();
|
||||||
|
t.string("secretPath");
|
||||||
|
t.integer("approvals").defaultTo(1).notNullable();
|
||||||
|
t.uuid("envId").notNullable();
|
||||||
|
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.SecretApprovalPolicy);
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SapApprover))) {
|
||||||
|
await knex.schema.createTable(TableName.SapApprover, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.uuid("approverId").notNullable();
|
||||||
|
t.foreign("approverId")
|
||||||
|
.references("id")
|
||||||
|
.inTable(TableName.ProjectMembership)
|
||||||
|
.onDelete("CASCADE");
|
||||||
|
t.uuid("policyId").notNullable();
|
||||||
|
t.foreign("policyId")
|
||||||
|
.references("id")
|
||||||
|
.inTable(TableName.SecretApprovalPolicy)
|
||||||
|
.onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await createOnUpdateTrigger(knex, TableName.SapApprover);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SapApprover);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SecretApprovalPolicy);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.SapApprover);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.SecretApprovalPolicy);
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { SecretEncryptionAlgo, SecretKeyEncoding, TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SecretApprovalRequest))) {
|
||||||
|
await knex.schema.createTable(TableName.SecretApprovalRequest, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.uuid("policyId").notNullable();
|
||||||
|
t.boolean("hasMerged").defaultTo(false).notNullable();
|
||||||
|
t.string("status").defaultTo("open").notNullable();
|
||||||
|
t.jsonb("conflicts");
|
||||||
|
t.foreign("policyId")
|
||||||
|
.references("id")
|
||||||
|
.inTable(TableName.SecretApprovalPolicy)
|
||||||
|
.onDelete("CASCADE");
|
||||||
|
t.string("slug").notNullable();
|
||||||
|
t.uuid("folderId").notNullable();
|
||||||
|
t.foreign("folderId").references("id").inTable(TableName.SecretFolder).onDelete("CASCADE");
|
||||||
|
t.uuid("statusChangeBy");
|
||||||
|
t.foreign("statusChangeBy")
|
||||||
|
.references("id")
|
||||||
|
.inTable(TableName.ProjectMembership)
|
||||||
|
.onDelete("CASCADE");
|
||||||
|
t.uuid("committerId").notNullable();
|
||||||
|
t.foreign("committerId")
|
||||||
|
.references("id")
|
||||||
|
.inTable(TableName.ProjectMembership)
|
||||||
|
.onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.SecretApprovalRequest);
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SarReviewer))) {
|
||||||
|
await knex.schema.createTable(TableName.SarReviewer, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.uuid("member").notNullable();
|
||||||
|
t.foreign("member").references("id").inTable(TableName.ProjectMembership).onDelete("CASCADE");
|
||||||
|
t.string("status").notNullable();
|
||||||
|
t.uuid("requestId").notNullable();
|
||||||
|
t.foreign("requestId")
|
||||||
|
.references("id")
|
||||||
|
.inTable(TableName.SecretApprovalRequest)
|
||||||
|
.onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.SarReviewer);
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SarSecret))) {
|
||||||
|
await knex.schema.createTable(TableName.SarSecret, (t) => {
|
||||||
|
// everything related to secret
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.integer("version").defaultTo(1);
|
||||||
|
t.text("secretBlindIndex").notNullable();
|
||||||
|
t.text("secretKeyCiphertext").notNullable();
|
||||||
|
t.text("secretKeyIV").notNullable();
|
||||||
|
t.text("secretKeyTag").notNullable();
|
||||||
|
t.text("secretValueCiphertext").notNullable();
|
||||||
|
t.text("secretValueIV").notNullable(); // symmetric encryption
|
||||||
|
t.text("secretValueTag").notNullable();
|
||||||
|
t.text("secretCommentCiphertext");
|
||||||
|
t.text("secretCommentIV");
|
||||||
|
t.text("secretCommentTag");
|
||||||
|
t.string("secretReminderNote");
|
||||||
|
t.integer("secretReminderRepeatDays");
|
||||||
|
t.boolean("skipMultilineEncoding").defaultTo(false);
|
||||||
|
t.string("algorithm").notNullable().defaultTo(SecretEncryptionAlgo.AES_256_GCM);
|
||||||
|
t.string("keyEncoding").notNullable().defaultTo(SecretKeyEncoding.UTF8);
|
||||||
|
t.jsonb("metadata");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
// commit details
|
||||||
|
t.uuid("requestId").notNullable();
|
||||||
|
t.foreign("requestId")
|
||||||
|
.references("id")
|
||||||
|
.inTable(TableName.SecretApprovalRequest)
|
||||||
|
.onDelete("CASCADE");
|
||||||
|
t.string("op").notNullable();
|
||||||
|
t.uuid("secretId");
|
||||||
|
t.foreign("secretId").references("id").inTable(TableName.Secret).onDelete("SET NULL");
|
||||||
|
t.uuid("secretVersion");
|
||||||
|
t.foreign("secretVersion")
|
||||||
|
.references("id")
|
||||||
|
.inTable(TableName.SecretVersion)
|
||||||
|
.onDelete("SET NULL");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.SarSecret);
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SarSecretTag))) {
|
||||||
|
await knex.schema.createTable(TableName.SarSecretTag, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.uuid("secretId").notNullable();
|
||||||
|
t.foreign("secretId").references("id").inTable(TableName.SarSecret).onDelete("CASCADE");
|
||||||
|
t.uuid("tagId").notNullable();
|
||||||
|
t.foreign("tagId").references("id").inTable(TableName.SecretTag).onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.SarSecretTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SarSecretTag);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SarSecret);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SarReviewer);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SecretApprovalRequest);
|
||||||
|
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.SarSecretTag);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.SarSecret);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.SarReviewer);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.SecretApprovalRequest);
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SecretRotation))) {
|
||||||
|
await knex.schema.createTable(TableName.SecretRotation, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("provider").notNullable();
|
||||||
|
t.string("secretPath").notNullable();
|
||||||
|
t.integer("interval").notNullable();
|
||||||
|
t.datetime("lastRotatedAt");
|
||||||
|
t.string("status");
|
||||||
|
t.text("statusMessage");
|
||||||
|
t.text("encryptedData");
|
||||||
|
t.text("encryptedDataIV");
|
||||||
|
t.text("encryptedDataTag");
|
||||||
|
t.string("algorithm");
|
||||||
|
t.string("keyEncoding");
|
||||||
|
t.uuid("envId").notNullable();
|
||||||
|
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.SecretRotation);
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SecretRotationOutput))) {
|
||||||
|
await knex.schema.createTable(TableName.SecretRotationOutput, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("key").notNullable();
|
||||||
|
t.uuid("secretId").notNullable();
|
||||||
|
t.foreign("secretId").references("id").inTable(TableName.Secret).onDelete("CASCADE");
|
||||||
|
t.uuid("rotationId").notNullable();
|
||||||
|
t.foreign("rotationId")
|
||||||
|
.references("id")
|
||||||
|
.inTable(TableName.SecretRotation)
|
||||||
|
.onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SecretRotationOutput);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SecretRotation);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.SecretRotation);
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.Snapshot))) {
|
||||||
|
await knex.schema.createTable(TableName.Snapshot, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.uuid("envId").notNullable();
|
||||||
|
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||||
|
// this is not a relation kept like that
|
||||||
|
// this ensure snapshot are not lost when folder gets deleted and rolled back
|
||||||
|
t.uuid("folderId").notNullable();
|
||||||
|
t.uuid("parentFolderId");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.Snapshot);
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SnapshotSecret))) {
|
||||||
|
await knex.schema.createTable(TableName.SnapshotSecret, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.uuid("envId").notNullable();
|
||||||
|
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||||
|
// not a relation kept like that to keep it when rolled back
|
||||||
|
t.uuid("secretVersionId").notNullable();
|
||||||
|
t.foreign("secretVersionId")
|
||||||
|
.references("id")
|
||||||
|
.inTable(TableName.SecretVersion)
|
||||||
|
.onDelete("CASCADE");
|
||||||
|
t.uuid("snapshotId").notNullable();
|
||||||
|
t.foreign("snapshotId").references("id").inTable(TableName.Snapshot).onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SnapshotFolder))) {
|
||||||
|
await knex.schema.createTable(TableName.SnapshotFolder, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.uuid("envId").notNullable();
|
||||||
|
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||||
|
// not a relation kept like that to keep it when rolled back
|
||||||
|
t.uuid("folderVersionId").notNullable();
|
||||||
|
t.foreign("folderVersionId")
|
||||||
|
.references("id")
|
||||||
|
.inTable(TableName.SecretFolderVersion)
|
||||||
|
.onDelete("CASCADE");
|
||||||
|
t.uuid("snapshotId").notNullable();
|
||||||
|
t.foreign("snapshotId").references("id").inTable(TableName.Snapshot).onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SnapshotSecret);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SnapshotFolder);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.Snapshot);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.Snapshot);
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SamlConfig))) {
|
||||||
|
await knex.schema.createTable(TableName.SamlConfig, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("authProvider").notNullable();
|
||||||
|
t.boolean("isActive").notNullable();
|
||||||
|
t.string("encryptedEntryPoint");
|
||||||
|
t.string("entryPointIV");
|
||||||
|
t.string("entryPointTag");
|
||||||
|
t.string("encryptedIssuer");
|
||||||
|
t.string("issuerTag");
|
||||||
|
t.string("issuerIV");
|
||||||
|
t.text("encryptedCert");
|
||||||
|
t.string("certIV");
|
||||||
|
t.string("certTag");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.uuid("orgId").notNullable().unique();
|
||||||
|
t.foreign("orgId").references("id").inTable(TableName.Organization);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await createOnUpdateTrigger(knex, TableName.SamlConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SamlConfig);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.SamlConfig);
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.OrgBot))) {
|
||||||
|
await knex.schema.createTable(TableName.OrgBot, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("name").notNullable();
|
||||||
|
t.text("publicKey").notNullable();
|
||||||
|
t.text("encryptedSymmetricKey").notNullable();
|
||||||
|
t.text("symmetricKeyIV").notNullable();
|
||||||
|
t.text("symmetricKeyTag").notNullable();
|
||||||
|
t.string("symmetricKeyAlgorithm").notNullable();
|
||||||
|
t.string("symmetricKeyKeyEncoding").notNullable();
|
||||||
|
t.text("encryptedPrivateKey").notNullable();
|
||||||
|
t.text("privateKeyIV").notNullable();
|
||||||
|
t.text("privateKeyTag").notNullable();
|
||||||
|
t.string("privateKeyAlgorithm").notNullable();
|
||||||
|
t.string("privateKeyKeyEncoding").notNullable();
|
||||||
|
// one to one relationship
|
||||||
|
t.uuid("orgId").notNullable().unique();
|
||||||
|
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await createOnUpdateTrigger(knex, TableName.OrgBot);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.OrgBot);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.OrgBot);
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.AuditLog))) {
|
||||||
|
await knex.schema.createTable(TableName.AuditLog, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("actor").notNullable();
|
||||||
|
t.jsonb("actorMetadata").notNullable();
|
||||||
|
t.string("ipAddress");
|
||||||
|
t.string("eventType").notNullable();
|
||||||
|
t.jsonb("eventMetadata");
|
||||||
|
t.string("userAgent");
|
||||||
|
t.string("userAgentType");
|
||||||
|
t.datetime("expiresAt");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
// no trigger needed as this collection is append only
|
||||||
|
t.uuid("orgId");
|
||||||
|
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
|
t.string("projectId");
|
||||||
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.AuditLog);
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.GitAppInstallSession))) {
|
||||||
|
await knex.schema.createTable(TableName.GitAppInstallSession, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("sessionId").notNullable().unique();
|
||||||
|
t.uuid("userId");
|
||||||
|
// one to one relationship
|
||||||
|
t.uuid("orgId").notNullable().unique();
|
||||||
|
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
createOnUpdateTrigger(knex, TableName.GitAppInstallSession);
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.GitAppOrg))) {
|
||||||
|
await knex.schema.createTable(TableName.GitAppOrg, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("installationId").notNullable().unique();
|
||||||
|
t.uuid("userId").notNullable();
|
||||||
|
// one to one relationship
|
||||||
|
t.uuid("orgId").notNullable().unique();
|
||||||
|
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
createOnUpdateTrigger(knex, TableName.GitAppOrg);
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SecretScanningGitRisk))) {
|
||||||
|
await knex.schema.createTable(TableName.SecretScanningGitRisk, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("description");
|
||||||
|
t.string("startLine");
|
||||||
|
t.string("endLine");
|
||||||
|
t.string("startColumn");
|
||||||
|
t.string("endColumn");
|
||||||
|
t.string("file");
|
||||||
|
t.string("symlinkFile");
|
||||||
|
t.string("commit");
|
||||||
|
t.string("entropy");
|
||||||
|
t.string("author");
|
||||||
|
t.string("email");
|
||||||
|
t.string("date");
|
||||||
|
t.text("message");
|
||||||
|
t.specificType("tags", "text[]");
|
||||||
|
t.string("ruleID");
|
||||||
|
t.string("fingerprint").unique();
|
||||||
|
t.string("fingerPrintWithoutCommitId");
|
||||||
|
t.boolean("isFalsePositive").defaultTo(false);
|
||||||
|
t.boolean("isResolved").defaultTo(false);
|
||||||
|
t.string("riskOwner");
|
||||||
|
t.string("installationId").notNullable();
|
||||||
|
t.string("repositoryId");
|
||||||
|
t.string("repositoryLink");
|
||||||
|
t.string("repositoryFullName");
|
||||||
|
t.string("pusherName");
|
||||||
|
t.string("pusherEmail");
|
||||||
|
t.string("status");
|
||||||
|
// one to one relationship
|
||||||
|
t.uuid("orgId").notNullable();
|
||||||
|
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
createOnUpdateTrigger(knex, TableName.SecretScanningGitRisk);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SecretScanningGitRisk);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.GitAppOrg);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.GitAppInstallSession);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.SecretScanningGitRisk);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.GitAppOrg);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.GitAppInstallSession);
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.TrustedIps))) {
|
||||||
|
await knex.schema.createTable(TableName.TrustedIps, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("ipAddress").notNullable();
|
||||||
|
t.string("type").notNullable();
|
||||||
|
t.integer("prefix");
|
||||||
|
t.boolean("isActive").defaultTo(true);
|
||||||
|
t.string("comment");
|
||||||
|
t.string("projectId").notNullable();
|
||||||
|
t.foreign("projectId").references("id").inTable(TableName.Project);
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createOnUpdateTrigger(knex, TableName.TrustedIps);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.TrustedIps);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.TrustedIps);
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export interface IAPIKeyData {
|
||||||
|
name: string;
|
||||||
|
user: Types.ObjectId;
|
||||||
|
lastUsed: Date;
|
||||||
|
expiresAt: Date;
|
||||||
|
secretHash: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const apiKeyDataSchema = new Schema<IAPIKeyData>(
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "User",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
lastUsed: {
|
||||||
|
type: Date,
|
||||||
|
},
|
||||||
|
expiresAt: {
|
||||||
|
type: Date,
|
||||||
|
},
|
||||||
|
secretHash: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
select: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const APIKeyData = model<IAPIKeyData>("APIKeyData", apiKeyDataSchema);
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { Document, Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export interface IAPIKeyDataV2 extends Document {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
name: string;
|
||||||
|
user: Types.ObjectId;
|
||||||
|
lastUsed?: Date
|
||||||
|
usageCount: number;
|
||||||
|
expiresAt?: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
const apiKeyDataV2Schema = new Schema(
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "User",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
lastUsed: {
|
||||||
|
type: Date,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
usageCount: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const APIKeyDataV2 = model<IAPIKeyDataV2>("APIKeyDataV2", apiKeyDataV2Schema);
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
import { ActorType, EventType, UserAgentType } from "./enums";
|
||||||
|
import { Actor, Event } from "./types";
|
||||||
|
|
||||||
|
export interface IAuditLog {
|
||||||
|
actor: Actor;
|
||||||
|
organization: Types.ObjectId;
|
||||||
|
workspace: Types.ObjectId;
|
||||||
|
ipAddress: string;
|
||||||
|
event: Event;
|
||||||
|
userAgent: string;
|
||||||
|
userAgentType: UserAgentType;
|
||||||
|
expiresAt?: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auditLogSchema = new Schema<IAuditLog>(
|
||||||
|
{
|
||||||
|
actor: {
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
enum: ActorType,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
type: Schema.Types.Mixed
|
||||||
|
}
|
||||||
|
},
|
||||||
|
organization: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
required: false,
|
||||||
|
index: true
|
||||||
|
},
|
||||||
|
ipAddress: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
event: {
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
enum: EventType,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
type: Schema.Types.Mixed
|
||||||
|
}
|
||||||
|
},
|
||||||
|
userAgent: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
userAgentType: {
|
||||||
|
type: String,
|
||||||
|
enum: UserAgentType,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
expiresAt: {
|
||||||
|
type: Date,
|
||||||
|
expires: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const AuditLog = model<IAuditLog>("AuditLog", auditLogSchema);
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
export enum ActorType { // would extend to AWS, Azure, ...
|
||||||
|
USER = "user", // userIdentity
|
||||||
|
SERVICE = "service",
|
||||||
|
IDENTITY = "identity"
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum UserAgentType {
|
||||||
|
WEB = "web",
|
||||||
|
CLI = "cli",
|
||||||
|
K8_OPERATOR = "k8-operator",
|
||||||
|
TERRAFORM = "terraform",
|
||||||
|
OTHER = "other",
|
||||||
|
PYTHON_SDK = "InfisicalPythonSDK",
|
||||||
|
NODE_SDK = "InfisicalNodeSDK"
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum EventType {
|
||||||
|
GET_SECRETS = "get-secrets",
|
||||||
|
GET_SECRET = "get-secret",
|
||||||
|
REVEAL_SECRET = "reveal-secret",
|
||||||
|
CREATE_SECRET = "create-secret",
|
||||||
|
CREATE_SECRETS = "create-secrets",
|
||||||
|
UPDATE_SECRET = "update-secret",
|
||||||
|
UPDATE_SECRETS = "update-secrets",
|
||||||
|
DELETE_SECRET = "delete-secret",
|
||||||
|
DELETE_SECRETS = "delete-secrets",
|
||||||
|
GET_WORKSPACE_KEY = "get-workspace-key",
|
||||||
|
AUTHORIZE_INTEGRATION = "authorize-integration",
|
||||||
|
UNAUTHORIZE_INTEGRATION = "unauthorize-integration",
|
||||||
|
CREATE_INTEGRATION = "create-integration",
|
||||||
|
DELETE_INTEGRATION = "delete-integration",
|
||||||
|
ADD_TRUSTED_IP = "add-trusted-ip",
|
||||||
|
UPDATE_TRUSTED_IP = "update-trusted-ip",
|
||||||
|
DELETE_TRUSTED_IP = "delete-trusted-ip",
|
||||||
|
CREATE_SERVICE_TOKEN = "create-service-token", // v2
|
||||||
|
DELETE_SERVICE_TOKEN = "delete-service-token", // v2
|
||||||
|
CREATE_IDENTITY = "create-identity",
|
||||||
|
UPDATE_IDENTITY = "update-identity",
|
||||||
|
DELETE_IDENTITY = "delete-identity",
|
||||||
|
LOGIN_IDENTITY_UNIVERSAL_AUTH = "login-identity-universal-auth",
|
||||||
|
ADD_IDENTITY_UNIVERSAL_AUTH = "add-identity-universal-auth",
|
||||||
|
UPDATE_IDENTITY_UNIVERSAL_AUTH = "update-identity-universal-auth",
|
||||||
|
GET_IDENTITY_UNIVERSAL_AUTH = "get-identity-universal-auth",
|
||||||
|
CREATE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "create-identity-universal-auth-client-secret",
|
||||||
|
REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "revoke-identity-universal-auth-client-secret",
|
||||||
|
GET_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRETS = "get-identity-universal-auth-client-secret",
|
||||||
|
CREATE_ENVIRONMENT = "create-environment",
|
||||||
|
UPDATE_ENVIRONMENT = "update-environment",
|
||||||
|
DELETE_ENVIRONMENT = "delete-environment",
|
||||||
|
ADD_WORKSPACE_MEMBER = "add-workspace-member",
|
||||||
|
ADD_BATCH_WORKSPACE_MEMBER = "add-workspace-members",
|
||||||
|
REMOVE_WORKSPACE_MEMBER = "remove-workspace-member",
|
||||||
|
CREATE_FOLDER = "create-folder",
|
||||||
|
UPDATE_FOLDER = "update-folder",
|
||||||
|
DELETE_FOLDER = "delete-folder",
|
||||||
|
CREATE_WEBHOOK = "create-webhook",
|
||||||
|
UPDATE_WEBHOOK_STATUS = "update-webhook-status",
|
||||||
|
DELETE_WEBHOOK = "delete-webhook",
|
||||||
|
GET_SECRET_IMPORTS = "get-secret-imports",
|
||||||
|
CREATE_SECRET_IMPORT = "create-secret-import",
|
||||||
|
UPDATE_SECRET_IMPORT = "update-secret-import",
|
||||||
|
DELETE_SECRET_IMPORT = "delete-secret-import",
|
||||||
|
UPDATE_USER_WORKSPACE_ROLE = "update-user-workspace-role",
|
||||||
|
UPDATE_USER_WORKSPACE_DENIED_PERMISSIONS = "update-user-workspace-denied-permissions",
|
||||||
|
SECRET_APPROVAL_MERGED = "secret-approval-merged",
|
||||||
|
SECRET_APPROVAL_REQUEST = "secret-approval-request",
|
||||||
|
SECRET_APPROVAL_CLOSED = "secret-approval-closed",
|
||||||
|
SECRET_APPROVAL_REOPENED = "secret-approval-reopened"
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export * from "./auditLog";
|
||||||
|
export * from "./enums";
|
||||||
|
export * from "./types";
|
||||||
@@ -0,0 +1,585 @@
|
|||||||
|
import { ActorType, EventType } from "./enums";
|
||||||
|
import { IIdentityTrustedIp } from "../../../models";
|
||||||
|
|
||||||
|
interface UserActorMetadata {
|
||||||
|
userId: string;
|
||||||
|
email: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ServiceActorMetadata {
|
||||||
|
serviceId: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IdentityActorMetadata {
|
||||||
|
identityId: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserActor {
|
||||||
|
type: ActorType.USER;
|
||||||
|
metadata: UserActorMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServiceActor {
|
||||||
|
type: ActorType.SERVICE;
|
||||||
|
metadata: ServiceActorMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IdentityActor {
|
||||||
|
type: ActorType.IDENTITY;
|
||||||
|
metadata: IdentityActorMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Actor = UserActor | ServiceActor | IdentityActor;
|
||||||
|
|
||||||
|
interface GetSecretsEvent {
|
||||||
|
type: EventType.GET_SECRETS;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
numberOfSecrets: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetSecretEvent {
|
||||||
|
type: EventType.GET_SECRET;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
secretId: string;
|
||||||
|
secretKey: string;
|
||||||
|
secretVersion: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateSecretEvent {
|
||||||
|
type: EventType.CREATE_SECRET;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
secretId: string;
|
||||||
|
secretKey: string;
|
||||||
|
secretVersion: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateSecretBatchEvent {
|
||||||
|
type: EventType.CREATE_SECRETS;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
secrets: Array<{ secretId: string; secretKey: string; secretVersion: number }>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateSecretEvent {
|
||||||
|
type: EventType.UPDATE_SECRET;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
secretId: string;
|
||||||
|
secretKey: string;
|
||||||
|
secretVersion: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateSecretBatchEvent {
|
||||||
|
type: EventType.UPDATE_SECRETS;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
secrets: Array<{ secretId: string; secretKey: string; secretVersion: number }>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteSecretEvent {
|
||||||
|
type: EventType.DELETE_SECRET;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
secretId: string;
|
||||||
|
secretKey: string;
|
||||||
|
secretVersion: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteSecretBatchEvent {
|
||||||
|
type: EventType.DELETE_SECRETS;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
secrets: Array<{ secretId: string; secretKey: string; secretVersion: number }>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetWorkspaceKeyEvent {
|
||||||
|
type: EventType.GET_WORKSPACE_KEY;
|
||||||
|
metadata: {
|
||||||
|
keyId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AuthorizeIntegrationEvent {
|
||||||
|
type: EventType.AUTHORIZE_INTEGRATION;
|
||||||
|
metadata: {
|
||||||
|
integration: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UnauthorizeIntegrationEvent {
|
||||||
|
type: EventType.UNAUTHORIZE_INTEGRATION;
|
||||||
|
metadata: {
|
||||||
|
integration: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateIntegrationEvent {
|
||||||
|
type: EventType.CREATE_INTEGRATION;
|
||||||
|
metadata: {
|
||||||
|
integrationId: string;
|
||||||
|
integration: string; // TODO: fix type
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
url?: string;
|
||||||
|
app?: string;
|
||||||
|
appId?: string;
|
||||||
|
targetEnvironment?: string;
|
||||||
|
targetEnvironmentId?: string;
|
||||||
|
targetService?: string;
|
||||||
|
targetServiceId?: string;
|
||||||
|
path?: string;
|
||||||
|
region?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteIntegrationEvent {
|
||||||
|
type: EventType.DELETE_INTEGRATION;
|
||||||
|
metadata: {
|
||||||
|
integrationId: string;
|
||||||
|
integration: string; // TODO: fix type
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
url?: string;
|
||||||
|
app?: string;
|
||||||
|
appId?: string;
|
||||||
|
targetEnvironment?: string;
|
||||||
|
targetEnvironmentId?: string;
|
||||||
|
targetService?: string;
|
||||||
|
targetServiceId?: string;
|
||||||
|
path?: string;
|
||||||
|
region?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AddTrustedIPEvent {
|
||||||
|
type: EventType.ADD_TRUSTED_IP;
|
||||||
|
metadata: {
|
||||||
|
trustedIpId: string;
|
||||||
|
ipAddress: string;
|
||||||
|
prefix?: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateTrustedIPEvent {
|
||||||
|
type: EventType.UPDATE_TRUSTED_IP;
|
||||||
|
metadata: {
|
||||||
|
trustedIpId: string;
|
||||||
|
ipAddress: string;
|
||||||
|
prefix?: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteTrustedIPEvent {
|
||||||
|
type: EventType.DELETE_TRUSTED_IP;
|
||||||
|
metadata: {
|
||||||
|
trustedIpId: string;
|
||||||
|
ipAddress: string;
|
||||||
|
prefix?: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateServiceTokenEvent {
|
||||||
|
type: EventType.CREATE_SERVICE_TOKEN;
|
||||||
|
metadata: {
|
||||||
|
name: string;
|
||||||
|
scopes: Array<{
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteServiceTokenEvent {
|
||||||
|
type: EventType.DELETE_SERVICE_TOKEN;
|
||||||
|
metadata: {
|
||||||
|
name: string;
|
||||||
|
scopes: Array<{
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateIdentityEvent { // note: currently not logging org-role
|
||||||
|
type: EventType.CREATE_IDENTITY;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateIdentityEvent {
|
||||||
|
type: EventType.UPDATE_IDENTITY;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
name?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteIdentityEvent {
|
||||||
|
type: EventType.DELETE_IDENTITY;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LoginIdentityUniversalAuthEvent {
|
||||||
|
type: EventType.LOGIN_IDENTITY_UNIVERSAL_AUTH ;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
identityUniversalAuthId: string;
|
||||||
|
clientSecretId: string;
|
||||||
|
identityAccessTokenId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AddIdentityUniversalAuthEvent {
|
||||||
|
type: EventType.ADD_IDENTITY_UNIVERSAL_AUTH;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
clientSecretTrustedIps: Array<IIdentityTrustedIp>;
|
||||||
|
accessTokenTTL: number;
|
||||||
|
accessTokenMaxTTL: number;
|
||||||
|
accessTokenNumUsesLimit: number;
|
||||||
|
accessTokenTrustedIps: Array<IIdentityTrustedIp>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateIdentityUniversalAuthEvent {
|
||||||
|
type: EventType.UPDATE_IDENTITY_UNIVERSAL_AUTH;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
clientSecretTrustedIps?: Array<IIdentityTrustedIp>;
|
||||||
|
accessTokenTTL?: number;
|
||||||
|
accessTokenMaxTTL?: number;
|
||||||
|
accessTokenNumUsesLimit?: number;
|
||||||
|
accessTokenTrustedIps?: Array<IIdentityTrustedIp>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetIdentityUniversalAuthEvent {
|
||||||
|
type: EventType.GET_IDENTITY_UNIVERSAL_AUTH;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateIdentityUniversalAuthClientSecretEvent {
|
||||||
|
type: EventType.CREATE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET ;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
clientSecretId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetIdentityUniversalAuthClientSecretsEvent {
|
||||||
|
type: EventType.GET_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRETS;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface RevokeIdentityUniversalAuthClientSecretEvent {
|
||||||
|
type: EventType.REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET ;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
clientSecretId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateEnvironmentEvent {
|
||||||
|
type: EventType.CREATE_ENVIRONMENT;
|
||||||
|
metadata: {
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateEnvironmentEvent {
|
||||||
|
type: EventType.UPDATE_ENVIRONMENT;
|
||||||
|
metadata: {
|
||||||
|
oldName: string;
|
||||||
|
newName: string;
|
||||||
|
oldSlug: string;
|
||||||
|
newSlug: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteEnvironmentEvent {
|
||||||
|
type: EventType.DELETE_ENVIRONMENT;
|
||||||
|
metadata: {
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AddWorkspaceMemberEvent {
|
||||||
|
type: EventType.ADD_WORKSPACE_MEMBER;
|
||||||
|
metadata: {
|
||||||
|
userId: string;
|
||||||
|
email: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AddBatchWorkspaceMemberEvent {
|
||||||
|
type: EventType.ADD_BATCH_WORKSPACE_MEMBER;
|
||||||
|
metadata: Array<{
|
||||||
|
userId: string;
|
||||||
|
email: string;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RemoveWorkspaceMemberEvent {
|
||||||
|
type: EventType.REMOVE_WORKSPACE_MEMBER;
|
||||||
|
metadata: {
|
||||||
|
userId: string;
|
||||||
|
email: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateFolderEvent {
|
||||||
|
type: EventType.CREATE_FOLDER;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
folderId: string;
|
||||||
|
folderName: string;
|
||||||
|
folderPath: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateFolderEvent {
|
||||||
|
type: EventType.UPDATE_FOLDER;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
folderId: string;
|
||||||
|
oldFolderName: string;
|
||||||
|
newFolderName: string;
|
||||||
|
folderPath: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteFolderEvent {
|
||||||
|
type: EventType.DELETE_FOLDER;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
folderId: string;
|
||||||
|
folderName: string;
|
||||||
|
folderPath: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateWebhookEvent {
|
||||||
|
type: EventType.CREATE_WEBHOOK;
|
||||||
|
metadata: {
|
||||||
|
webhookId: string;
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
webhookUrl: string;
|
||||||
|
isDisabled: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateWebhookStatusEvent {
|
||||||
|
type: EventType.UPDATE_WEBHOOK_STATUS;
|
||||||
|
metadata: {
|
||||||
|
webhookId: string;
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
webhookUrl: string;
|
||||||
|
isDisabled: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteWebhookEvent {
|
||||||
|
type: EventType.DELETE_WEBHOOK;
|
||||||
|
metadata: {
|
||||||
|
webhookId: string;
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
webhookUrl: string;
|
||||||
|
isDisabled: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetSecretImportsEvent {
|
||||||
|
type: EventType.GET_SECRET_IMPORTS;
|
||||||
|
metadata: {
|
||||||
|
environment: string;
|
||||||
|
secretImportId: string;
|
||||||
|
folderId: string;
|
||||||
|
numberOfImports: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateSecretImportEvent {
|
||||||
|
type: EventType.CREATE_SECRET_IMPORT;
|
||||||
|
metadata: {
|
||||||
|
secretImportId: string;
|
||||||
|
folderId: string;
|
||||||
|
importFromEnvironment: string;
|
||||||
|
importFromSecretPath: string;
|
||||||
|
importToEnvironment: string;
|
||||||
|
importToSecretPath: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateSecretImportEvent {
|
||||||
|
type: EventType.UPDATE_SECRET_IMPORT;
|
||||||
|
metadata: {
|
||||||
|
secretImportId: string;
|
||||||
|
folderId: string;
|
||||||
|
importToEnvironment: string;
|
||||||
|
importToSecretPath: string;
|
||||||
|
orderBefore: {
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
}[];
|
||||||
|
orderAfter: {
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteSecretImportEvent {
|
||||||
|
type: EventType.DELETE_SECRET_IMPORT;
|
||||||
|
metadata: {
|
||||||
|
secretImportId: string;
|
||||||
|
folderId: string;
|
||||||
|
importFromEnvironment: string;
|
||||||
|
importFromSecretPath: string;
|
||||||
|
importToEnvironment: string;
|
||||||
|
importToSecretPath: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateUserRole {
|
||||||
|
type: EventType.UPDATE_USER_WORKSPACE_ROLE;
|
||||||
|
metadata: {
|
||||||
|
userId: string;
|
||||||
|
email: string;
|
||||||
|
oldRole: string;
|
||||||
|
newRole: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateUserDeniedPermissions {
|
||||||
|
type: EventType.UPDATE_USER_WORKSPACE_DENIED_PERMISSIONS;
|
||||||
|
metadata: {
|
||||||
|
userId: string;
|
||||||
|
email: string;
|
||||||
|
deniedPermissions: {
|
||||||
|
environmentSlug: string;
|
||||||
|
ability: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
interface SecretApprovalMerge {
|
||||||
|
type: EventType.SECRET_APPROVAL_MERGED;
|
||||||
|
metadata: {
|
||||||
|
mergedBy: string;
|
||||||
|
secretApprovalRequestSlug: string;
|
||||||
|
secretApprovalRequestId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SecretApprovalClosed {
|
||||||
|
type: EventType.SECRET_APPROVAL_CLOSED;
|
||||||
|
metadata: {
|
||||||
|
closedBy: string;
|
||||||
|
secretApprovalRequestSlug: string;
|
||||||
|
secretApprovalRequestId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SecretApprovalReopened {
|
||||||
|
type: EventType.SECRET_APPROVAL_REOPENED;
|
||||||
|
metadata: {
|
||||||
|
reopenedBy: string;
|
||||||
|
secretApprovalRequestSlug: string;
|
||||||
|
secretApprovalRequestId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SecretApprovalRequest {
|
||||||
|
type: EventType.SECRET_APPROVAL_REQUEST;
|
||||||
|
metadata: {
|
||||||
|
committedBy: string;
|
||||||
|
secretApprovalRequestSlug: string;
|
||||||
|
secretApprovalRequestId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Event =
|
||||||
|
| GetSecretsEvent
|
||||||
|
| GetSecretEvent
|
||||||
|
| CreateSecretEvent
|
||||||
|
| CreateSecretBatchEvent
|
||||||
|
| UpdateSecretEvent
|
||||||
|
| UpdateSecretBatchEvent
|
||||||
|
| DeleteSecretEvent
|
||||||
|
| DeleteSecretBatchEvent
|
||||||
|
| GetWorkspaceKeyEvent
|
||||||
|
| AuthorizeIntegrationEvent
|
||||||
|
| UnauthorizeIntegrationEvent
|
||||||
|
| CreateIntegrationEvent
|
||||||
|
| DeleteIntegrationEvent
|
||||||
|
| AddTrustedIPEvent
|
||||||
|
| UpdateTrustedIPEvent
|
||||||
|
| DeleteTrustedIPEvent
|
||||||
|
| CreateServiceTokenEvent
|
||||||
|
| DeleteServiceTokenEvent
|
||||||
|
| CreateIdentityEvent
|
||||||
|
| UpdateIdentityEvent
|
||||||
|
| DeleteIdentityEvent
|
||||||
|
| LoginIdentityUniversalAuthEvent
|
||||||
|
| AddIdentityUniversalAuthEvent
|
||||||
|
| UpdateIdentityUniversalAuthEvent
|
||||||
|
| GetIdentityUniversalAuthEvent
|
||||||
|
| CreateIdentityUniversalAuthClientSecretEvent
|
||||||
|
| GetIdentityUniversalAuthClientSecretsEvent
|
||||||
|
| RevokeIdentityUniversalAuthClientSecretEvent
|
||||||
|
| CreateEnvironmentEvent
|
||||||
|
| UpdateEnvironmentEvent
|
||||||
|
| DeleteEnvironmentEvent
|
||||||
|
| AddWorkspaceMemberEvent
|
||||||
|
| AddBatchWorkspaceMemberEvent
|
||||||
|
| RemoveWorkspaceMemberEvent
|
||||||
|
| CreateFolderEvent
|
||||||
|
| UpdateFolderEvent
|
||||||
|
| DeleteFolderEvent
|
||||||
|
| CreateWebhookEvent
|
||||||
|
| UpdateWebhookStatusEvent
|
||||||
|
| DeleteWebhookEvent
|
||||||
|
| GetSecretImportsEvent
|
||||||
|
| CreateSecretImportEvent
|
||||||
|
| UpdateSecretImportEvent
|
||||||
|
| DeleteSecretImportEvent
|
||||||
|
| UpdateUserRole
|
||||||
|
| UpdateUserDeniedPermissions
|
||||||
|
| SecretApprovalMerge
|
||||||
|
| SecretApprovalClosed
|
||||||
|
| SecretApprovalRequest
|
||||||
|
| SecretApprovalReopened;
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
import {
|
||||||
|
ALGORITHM_AES_256_GCM,
|
||||||
|
ENCODING_SCHEME_BASE64,
|
||||||
|
ENCODING_SCHEME_UTF8,
|
||||||
|
} from "../variables";
|
||||||
|
|
||||||
|
export interface IBackupPrivateKey {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
user: Types.ObjectId;
|
||||||
|
encryptedPrivateKey: string;
|
||||||
|
iv: string;
|
||||||
|
tag: string;
|
||||||
|
salt: string;
|
||||||
|
algorithm: string;
|
||||||
|
keyEncoding: "base64" | "utf8";
|
||||||
|
verifier: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const backupPrivateKeySchema = new Schema<IBackupPrivateKey>(
|
||||||
|
{
|
||||||
|
user: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "User",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
encryptedPrivateKey: {
|
||||||
|
type: String,
|
||||||
|
select: false,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
iv: {
|
||||||
|
type: String,
|
||||||
|
select: false,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
tag: {
|
||||||
|
type: String,
|
||||||
|
select: false,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
algorithm: { // the encryption algorithm used
|
||||||
|
type: String,
|
||||||
|
enum: [ALGORITHM_AES_256_GCM],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
keyEncoding: {
|
||||||
|
type: String,
|
||||||
|
enum: [
|
||||||
|
ENCODING_SCHEME_UTF8,
|
||||||
|
ENCODING_SCHEME_BASE64,
|
||||||
|
],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
salt: {
|
||||||
|
type: String,
|
||||||
|
select: false,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
verifier: {
|
||||||
|
type: String,
|
||||||
|
select: false,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const BackupPrivateKey = model<IBackupPrivateKey>(
|
||||||
|
"BackupPrivateKey",
|
||||||
|
backupPrivateKeySchema
|
||||||
|
);
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
import {
|
||||||
|
ALGORITHM_AES_256_GCM,
|
||||||
|
ENCODING_SCHEME_BASE64,
|
||||||
|
ENCODING_SCHEME_UTF8,
|
||||||
|
} from "../variables";
|
||||||
|
|
||||||
|
export interface IBot {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
name: string;
|
||||||
|
workspace: Types.ObjectId;
|
||||||
|
isActive: boolean;
|
||||||
|
publicKey: string;
|
||||||
|
encryptedPrivateKey: string;
|
||||||
|
iv: string;
|
||||||
|
tag: string;
|
||||||
|
algorithm: "aes-256-gcm";
|
||||||
|
keyEncoding: "base64" | "utf8";
|
||||||
|
}
|
||||||
|
|
||||||
|
const botSchema = new Schema<IBot>(
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Workspace",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
isActive: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
publicKey: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
encryptedPrivateKey: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
select: false,
|
||||||
|
},
|
||||||
|
iv: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
select: false,
|
||||||
|
},
|
||||||
|
tag: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
select: false,
|
||||||
|
},
|
||||||
|
algorithm: { // the encryption algorithm used
|
||||||
|
type: String,
|
||||||
|
enum: [ALGORITHM_AES_256_GCM],
|
||||||
|
required: true,
|
||||||
|
select: false,
|
||||||
|
},
|
||||||
|
keyEncoding: {
|
||||||
|
type: String,
|
||||||
|
enum: [
|
||||||
|
ENCODING_SCHEME_UTF8,
|
||||||
|
ENCODING_SCHEME_BASE64,
|
||||||
|
],
|
||||||
|
required: true,
|
||||||
|
select: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const Bot = model<IBot>("Bot", botSchema);
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export interface IBotKey {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
encryptedKey: string;
|
||||||
|
nonce: string;
|
||||||
|
sender: Types.ObjectId;
|
||||||
|
bot: Types.ObjectId;
|
||||||
|
workspace: Types.ObjectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const botKeySchema = new Schema<IBotKey>(
|
||||||
|
{
|
||||||
|
encryptedKey: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
nonce: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
sender: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "User",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
bot: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Bot",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Workspace",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const BotKey = model<IBotKey>("BotKey", botKeySchema);
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
import {
|
||||||
|
ALGORITHM_AES_256_GCM,
|
||||||
|
ENCODING_SCHEME_BASE64,
|
||||||
|
ENCODING_SCHEME_UTF8,
|
||||||
|
} from "../variables";
|
||||||
|
|
||||||
|
export interface IBotOrg {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
name: string;
|
||||||
|
organization: Types.ObjectId;
|
||||||
|
publicKey: string;
|
||||||
|
encryptedSymmetricKey: string;
|
||||||
|
symmetricKeyIV: string;
|
||||||
|
symmetricKeyTag: string;
|
||||||
|
symmetricKeyAlgorithm: "aes-256-gcm";
|
||||||
|
symmetricKeyKeyEncoding: "base64" | "utf8";
|
||||||
|
encryptedPrivateKey: string;
|
||||||
|
privateKeyIV: string;
|
||||||
|
privateKeyTag: string;
|
||||||
|
privateKeyAlgorithm: "aes-256-gcm";
|
||||||
|
privateKeyKeyEncoding: "base64" | "utf8";
|
||||||
|
}
|
||||||
|
|
||||||
|
const botOrgSchema = new Schema<IBotOrg>(
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
organization: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Organization",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
publicKey: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
encryptedSymmetricKey: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
symmetricKeyIV: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
symmetricKeyTag: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
symmetricKeyAlgorithm: {
|
||||||
|
type: String,
|
||||||
|
enum: [ALGORITHM_AES_256_GCM],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
symmetricKeyKeyEncoding: {
|
||||||
|
type: String,
|
||||||
|
enum: [
|
||||||
|
ENCODING_SCHEME_UTF8,
|
||||||
|
ENCODING_SCHEME_BASE64,
|
||||||
|
],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
encryptedPrivateKey: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
privateKeyIV: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
privateKeyTag: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
privateKeyAlgorithm: {
|
||||||
|
type: String,
|
||||||
|
enum: [ALGORITHM_AES_256_GCM],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
privateKeyKeyEncoding: {
|
||||||
|
type: String,
|
||||||
|
enum: [
|
||||||
|
ENCODING_SCHEME_UTF8,
|
||||||
|
ENCODING_SCHEME_BASE64,
|
||||||
|
],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const BotOrg = model<IBotOrg>("BotOrg", botOrgSchema);
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export type TFolderRootSchema = {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
workspace: Types.ObjectId;
|
||||||
|
environment: string;
|
||||||
|
nodes: TFolderSchema;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TFolderSchema = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
version: number;
|
||||||
|
children: TFolderSchema[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const folderSchema = new Schema<TFolderSchema>({
|
||||||
|
id: {
|
||||||
|
required: true,
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
version: {
|
||||||
|
required: true,
|
||||||
|
type: Number,
|
||||||
|
default: 1,
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
required: true,
|
||||||
|
type: String,
|
||||||
|
default: "root",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
folderSchema.add({ children: [folderSchema] });
|
||||||
|
|
||||||
|
const folderRootSchema = new Schema<TFolderRootSchema>(
|
||||||
|
{
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Workspace",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
environment: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
nodes: folderSchema,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const Folder = model<TFolderRootSchema>("Folder", folderRootSchema);
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export type TFolderRootVersionSchema = {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
workspace: Types.ObjectId;
|
||||||
|
environment: string;
|
||||||
|
nodes: TFolderVersionSchema;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TFolderVersionSchema = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
version: number;
|
||||||
|
children: TFolderVersionSchema[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const folderVersionSchema = new Schema<TFolderVersionSchema>({
|
||||||
|
id: {
|
||||||
|
required: true,
|
||||||
|
type: String,
|
||||||
|
default: "root",
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
required: true,
|
||||||
|
type: String,
|
||||||
|
default: "root",
|
||||||
|
},
|
||||||
|
version: {
|
||||||
|
required: true,
|
||||||
|
type: Number,
|
||||||
|
default: 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
folderVersionSchema.add({ children: [folderVersionSchema] });
|
||||||
|
|
||||||
|
const folderRootVersionSchema = new Schema<TFolderRootVersionSchema>(
|
||||||
|
{
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Workspace",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
environment: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
nodes: folderVersionSchema,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const FolderVersion = model<TFolderRootVersionSchema>(
|
||||||
|
"FolderVersion",
|
||||||
|
folderRootVersionSchema
|
||||||
|
);
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
type GitAppInstallationSession = {
|
||||||
|
id: string;
|
||||||
|
sessionId: string;
|
||||||
|
organization: Types.ObjectId;
|
||||||
|
user: Types.ObjectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const gitAppInstallationSession = new Schema<GitAppInstallationSession>({
|
||||||
|
id: {
|
||||||
|
required: true,
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
sessionId: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
unique: true
|
||||||
|
},
|
||||||
|
organization: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
required: true,
|
||||||
|
unique: true
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "User"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export const GitAppInstallationSession = model<GitAppInstallationSession>("git_app_installation_session", gitAppInstallationSession);
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { Schema, model } from "mongoose";
|
||||||
|
|
||||||
|
type Installation = {
|
||||||
|
installationId: string
|
||||||
|
organizationId: string
|
||||||
|
user: Schema.Types.ObjectId
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const gitAppOrganizationInstallation = new Schema<Installation>({
|
||||||
|
installationId: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
unique: true
|
||||||
|
},
|
||||||
|
organizationId: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
unique: true
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "User",
|
||||||
|
required: true,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export const GitAppOrganizationInstallation = model<Installation>("git_app_organization_installation", gitAppOrganizationInstallation);
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
import { Schema, model } from "mongoose";
|
||||||
|
|
||||||
|
export const STATUS_RESOLVED_FALSE_POSITIVE = "RESOLVED_FALSE_POSITIVE";
|
||||||
|
export const STATUS_RESOLVED_REVOKED = "RESOLVED_REVOKED";
|
||||||
|
export const STATUS_RESOLVED_NOT_REVOKED = "RESOLVED_NOT_REVOKED";
|
||||||
|
export const STATUS_UNRESOLVED = "UNRESOLVED";
|
||||||
|
|
||||||
|
export type IGitRisks = {
|
||||||
|
id: string;
|
||||||
|
description: string;
|
||||||
|
startLine: string;
|
||||||
|
endLine: string;
|
||||||
|
startColumn: string;
|
||||||
|
endColumn: string;
|
||||||
|
match: string;
|
||||||
|
secret: string;
|
||||||
|
file: string;
|
||||||
|
symlinkFile: string;
|
||||||
|
commit: string;
|
||||||
|
entropy: string;
|
||||||
|
author: string;
|
||||||
|
email: string;
|
||||||
|
date: string;
|
||||||
|
message: string;
|
||||||
|
tags: string[];
|
||||||
|
ruleID: string;
|
||||||
|
fingerprint: string;
|
||||||
|
fingerPrintWithoutCommitId: string
|
||||||
|
|
||||||
|
isFalsePositive: boolean; // New field for marking risks as false positives
|
||||||
|
isResolved: boolean; // New field for marking risks as resolved
|
||||||
|
riskOwner: string | null; // New field for setting a risk owner (nullable string)
|
||||||
|
installationId: string,
|
||||||
|
repositoryId: string,
|
||||||
|
repositoryLink: string
|
||||||
|
repositoryFullName: string
|
||||||
|
status: string
|
||||||
|
pusher: {
|
||||||
|
name: string,
|
||||||
|
email: string
|
||||||
|
},
|
||||||
|
organization: Schema.Types.ObjectId,
|
||||||
|
}
|
||||||
|
|
||||||
|
const gitRisks = new Schema<IGitRisks>({
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
startLine: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
endLine: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
startColumn: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
endColumn: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
file: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
symlinkFile: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
commit: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
entropy: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
author: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
email: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
date: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
tags: {
|
||||||
|
type: [String],
|
||||||
|
},
|
||||||
|
ruleID: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
fingerprint: {
|
||||||
|
type: String,
|
||||||
|
unique: true
|
||||||
|
},
|
||||||
|
fingerPrintWithoutCommitId: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
isFalsePositive: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
isResolved: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
riskOwner: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
installationId: {
|
||||||
|
type: String,
|
||||||
|
require: true
|
||||||
|
},
|
||||||
|
repositoryId: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
repositoryLink: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
repositoryFullName: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
pusher: {
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
email: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
},
|
||||||
|
organization: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Organization",
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
type: String,
|
||||||
|
enum: [
|
||||||
|
STATUS_RESOLVED_FALSE_POSITIVE,
|
||||||
|
STATUS_RESOLVED_REVOKED,
|
||||||
|
STATUS_RESOLVED_NOT_REVOKED,
|
||||||
|
STATUS_UNRESOLVED
|
||||||
|
],
|
||||||
|
default: STATUS_UNRESOLVED
|
||||||
|
}
|
||||||
|
}, { timestamps: true });
|
||||||
|
|
||||||
|
export const GitRisks = model<IGitRisks>("GitRisks", gitRisks);
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { Document, Schema, Types, model } from "mongoose";
|
||||||
|
import { IPType } from "../ee/models";
|
||||||
|
|
||||||
|
export interface IIdentityTrustedIp {
|
||||||
|
ipAddress: string;
|
||||||
|
type: IPType;
|
||||||
|
prefix: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum IdentityAuthMethod {
|
||||||
|
UNIVERSAL_AUTH = "universal-auth"
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IIdentity extends Document {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
name: string;
|
||||||
|
authMethod?: IdentityAuthMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
const identitySchema = new Schema(
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
authMethod: {
|
||||||
|
type: String,
|
||||||
|
enum: IdentityAuthMethod,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const Identity = model<IIdentity>("Identity", identitySchema);
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
import { Document, Schema, Types, model } from "mongoose";
|
||||||
|
import { IIdentityTrustedIp } from "./identity";
|
||||||
|
import { IPType } from "../ee/models/trustedIp";
|
||||||
|
|
||||||
|
export interface IIdentityAccessToken extends Document {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
identity: Types.ObjectId;
|
||||||
|
identityUniversalAuthClientSecret?: Types.ObjectId;
|
||||||
|
accessTokenLastUsedAt?: Date;
|
||||||
|
accessTokenLastRenewedAt?: Date;
|
||||||
|
accessTokenNumUses: number;
|
||||||
|
accessTokenNumUsesLimit: number;
|
||||||
|
accessTokenTTL: number;
|
||||||
|
accessTokenMaxTTL: number;
|
||||||
|
accessTokenTrustedIps: Array<IIdentityTrustedIp>;
|
||||||
|
isAccessTokenRevoked: boolean;
|
||||||
|
updatedAt: Date;
|
||||||
|
createdAt: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
const identityAccessTokenSchema = new Schema(
|
||||||
|
{
|
||||||
|
identity: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Identity",
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
identityUniversalAuthClientSecret: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "IdentityUniversalAuthClientSecret",
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
accessTokenLastUsedAt: {
|
||||||
|
type: Date,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
accessTokenLastRenewedAt: {
|
||||||
|
type: Date,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
accessTokenNumUses: {
|
||||||
|
// number of times access token has been used
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
accessTokenNumUsesLimit: {
|
||||||
|
// number of times access token can be used for
|
||||||
|
type: Number,
|
||||||
|
default: 0, // default: used as many times as needed
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
accessTokenTTL: { // seconds
|
||||||
|
// incremental lifetime
|
||||||
|
type: Number,
|
||||||
|
default: 2592000, // 30 days
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
accessTokenMaxTTL: { // seconds
|
||||||
|
// max lifetime
|
||||||
|
type: Number,
|
||||||
|
default: 2592000, // 30 days
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
accessTokenTrustedIps: {
|
||||||
|
type: [
|
||||||
|
{
|
||||||
|
ipAddress: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
enum: [
|
||||||
|
IPType.IPV4,
|
||||||
|
IPType.IPV6
|
||||||
|
],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
prefix: {
|
||||||
|
type: Number,
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
default: [{
|
||||||
|
ipAddress: "0.0.0.0",
|
||||||
|
type: IPType.IPV4.toString(),
|
||||||
|
prefix: 0
|
||||||
|
}],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
isAccessTokenRevoked: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const IdentityAccessToken = model<IIdentityAccessToken>("IdentityAccessToken", identityAccessTokenSchema);
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
import { ADMIN, CUSTOM, MEMBER, NO_ACCESS, VIEWER } from "../variables";
|
||||||
|
|
||||||
|
export interface IIdentityMembership {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
identity: Types.ObjectId;
|
||||||
|
workspace: Types.ObjectId;
|
||||||
|
role: "admin" | "member" | "viewer" | "no-access" | "custom";
|
||||||
|
customRole: Types.ObjectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const identityMembershipSchema = new Schema<IIdentityMembership>(
|
||||||
|
{
|
||||||
|
identity: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Identity"
|
||||||
|
},
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Workspace",
|
||||||
|
required: true,
|
||||||
|
index: true,
|
||||||
|
},
|
||||||
|
role: {
|
||||||
|
type: String,
|
||||||
|
enum: [ADMIN, MEMBER, VIEWER, CUSTOM, NO_ACCESS],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
customRole: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Role"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const IdentityMembership = model<IIdentityMembership>("IdentityMembership", identityMembershipSchema);
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
import { ADMIN, CUSTOM, MEMBER, NO_ACCESS} from "../variables";
|
||||||
|
|
||||||
|
export interface IIdentityMembershipOrg {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
identity: Types.ObjectId;
|
||||||
|
organization: Types.ObjectId;
|
||||||
|
role: "admin" | "member" | "no-access" | "custom";
|
||||||
|
customRole: Types.ObjectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const identityMembershipOrgSchema = new Schema<IIdentityMembershipOrg>(
|
||||||
|
{
|
||||||
|
identity: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Identity"
|
||||||
|
},
|
||||||
|
organization: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Organization"
|
||||||
|
},
|
||||||
|
role: {
|
||||||
|
type: String,
|
||||||
|
enum: [ADMIN, MEMBER, NO_ACCESS, CUSTOM],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
customRole: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Role"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const IdentityMembershipOrg = model<IIdentityMembershipOrg>("IdentityMembershipOrg", identityMembershipOrgSchema);
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
import { Document, Schema, Types, model } from "mongoose";
|
||||||
|
import { IPType } from "../ee/models";
|
||||||
|
import { IIdentityTrustedIp } from "./identity";
|
||||||
|
|
||||||
|
export interface IIdentityUniversalAuth extends Document {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
identity: Types.ObjectId;
|
||||||
|
clientId: string;
|
||||||
|
clientSecretTrustedIps: Array<IIdentityTrustedIp>;
|
||||||
|
accessTokenTTL: number;
|
||||||
|
accessTokenMaxTTL: number;
|
||||||
|
accessTokenNumUsesLimit: number;
|
||||||
|
accessTokenTrustedIps: Array<IIdentityTrustedIp>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const identityUniversalAuthSchema = new Schema(
|
||||||
|
{
|
||||||
|
identity: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Identity",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
clientId: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
clientSecretTrustedIps: {
|
||||||
|
type: [
|
||||||
|
{
|
||||||
|
ipAddress: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
enum: [
|
||||||
|
IPType.IPV4,
|
||||||
|
IPType.IPV6
|
||||||
|
],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
prefix: {
|
||||||
|
type: Number,
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
default: [{
|
||||||
|
ipAddress: "0.0.0.0",
|
||||||
|
type: IPType.IPV4.toString(),
|
||||||
|
prefix: 0
|
||||||
|
}],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
accessTokenTTL: { // seconds
|
||||||
|
// incremental lifetime
|
||||||
|
type: Number,
|
||||||
|
default: 7200,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
accessTokenMaxTTL: { // seconds
|
||||||
|
// max lifetime
|
||||||
|
type: Number,
|
||||||
|
default: 7200,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
accessTokenNumUsesLimit: {
|
||||||
|
// number of times access token can be used for
|
||||||
|
type: Number,
|
||||||
|
default: 0, // default: used as many times as needed
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
accessTokenTrustedIps: {
|
||||||
|
type: [
|
||||||
|
{
|
||||||
|
ipAddress: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
enum: [
|
||||||
|
IPType.IPV4,
|
||||||
|
IPType.IPV6
|
||||||
|
],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
prefix: {
|
||||||
|
type: Number,
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
default: [{
|
||||||
|
ipAddress: "0.0.0.0",
|
||||||
|
type: IPType.IPV4.toString(),
|
||||||
|
prefix: 0
|
||||||
|
}],
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const IdentityUniversalAuth = model<IIdentityUniversalAuth>("IdentityUniversalAuth", identityUniversalAuthSchema);
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
import { Document, Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export interface IIdentityUniversalAuthClientSecret extends Document {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
identity: Types.ObjectId;
|
||||||
|
identityUniversalAuth : Types.ObjectId;
|
||||||
|
description: string;
|
||||||
|
clientSecretPrefix: string;
|
||||||
|
clientSecretHash: string;
|
||||||
|
clientSecretLastUsedAt?: Date;
|
||||||
|
clientSecretNumUses: number;
|
||||||
|
clientSecretNumUsesLimit: number;
|
||||||
|
clientSecretTTL: number;
|
||||||
|
updatedAt: Date;
|
||||||
|
createdAt: Date;
|
||||||
|
isClientSecretRevoked: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const identityUniversalAuthClientSecretSchema = new Schema(
|
||||||
|
{
|
||||||
|
identity: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Identity",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
identityUniversalAuth: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "IdentityUniversalAuth",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
clientSecretPrefix: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
clientSecretHash: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
clientSecretLastUsedAt: {
|
||||||
|
type: Date,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
clientSecretNumUses: {
|
||||||
|
// number of times client secret has been used
|
||||||
|
// in login operation
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
clientSecretNumUsesLimit: {
|
||||||
|
// number of times client secret can be used for
|
||||||
|
// a login operation
|
||||||
|
type: Number,
|
||||||
|
default: 0, // default: used as many times as needed
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
clientSecretTTL: {
|
||||||
|
type: Number,
|
||||||
|
default: 0, // default: does not expire
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
isClientSecretRevoked: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
identityUniversalAuthClientSecretSchema.index(
|
||||||
|
{ identityUniversalAuth: 1, isClientSecretRevoked: 1 }
|
||||||
|
);
|
||||||
|
|
||||||
|
export const IdentityUniversalAuthClientSecret = model<IIdentityUniversalAuthClientSecret>("IdentityUniversalAuthClientSecret", identityUniversalAuthClientSecretSchema);
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export interface IIncidentContactOrg {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
email: string;
|
||||||
|
organization: Types.ObjectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const incidentContactOrgSchema = new Schema<IIncidentContactOrg>(
|
||||||
|
{
|
||||||
|
email: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
organization: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Organization",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const IncidentContactOrg = model<IIncidentContactOrg>(
|
||||||
|
"IncidentContactOrg",
|
||||||
|
incidentContactOrgSchema
|
||||||
|
);
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
export * from "./backupPrivateKey";
|
||||||
|
export * from "./bot";
|
||||||
|
export * from "./botOrg";
|
||||||
|
export * from "./botKey";
|
||||||
|
export * from "./incidentContactOrg";
|
||||||
|
export * from "./integration/integration";
|
||||||
|
export * from "./integrationAuth";
|
||||||
|
export * from "./key";
|
||||||
|
export * from "./membership";
|
||||||
|
export * from "./membershipOrg";
|
||||||
|
export * from "./organization";
|
||||||
|
export * from "./secret";
|
||||||
|
export * from "./tag";
|
||||||
|
export * from "./folder";
|
||||||
|
export * from "./secretImports";
|
||||||
|
export * from "./secretBlindIndexData";
|
||||||
|
export * from "./serviceToken"; // TODO: deprecate
|
||||||
|
export * from "./tokenData";
|
||||||
|
export * from "./user";
|
||||||
|
export * from "./userAction";
|
||||||
|
export * from "./workspace";
|
||||||
|
export * from "./serviceTokenData"; // TODO: deprecate
|
||||||
|
|
||||||
|
// new
|
||||||
|
export * from "./identity";
|
||||||
|
export * from "./identityMembership";
|
||||||
|
export * from "./identityMembershipOrg";
|
||||||
|
export * from "./identityUniversalAuth";
|
||||||
|
export * from "./identityUniversalAuthClientSecret";
|
||||||
|
export * from "./identityAccessToken";
|
||||||
|
|
||||||
|
export * from "./apiKeyData"; // TODO: deprecate
|
||||||
|
export * from "./apiKeyDataV2";
|
||||||
|
export * from "./loginSRPDetail";
|
||||||
|
export * from "./tokenVersion";
|
||||||
|
export * from "./webhooks";
|
||||||
|
|
||||||
|
export * from "./secretSnapshot";
|
||||||
|
export * from "./secretVersion";
|
||||||
|
export * from "./folderVersion";
|
||||||
|
export * from "./role";
|
||||||
|
export * from "./ssoConfig";
|
||||||
|
export * from "./trustedIp";
|
||||||
|
export * from "./auditLog";
|
||||||
|
export * from "./gitRisks";
|
||||||
|
export * from "./gitAppOrganizationInstallation";
|
||||||
|
export * from "./gitAppInstallationSession";
|
||||||
|
export * from "./secretApprovalPolicy";
|
||||||
|
export * from "./secretApprovalRequest";
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from "./integration";
|
||||||
@@ -0,0 +1,216 @@
|
|||||||
|
import {
|
||||||
|
INTEGRATION_AWS_PARAMETER_STORE,
|
||||||
|
INTEGRATION_AWS_SECRET_MANAGER,
|
||||||
|
INTEGRATION_AZURE_KEY_VAULT,
|
||||||
|
INTEGRATION_BITBUCKET,
|
||||||
|
INTEGRATION_CHECKLY,
|
||||||
|
INTEGRATION_CIRCLECI,
|
||||||
|
INTEGRATION_CLOUDFLARE_PAGES,
|
||||||
|
INTEGRATION_CLOUDFLARE_WORKERS,
|
||||||
|
INTEGRATION_CLOUD_66,
|
||||||
|
INTEGRATION_CODEFRESH,
|
||||||
|
INTEGRATION_DIGITAL_OCEAN_APP_PLATFORM,
|
||||||
|
INTEGRATION_FLYIO,
|
||||||
|
INTEGRATION_GCP_SECRET_MANAGER,
|
||||||
|
INTEGRATION_GITHUB,
|
||||||
|
INTEGRATION_GITLAB,
|
||||||
|
INTEGRATION_HASHICORP_VAULT,
|
||||||
|
INTEGRATION_HASURA_CLOUD,
|
||||||
|
INTEGRATION_HEROKU,
|
||||||
|
INTEGRATION_LARAVELFORGE,
|
||||||
|
INTEGRATION_NETLIFY,
|
||||||
|
INTEGRATION_NORTHFLANK,
|
||||||
|
INTEGRATION_QOVERY,
|
||||||
|
INTEGRATION_RAILWAY,
|
||||||
|
INTEGRATION_RENDER,
|
||||||
|
INTEGRATION_SUPABASE,
|
||||||
|
INTEGRATION_TEAMCITY,
|
||||||
|
INTEGRATION_TERRAFORM_CLOUD,
|
||||||
|
INTEGRATION_TRAVISCI,
|
||||||
|
INTEGRATION_VERCEL,
|
||||||
|
INTEGRATION_WINDMILL
|
||||||
|
} from "../../variables";
|
||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
import { Metadata } from "./types";
|
||||||
|
|
||||||
|
export interface IIntegration {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
workspace: Types.ObjectId;
|
||||||
|
environment: string;
|
||||||
|
isActive: boolean;
|
||||||
|
url: string;
|
||||||
|
app: string;
|
||||||
|
appId: string;
|
||||||
|
owner: string;
|
||||||
|
targetEnvironment: string;
|
||||||
|
targetEnvironmentId: string;
|
||||||
|
targetService: string;
|
||||||
|
targetServiceId: string;
|
||||||
|
path: string;
|
||||||
|
region: string;
|
||||||
|
scope: string;
|
||||||
|
secretPath: string;
|
||||||
|
integration:
|
||||||
|
| "azure-key-vault"
|
||||||
|
| "aws-parameter-store"
|
||||||
|
| "aws-secret-manager"
|
||||||
|
| "heroku"
|
||||||
|
| "vercel"
|
||||||
|
| "netlify"
|
||||||
|
| "github"
|
||||||
|
| "gitlab"
|
||||||
|
| "render"
|
||||||
|
| "railway"
|
||||||
|
| "flyio"
|
||||||
|
| "circleci"
|
||||||
|
| "laravel-forge"
|
||||||
|
| "travisci"
|
||||||
|
| "supabase"
|
||||||
|
| "checkly"
|
||||||
|
| "qovery"
|
||||||
|
| "terraform-cloud"
|
||||||
|
| "teamcity"
|
||||||
|
| "hashicorp-vault"
|
||||||
|
| "cloudflare-pages"
|
||||||
|
| "cloudflare-workers"
|
||||||
|
| "bitbucket"
|
||||||
|
| "codefresh"
|
||||||
|
| "digital-ocean-app-platform"
|
||||||
|
| "cloud-66"
|
||||||
|
| "northflank"
|
||||||
|
| "windmill"
|
||||||
|
| "gcp-secret-manager"
|
||||||
|
| "hasura-cloud";
|
||||||
|
integrationAuth: Types.ObjectId;
|
||||||
|
metadata: Metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
const integrationSchema = new Schema<IIntegration>(
|
||||||
|
{
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Workspace",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
environment: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
isActive: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
// for custom self-hosted integrations (e.g. self-hosted GitHub enterprise)
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
app: {
|
||||||
|
// name of app in provider
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
appId: {
|
||||||
|
// id of app in provider
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
targetEnvironment: {
|
||||||
|
// target environment
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
targetEnvironmentId: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
targetService: {
|
||||||
|
// railway-specific service
|
||||||
|
// qovery-specific project
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
targetServiceId: {
|
||||||
|
// railway-specific service
|
||||||
|
// qovery specific project
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
owner: {
|
||||||
|
// github-specific repo owner-login
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
path: {
|
||||||
|
// aws-parameter-store-specific path
|
||||||
|
// (also) vercel preview-branch
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
region: {
|
||||||
|
// aws-parameter-store-specific path
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
scope: {
|
||||||
|
// qovery-specific scope
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
integration: {
|
||||||
|
type: String,
|
||||||
|
enum: [
|
||||||
|
INTEGRATION_AZURE_KEY_VAULT,
|
||||||
|
INTEGRATION_AWS_PARAMETER_STORE,
|
||||||
|
INTEGRATION_AWS_SECRET_MANAGER,
|
||||||
|
INTEGRATION_HEROKU,
|
||||||
|
INTEGRATION_VERCEL,
|
||||||
|
INTEGRATION_NETLIFY,
|
||||||
|
INTEGRATION_GITHUB,
|
||||||
|
INTEGRATION_GITLAB,
|
||||||
|
INTEGRATION_RENDER,
|
||||||
|
INTEGRATION_RAILWAY,
|
||||||
|
INTEGRATION_FLYIO,
|
||||||
|
INTEGRATION_CIRCLECI,
|
||||||
|
INTEGRATION_LARAVELFORGE,
|
||||||
|
INTEGRATION_TRAVISCI,
|
||||||
|
INTEGRATION_SUPABASE,
|
||||||
|
INTEGRATION_CHECKLY,
|
||||||
|
INTEGRATION_QOVERY,
|
||||||
|
INTEGRATION_TERRAFORM_CLOUD,
|
||||||
|
INTEGRATION_TEAMCITY,
|
||||||
|
INTEGRATION_HASHICORP_VAULT,
|
||||||
|
INTEGRATION_CLOUDFLARE_PAGES,
|
||||||
|
INTEGRATION_CLOUDFLARE_WORKERS,
|
||||||
|
INTEGRATION_CODEFRESH,
|
||||||
|
INTEGRATION_WINDMILL,
|
||||||
|
INTEGRATION_BITBUCKET,
|
||||||
|
INTEGRATION_DIGITAL_OCEAN_APP_PLATFORM,
|
||||||
|
INTEGRATION_CLOUD_66,
|
||||||
|
INTEGRATION_NORTHFLANK,
|
||||||
|
INTEGRATION_GCP_SECRET_MANAGER,
|
||||||
|
INTEGRATION_HASURA_CLOUD
|
||||||
|
],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
integrationAuth: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "IntegrationAuth",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretPath: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
default: "/"
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
type: Schema.Types.Mixed,
|
||||||
|
default: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const Integration = model<IIntegration>("Integration", integrationSchema);
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export type Metadata = {
|
||||||
|
secretPrefix?: string;
|
||||||
|
secretSuffix?: string;
|
||||||
|
secretGCPLabel?: {
|
||||||
|
labelName: string;
|
||||||
|
labelValue: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from "./integrationAuth";
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
import {
|
||||||
|
ALGORITHM_AES_256_GCM,
|
||||||
|
ENCODING_SCHEME_BASE64,
|
||||||
|
ENCODING_SCHEME_UTF8,
|
||||||
|
INTEGRATION_AWS_PARAMETER_STORE,
|
||||||
|
INTEGRATION_AWS_SECRET_MANAGER,
|
||||||
|
INTEGRATION_AZURE_KEY_VAULT,
|
||||||
|
INTEGRATION_BITBUCKET,
|
||||||
|
INTEGRATION_CIRCLECI,
|
||||||
|
INTEGRATION_CLOUDFLARE_PAGES,
|
||||||
|
INTEGRATION_CLOUDFLARE_WORKERS,
|
||||||
|
INTEGRATION_CLOUD_66,
|
||||||
|
INTEGRATION_CODEFRESH,
|
||||||
|
INTEGRATION_DIGITAL_OCEAN_APP_PLATFORM,
|
||||||
|
INTEGRATION_FLYIO,
|
||||||
|
INTEGRATION_GCP_SECRET_MANAGER,
|
||||||
|
INTEGRATION_GITHUB,
|
||||||
|
INTEGRATION_GITLAB,
|
||||||
|
INTEGRATION_HASHICORP_VAULT,
|
||||||
|
INTEGRATION_HASURA_CLOUD,
|
||||||
|
INTEGRATION_HEROKU,
|
||||||
|
INTEGRATION_LARAVELFORGE,
|
||||||
|
INTEGRATION_NETLIFY,
|
||||||
|
INTEGRATION_NORTHFLANK,
|
||||||
|
INTEGRATION_RAILWAY,
|
||||||
|
INTEGRATION_RENDER,
|
||||||
|
INTEGRATION_SUPABASE,
|
||||||
|
INTEGRATION_TEAMCITY,
|
||||||
|
INTEGRATION_TERRAFORM_CLOUD,
|
||||||
|
INTEGRATION_TRAVISCI,
|
||||||
|
INTEGRATION_VERCEL,
|
||||||
|
INTEGRATION_WINDMILL
|
||||||
|
} from "../../variables";
|
||||||
|
import { Document, Schema, Types, model } from "mongoose";
|
||||||
|
import { IntegrationAuthMetadata } from "./types";
|
||||||
|
|
||||||
|
export interface IIntegrationAuth extends Document {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
workspace: Types.ObjectId;
|
||||||
|
integration:
|
||||||
|
| "heroku"
|
||||||
|
| "vercel"
|
||||||
|
| "netlify"
|
||||||
|
| "github"
|
||||||
|
| "gitlab"
|
||||||
|
| "render"
|
||||||
|
| "railway"
|
||||||
|
| "flyio"
|
||||||
|
| "azure-key-vault"
|
||||||
|
| "laravel-forge"
|
||||||
|
| "circleci"
|
||||||
|
| "travisci"
|
||||||
|
| "supabase"
|
||||||
|
| "aws-parameter-store"
|
||||||
|
| "aws-secret-manager"
|
||||||
|
| "checkly"
|
||||||
|
| "qovery"
|
||||||
|
| "cloudflare-pages"
|
||||||
|
| "cloudflare-workers"
|
||||||
|
| "codefresh"
|
||||||
|
| "digital-ocean-app-platform"
|
||||||
|
| "bitbucket"
|
||||||
|
| "cloud-66"
|
||||||
|
| "terraform-cloud"
|
||||||
|
| "teamcity"
|
||||||
|
| "northflank"
|
||||||
|
| "windmill"
|
||||||
|
| "gcp-secret-manager"
|
||||||
|
| "hasura-cloud";
|
||||||
|
teamId: string;
|
||||||
|
accountId: string;
|
||||||
|
url: string;
|
||||||
|
namespace: string;
|
||||||
|
refreshCiphertext?: string;
|
||||||
|
refreshIV?: string;
|
||||||
|
refreshTag?: string;
|
||||||
|
accessIdCiphertext?: string;
|
||||||
|
accessIdIV?: string;
|
||||||
|
accessIdTag?: string;
|
||||||
|
accessCiphertext?: string;
|
||||||
|
accessIV?: string;
|
||||||
|
accessTag?: string;
|
||||||
|
algorithm?: "aes-256-gcm";
|
||||||
|
keyEncoding?: "utf8" | "base64";
|
||||||
|
accessExpiresAt?: Date;
|
||||||
|
metadata?: IntegrationAuthMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
const integrationAuthSchema = new Schema<IIntegrationAuth>(
|
||||||
|
{
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Workspace",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
integration: {
|
||||||
|
type: String,
|
||||||
|
enum: [
|
||||||
|
INTEGRATION_AZURE_KEY_VAULT,
|
||||||
|
INTEGRATION_AWS_PARAMETER_STORE,
|
||||||
|
INTEGRATION_AWS_SECRET_MANAGER,
|
||||||
|
INTEGRATION_HEROKU,
|
||||||
|
INTEGRATION_VERCEL,
|
||||||
|
INTEGRATION_NETLIFY,
|
||||||
|
INTEGRATION_GITHUB,
|
||||||
|
INTEGRATION_GITLAB,
|
||||||
|
INTEGRATION_RENDER,
|
||||||
|
INTEGRATION_RAILWAY,
|
||||||
|
INTEGRATION_FLYIO,
|
||||||
|
INTEGRATION_CIRCLECI,
|
||||||
|
INTEGRATION_LARAVELFORGE,
|
||||||
|
INTEGRATION_TRAVISCI,
|
||||||
|
INTEGRATION_TEAMCITY,
|
||||||
|
INTEGRATION_SUPABASE,
|
||||||
|
INTEGRATION_TERRAFORM_CLOUD,
|
||||||
|
INTEGRATION_HASHICORP_VAULT,
|
||||||
|
INTEGRATION_CLOUDFLARE_PAGES,
|
||||||
|
INTEGRATION_CLOUDFLARE_WORKERS,
|
||||||
|
INTEGRATION_CODEFRESH,
|
||||||
|
INTEGRATION_WINDMILL,
|
||||||
|
INTEGRATION_BITBUCKET,
|
||||||
|
INTEGRATION_DIGITAL_OCEAN_APP_PLATFORM,
|
||||||
|
INTEGRATION_CLOUD_66,
|
||||||
|
INTEGRATION_NORTHFLANK,
|
||||||
|
INTEGRATION_GCP_SECRET_MANAGER,
|
||||||
|
INTEGRATION_HASURA_CLOUD
|
||||||
|
],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
teamId: {
|
||||||
|
// vercel-specific integration param
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
// for any self-hosted integrations (e.g. self-hosted hashicorp-vault)
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
namespace: {
|
||||||
|
// hashicorp-vault-specific integration param
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
accountId: {
|
||||||
|
// netlify-specific integration param
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
refreshCiphertext: {
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
refreshIV: {
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
refreshTag: {
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
accessIdCiphertext: {
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
accessIdIV: {
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
accessIdTag: {
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
accessCiphertext: {
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
accessIV: {
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
accessTag: {
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
accessExpiresAt: {
|
||||||
|
type: Date,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
algorithm: {
|
||||||
|
// the encryption algorithm used
|
||||||
|
type: String,
|
||||||
|
enum: [ALGORITHM_AES_256_GCM],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
keyEncoding: {
|
||||||
|
type: String,
|
||||||
|
enum: [ENCODING_SCHEME_UTF8, ENCODING_SCHEME_BASE64],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
type: Schema.Types.Mixed
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const IntegrationAuth = model<IIntegrationAuth>("IntegrationAuth", integrationAuthSchema);
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
interface GCPIntegrationAuthMetadata {
|
||||||
|
authMethod: "oauth2" | "serviceAccount"
|
||||||
|
}
|
||||||
|
|
||||||
|
export type IntegrationAuthMetadata = GCPIntegrationAuthMetadata;
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export interface IKey {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
encryptedKey: string;
|
||||||
|
nonce: string;
|
||||||
|
sender: Types.ObjectId;
|
||||||
|
receiver: Types.ObjectId;
|
||||||
|
workspace: Types.ObjectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const keySchema = new Schema<IKey>(
|
||||||
|
{
|
||||||
|
encryptedKey: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
nonce: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
sender: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "User",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
receiver: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "User",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Workspace",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export const Key = model<IKey>("Key", keySchema);
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import mongoose, { Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export interface ILoginSRPDetail {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
clientPublicKey: string;
|
||||||
|
email: string;
|
||||||
|
serverBInt: mongoose.Schema.Types.Buffer;
|
||||||
|
userId: string;
|
||||||
|
expireAt: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
const loginSRPDetailSchema = new Schema<ILoginSRPDetail>(
|
||||||
|
{
|
||||||
|
clientPublicKey: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
email: {
|
||||||
|
type: String,
|
||||||
|
unique: true,
|
||||||
|
},
|
||||||
|
serverBInt: { type: mongoose.Schema.Types.Buffer },
|
||||||
|
expireAt: { type: Date },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const LoginSRPDetail = model("LoginSRPDetail", loginSRPDetailSchema);
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
import { ADMIN, CUSTOM, MEMBER, NO_ACCESS, VIEWER } from "../variables";
|
||||||
|
|
||||||
|
export interface IMembershipPermission {
|
||||||
|
environmentSlug: string;
|
||||||
|
ability: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IMembership {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
user: Types.ObjectId;
|
||||||
|
inviteEmail?: string;
|
||||||
|
workspace: Types.ObjectId;
|
||||||
|
role: "admin" | "member" | "viewer" | "no-access" | "custom";
|
||||||
|
customRole: Types.ObjectId;
|
||||||
|
deniedPermissions: IMembershipPermission[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const membershipSchema = new Schema<IMembership>(
|
||||||
|
{
|
||||||
|
user: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "User"
|
||||||
|
},
|
||||||
|
inviteEmail: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Workspace",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
deniedPermissions: {
|
||||||
|
type: [
|
||||||
|
{
|
||||||
|
environmentSlug: String,
|
||||||
|
ability: {
|
||||||
|
type: String,
|
||||||
|
enum: ["read", "write"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
role: {
|
||||||
|
type: String,
|
||||||
|
enum: [ADMIN, MEMBER, VIEWER, NO_ACCESS, CUSTOM],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
customRole: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Role"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const Membership = model<IMembership>("Membership", membershipSchema);
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { Document, Schema, Types, model } from "mongoose";
|
||||||
|
import { ACCEPTED, ADMIN, CUSTOM, INVITED, MEMBER, NO_ACCESS } from "../variables";
|
||||||
|
|
||||||
|
export interface IMembershipOrg extends Document {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
user: Types.ObjectId;
|
||||||
|
inviteEmail: string;
|
||||||
|
organization: Types.ObjectId;
|
||||||
|
role: "admin" | "member" | "no-access" | "custom";
|
||||||
|
customRole: Types.ObjectId;
|
||||||
|
status: "invited" | "accepted";
|
||||||
|
}
|
||||||
|
|
||||||
|
const membershipOrgSchema = new Schema(
|
||||||
|
{
|
||||||
|
user: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "User"
|
||||||
|
},
|
||||||
|
inviteEmail: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
organization: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Organization"
|
||||||
|
},
|
||||||
|
role: {
|
||||||
|
type: String,
|
||||||
|
enum: [ADMIN, MEMBER, NO_ACCESS, CUSTOM],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
type: String,
|
||||||
|
enum: [INVITED, ACCEPTED],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
customRole: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Role"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const MembershipOrg = model<IMembershipOrg>("MembershipOrg", membershipOrgSchema);
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export interface IOrganization {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
name: string;
|
||||||
|
customerId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const organizationSchema = new Schema<IOrganization>(
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
customerId: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const Organization = model<IOrganization>("Organization", organizationSchema);
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export interface IRole {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
slug: string;
|
||||||
|
permissions: Array<unknown>;
|
||||||
|
workspace: Types.ObjectId;
|
||||||
|
organization: Types.ObjectId;
|
||||||
|
isOrgRole: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const roleSchema = new Schema<IRole>(
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
organization: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Organization",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Workspace"
|
||||||
|
},
|
||||||
|
isOrgRole: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
slug: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
permissions: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
roleSchema.index({ organization: 1, workspace: 1 });
|
||||||
|
|
||||||
|
export const Role = model<IRole>("Role", roleSchema);
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
import {
|
||||||
|
ALGORITHM_AES_256_GCM,
|
||||||
|
ENCODING_SCHEME_BASE64,
|
||||||
|
ENCODING_SCHEME_UTF8,
|
||||||
|
SECRET_PERSONAL,
|
||||||
|
SECRET_SHARED
|
||||||
|
} from "../variables";
|
||||||
|
|
||||||
|
export interface ISecret {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
version: number;
|
||||||
|
workspace: Types.ObjectId;
|
||||||
|
type: string;
|
||||||
|
user?: Types.ObjectId;
|
||||||
|
environment: string;
|
||||||
|
secretBlindIndex?: string;
|
||||||
|
secretKeyCiphertext: string;
|
||||||
|
secretKeyIV: string;
|
||||||
|
secretKeyTag: string;
|
||||||
|
secretKeyHash: string;
|
||||||
|
secretValueCiphertext: string;
|
||||||
|
secretValueIV: string;
|
||||||
|
secretValueTag: string;
|
||||||
|
secretValueHash: string;
|
||||||
|
secretCommentCiphertext?: string;
|
||||||
|
secretCommentIV?: string;
|
||||||
|
secretCommentTag?: string;
|
||||||
|
secretCommentHash?: string;
|
||||||
|
|
||||||
|
// ? NOTE: This works great for workspace-level reminders.
|
||||||
|
// ? If we want to do it on a user-basis, we should ideally have a seperate model for reminders.
|
||||||
|
secretReminderRepeatDays?: number | null;
|
||||||
|
secretReminderNote?: string | null;
|
||||||
|
|
||||||
|
skipMultilineEncoding?: boolean;
|
||||||
|
algorithm: "aes-256-gcm";
|
||||||
|
keyEncoding: "utf8" | "base64";
|
||||||
|
tags?: string[];
|
||||||
|
folder?: string;
|
||||||
|
metadata?: {
|
||||||
|
[key: string]: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const secretSchema = new Schema<ISecret>(
|
||||||
|
{
|
||||||
|
version: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Workspace",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
enum: [SECRET_SHARED, SECRET_PERSONAL],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
// user associated with the personal secret
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "User"
|
||||||
|
},
|
||||||
|
tags: {
|
||||||
|
ref: "Tag",
|
||||||
|
type: [Schema.Types.ObjectId],
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
environment: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretBlindIndex: {
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
secretKeyCiphertext: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretKeyIV: {
|
||||||
|
type: String, // symmetric
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretKeyTag: {
|
||||||
|
type: String, // symmetric
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretKeyHash: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
secretValueCiphertext: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretValueIV: {
|
||||||
|
type: String, // symmetric
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretValueTag: {
|
||||||
|
type: String, // symmetric
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretValueHash: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
secretCommentCiphertext: {
|
||||||
|
type: String,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
secretCommentIV: {
|
||||||
|
type: String, // symmetric
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
secretCommentTag: {
|
||||||
|
type: String, // symmetric
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
secretCommentHash: {
|
||||||
|
type: String,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
|
||||||
|
secretReminderRepeatDays: {
|
||||||
|
type: Number,
|
||||||
|
required: false,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
secretReminderNote: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
|
||||||
|
skipMultilineEncoding: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
|
||||||
|
algorithm: {
|
||||||
|
// the encryption algorithm used
|
||||||
|
type: String,
|
||||||
|
enum: [ALGORITHM_AES_256_GCM],
|
||||||
|
required: true,
|
||||||
|
default: ALGORITHM_AES_256_GCM
|
||||||
|
},
|
||||||
|
keyEncoding: {
|
||||||
|
type: String,
|
||||||
|
enum: [ENCODING_SCHEME_UTF8, ENCODING_SCHEME_BASE64],
|
||||||
|
required: true,
|
||||||
|
default: ENCODING_SCHEME_UTF8
|
||||||
|
},
|
||||||
|
folder: {
|
||||||
|
type: String,
|
||||||
|
default: "root"
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
type: Schema.Types.Mixed
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
secretSchema.index({ tags: 1 }, { background: true });
|
||||||
|
|
||||||
|
export const Secret = model<ISecret>("Secret", secretSchema);
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export interface ISecretApprovalPolicy {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
workspace: Types.ObjectId;
|
||||||
|
name: string;
|
||||||
|
environment: string;
|
||||||
|
secretPath?: string;
|
||||||
|
approvers: Types.ObjectId[];
|
||||||
|
approvals: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const secretApprovalPolicySchema = new Schema<ISecretApprovalPolicy>(
|
||||||
|
{
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Workspace",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
approvers: [
|
||||||
|
{
|
||||||
|
// user associated with the personal secret
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Membership"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
name: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
environment: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretPath: {
|
||||||
|
type: String,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
approvals: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const SecretApprovalPolicy = model<ISecretApprovalPolicy>(
|
||||||
|
"SecretApprovalPolicy",
|
||||||
|
secretApprovalPolicySchema
|
||||||
|
);
|
||||||
@@ -0,0 +1,203 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
import { customAlphabet } from "nanoid";
|
||||||
|
import {
|
||||||
|
ALGORITHM_AES_256_GCM,
|
||||||
|
ENCODING_SCHEME_BASE64,
|
||||||
|
ENCODING_SCHEME_UTF8
|
||||||
|
} from "../../variables";
|
||||||
|
|
||||||
|
export enum ApprovalStatus {
|
||||||
|
PENDING = "pending",
|
||||||
|
APPROVED = "approved",
|
||||||
|
REJECTED = "rejected"
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum CommitType {
|
||||||
|
DELETE = "delete",
|
||||||
|
UPDATE = "update",
|
||||||
|
CREATE = "create"
|
||||||
|
}
|
||||||
|
|
||||||
|
const SLUG_ALPHABETS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||||
|
const nanoId = customAlphabet(SLUG_ALPHABETS, 10);
|
||||||
|
|
||||||
|
export interface ISecretApprovalSecChange {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
version: number;
|
||||||
|
secretBlindIndex?: string;
|
||||||
|
secretKeyCiphertext: string;
|
||||||
|
secretKeyIV: string;
|
||||||
|
secretKeyTag: string;
|
||||||
|
secretValueCiphertext: string;
|
||||||
|
secretValueIV: string;
|
||||||
|
secretValueTag: string;
|
||||||
|
secretCommentIV?: string;
|
||||||
|
secretCommentTag?: string;
|
||||||
|
secretCommentCiphertext?: string;
|
||||||
|
skipMultilineEncoding?: boolean;
|
||||||
|
algorithm?: "aes-256-gcm";
|
||||||
|
keyEncoding?: "utf8" | "base64";
|
||||||
|
tags?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ISecretCommits<T = Types.ObjectId, J = Types.ObjectId> = Array<
|
||||||
|
| {
|
||||||
|
newVersion: ISecretApprovalSecChange;
|
||||||
|
op: CommitType.CREATE;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
// secret is recorded to get the latest version, we can keep ref to secret for pulling change as it will also get changed
|
||||||
|
// on merge
|
||||||
|
secretVersion: J;
|
||||||
|
secret: T;
|
||||||
|
newVersion: Partial<Omit<ISecretApprovalSecChange, "_id">> & { _id: Types.ObjectId };
|
||||||
|
op: CommitType.UPDATE;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
secret: T;
|
||||||
|
secretVersion: J;
|
||||||
|
op: CommitType.DELETE;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
export interface ISecretApprovalRequest {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
committer: Types.ObjectId;
|
||||||
|
slug: string;
|
||||||
|
statusChangeBy: Types.ObjectId;
|
||||||
|
reviewers: {
|
||||||
|
member: Types.ObjectId;
|
||||||
|
status: ApprovalStatus;
|
||||||
|
}[];
|
||||||
|
workspace: Types.ObjectId;
|
||||||
|
environment: string;
|
||||||
|
folderId: string;
|
||||||
|
hasMerged: boolean;
|
||||||
|
status: "open" | "close";
|
||||||
|
policy: Types.ObjectId;
|
||||||
|
commits: ISecretCommits;
|
||||||
|
conflicts: Array<{ secretId: string; op: CommitType }>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const secretApprovalSecretChangeSchema = new Schema<ISecretApprovalSecChange>({
|
||||||
|
version: {
|
||||||
|
type: Number,
|
||||||
|
default: 1,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretBlindIndex: {
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
secretKeyCiphertext: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretKeyIV: {
|
||||||
|
type: String, // symmetric
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretKeyTag: {
|
||||||
|
type: String, // symmetric
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretValueCiphertext: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretValueIV: {
|
||||||
|
type: String, // symmetric
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretValueTag: {
|
||||||
|
type: String, // symmetric
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
skipMultilineEncoding: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
algorithm: {
|
||||||
|
// the encryption algorithm used
|
||||||
|
type: String,
|
||||||
|
enum: [ALGORITHM_AES_256_GCM],
|
||||||
|
required: true,
|
||||||
|
default: ALGORITHM_AES_256_GCM
|
||||||
|
},
|
||||||
|
keyEncoding: {
|
||||||
|
type: String,
|
||||||
|
enum: [ENCODING_SCHEME_UTF8, ENCODING_SCHEME_BASE64],
|
||||||
|
required: true,
|
||||||
|
default: ENCODING_SCHEME_UTF8
|
||||||
|
},
|
||||||
|
tags: {
|
||||||
|
ref: "Tag",
|
||||||
|
type: [Schema.Types.ObjectId],
|
||||||
|
default: []
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const secretApprovalRequestSchema = new Schema<ISecretApprovalRequest>(
|
||||||
|
{
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Workspace",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
environment: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
folderId: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
default: "root"
|
||||||
|
},
|
||||||
|
slug: {
|
||||||
|
type: String,
|
||||||
|
default: () => nanoId()
|
||||||
|
},
|
||||||
|
reviewers: {
|
||||||
|
type: [
|
||||||
|
{
|
||||||
|
member: {
|
||||||
|
// user associated with the personal secret
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Membership"
|
||||||
|
},
|
||||||
|
status: { type: String, enum: ApprovalStatus, default: ApprovalStatus.PENDING }
|
||||||
|
}
|
||||||
|
],
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
policy: { type: Schema.Types.ObjectId, ref: "SecretApprovalPolicy" },
|
||||||
|
hasMerged: { type: Boolean, default: false },
|
||||||
|
status: { type: String, enum: ["close", "open"], default: "open" },
|
||||||
|
committer: { type: Schema.Types.ObjectId, ref: "Membership" },
|
||||||
|
statusChangeBy: { type: Schema.Types.ObjectId, ref: "Membership" },
|
||||||
|
commits: [
|
||||||
|
{
|
||||||
|
secret: { type: Types.ObjectId, ref: "Secret" },
|
||||||
|
newVersion: secretApprovalSecretChangeSchema,
|
||||||
|
secretVersion: { type: Types.ObjectId, ref: "SecretVersion" },
|
||||||
|
op: { type: String, enum: [CommitType], required: true }
|
||||||
|
}
|
||||||
|
],
|
||||||
|
conflicts: {
|
||||||
|
type: [
|
||||||
|
{
|
||||||
|
secretId: { type: String, required: true },
|
||||||
|
op: { type: String, enum: [CommitType], required: true }
|
||||||
|
}
|
||||||
|
],
|
||||||
|
default: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const SecretApprovalRequest = model<ISecretApprovalRequest>(
|
||||||
|
"SecretApprovalRequest",
|
||||||
|
secretApprovalRequestSchema
|
||||||
|
);
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import { Document, Schema, Types, model } from "mongoose";
|
||||||
|
import {
|
||||||
|
ALGORITHM_AES_256_GCM,
|
||||||
|
ENCODING_SCHEME_BASE64,
|
||||||
|
ENCODING_SCHEME_UTF8,
|
||||||
|
} from "../variables";
|
||||||
|
|
||||||
|
export interface ISecretBlindIndexData extends Document {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
workspace: Types.ObjectId;
|
||||||
|
encryptedSaltCiphertext: string;
|
||||||
|
saltIV: string;
|
||||||
|
saltTag: string;
|
||||||
|
algorithm: "aes-256-gcm";
|
||||||
|
keyEncoding: "base64" | "utf8"
|
||||||
|
}
|
||||||
|
|
||||||
|
const secretBlindIndexDataSchema = new Schema<ISecretBlindIndexData>(
|
||||||
|
{
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Workspace",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
encryptedSaltCiphertext: { // TODO: make these select: false
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
saltIV: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
saltTag: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
algorithm: {
|
||||||
|
type: String,
|
||||||
|
enum: [ALGORITHM_AES_256_GCM],
|
||||||
|
required: true,
|
||||||
|
select: false,
|
||||||
|
},
|
||||||
|
keyEncoding: {
|
||||||
|
type: String,
|
||||||
|
enum: [
|
||||||
|
ENCODING_SCHEME_UTF8,
|
||||||
|
ENCODING_SCHEME_BASE64,
|
||||||
|
],
|
||||||
|
required: true,
|
||||||
|
select: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
secretBlindIndexDataSchema.index({ workspace: 1 });
|
||||||
|
|
||||||
|
export const SecretBlindIndexData = model<ISecretBlindIndexData>("SecretBlindIndexData", secretBlindIndexDataSchema);
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export interface ISecretImports {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
workspace: Types.ObjectId;
|
||||||
|
environment: string;
|
||||||
|
folderId: string;
|
||||||
|
imports: Array<{
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const secretImportSchema = new Schema<ISecretImports>(
|
||||||
|
{
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Workspace",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
environment: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
folderId: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
default: "root"
|
||||||
|
},
|
||||||
|
imports: {
|
||||||
|
type: [
|
||||||
|
{
|
||||||
|
environment: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretPath: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
default: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const SecretImport = model<ISecretImports>("SecretImports", secretImportSchema);
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export interface ISecretSnapshot {
|
||||||
|
workspace: Types.ObjectId;
|
||||||
|
environment: string;
|
||||||
|
folderId: string | "root";
|
||||||
|
version: number;
|
||||||
|
secretVersions: Types.ObjectId[];
|
||||||
|
folderVersion: Types.ObjectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const secretSnapshotSchema = new Schema<ISecretSnapshot>(
|
||||||
|
{
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Workspace",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
environment: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
folderId: {
|
||||||
|
type: String,
|
||||||
|
default: "root",
|
||||||
|
},
|
||||||
|
version: {
|
||||||
|
type: Number,
|
||||||
|
default: 1,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
secretVersions: [
|
||||||
|
{
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "SecretVersion",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
folderVersion: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "FolderVersion",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const SecretSnapshot = model<ISecretSnapshot>(
|
||||||
|
"SecretSnapshot",
|
||||||
|
secretSnapshotSchema
|
||||||
|
);
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
import {
|
||||||
|
ALGORITHM_AES_256_GCM,
|
||||||
|
ENCODING_SCHEME_BASE64,
|
||||||
|
ENCODING_SCHEME_UTF8,
|
||||||
|
SECRET_PERSONAL,
|
||||||
|
SECRET_SHARED
|
||||||
|
} from "../../variables";
|
||||||
|
|
||||||
|
export interface ISecretVersion {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
secret: Types.ObjectId;
|
||||||
|
version: number;
|
||||||
|
workspace: Types.ObjectId; // new
|
||||||
|
type: string; // new
|
||||||
|
user?: Types.ObjectId; // new
|
||||||
|
environment: string; // new
|
||||||
|
isDeleted: boolean;
|
||||||
|
secretBlindIndex?: string;
|
||||||
|
secretKeyCiphertext: string;
|
||||||
|
secretKeyIV: string;
|
||||||
|
secretKeyTag: string;
|
||||||
|
secretValueCiphertext: string;
|
||||||
|
secretValueIV: string;
|
||||||
|
secretValueTag: string;
|
||||||
|
skipMultilineEncoding?: boolean;
|
||||||
|
algorithm: "aes-256-gcm";
|
||||||
|
keyEncoding: "utf8" | "base64";
|
||||||
|
createdAt: string;
|
||||||
|
folder?: string;
|
||||||
|
tags?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const secretVersionSchema = new Schema<ISecretVersion>(
|
||||||
|
{
|
||||||
|
secret: {
|
||||||
|
// could be deleted
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Secret",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
version: {
|
||||||
|
type: Number,
|
||||||
|
default: 1,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Workspace",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
enum: [SECRET_SHARED, SECRET_PERSONAL],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
// user associated with the personal secret
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "User"
|
||||||
|
},
|
||||||
|
environment: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
isDeleted: {
|
||||||
|
// consider removing field
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretBlindIndex: {
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
secretKeyCiphertext: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretKeyIV: {
|
||||||
|
type: String, // symmetric
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretKeyTag: {
|
||||||
|
type: String, // symmetric
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretValueCiphertext: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretValueIV: {
|
||||||
|
type: String, // symmetric
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretValueTag: {
|
||||||
|
type: String, // symmetric
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
skipMultilineEncoding: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
algorithm: {
|
||||||
|
// the encryption algorithm used
|
||||||
|
type: String,
|
||||||
|
enum: [ALGORITHM_AES_256_GCM],
|
||||||
|
required: true,
|
||||||
|
default: ALGORITHM_AES_256_GCM
|
||||||
|
},
|
||||||
|
keyEncoding: {
|
||||||
|
type: String,
|
||||||
|
enum: [ENCODING_SCHEME_UTF8, ENCODING_SCHEME_BASE64],
|
||||||
|
required: true,
|
||||||
|
default: ENCODING_SCHEME_UTF8
|
||||||
|
},
|
||||||
|
folder: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
tags: {
|
||||||
|
ref: "Tag",
|
||||||
|
type: [Schema.Types.ObjectId],
|
||||||
|
default: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const SecretVersion = model<ISecretVersion>("SecretVersion", secretVersionSchema);
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export interface IServerConfig {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
initialized: boolean;
|
||||||
|
allowSignUp: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const serverConfigSchema = new Schema<IServerConfig>(
|
||||||
|
{
|
||||||
|
initialized: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
allowSignUp: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const ServerConfig = model<IServerConfig>("ServerConfig", serverConfigSchema);
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
// TODO: deprecate
|
||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
export interface IServiceToken {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
name: string;
|
||||||
|
user: Types.ObjectId;
|
||||||
|
workspace: Types.ObjectId;
|
||||||
|
environment: string;
|
||||||
|
expiresAt: Date;
|
||||||
|
publicKey: string;
|
||||||
|
encryptedKey: string;
|
||||||
|
nonce: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const serviceTokenSchema = new Schema<IServiceToken>(
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
// token issuer
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "User",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Workspace",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
environment: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
expiresAt: {
|
||||||
|
type: Date,
|
||||||
|
},
|
||||||
|
publicKey: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
select: true,
|
||||||
|
},
|
||||||
|
encryptedKey: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
select: true,
|
||||||
|
},
|
||||||
|
nonce: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
select: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const ServiceToken = model<IServiceToken>("ServiceToken", serviceTokenSchema);
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
// TODO: deprecate
|
||||||
|
import { Document, Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export interface IServiceTokenData extends Document {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
name: string;
|
||||||
|
workspace: Types.ObjectId;
|
||||||
|
scopes: Array<{
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
}>;
|
||||||
|
user: Types.ObjectId;
|
||||||
|
serviceAccount: Types.ObjectId;
|
||||||
|
lastUsed: Date;
|
||||||
|
expiresAt: Date;
|
||||||
|
secretHash: string;
|
||||||
|
encryptedKey: string;
|
||||||
|
iv: string;
|
||||||
|
tag: string;
|
||||||
|
permissions: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const serviceTokenDataSchema = new Schema<IServiceTokenData>(
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Workspace",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
scopes: {
|
||||||
|
type: [
|
||||||
|
{
|
||||||
|
environment: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretPath: {
|
||||||
|
type: String,
|
||||||
|
default: "/",
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "User",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
serviceAccount: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "ServiceAccount"
|
||||||
|
},
|
||||||
|
lastUsed: {
|
||||||
|
type: Date
|
||||||
|
},
|
||||||
|
expiresAt: {
|
||||||
|
type: Date
|
||||||
|
},
|
||||||
|
secretHash: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
encryptedKey: {
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
iv: {
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
tag: {
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
permissions: {
|
||||||
|
type: [String],
|
||||||
|
enum: ["read", "write"],
|
||||||
|
default: ["read"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const ServiceTokenData = model<IServiceTokenData>("ServiceTokenData", serviceTokenDataSchema);
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export enum AuthProvider {
|
||||||
|
OKTA_SAML = "okta-saml",
|
||||||
|
AZURE_SAML = "azure-saml",
|
||||||
|
JUMPCLOUD_SAML = "jumpcloud-saml"
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ISSOConfig {
|
||||||
|
organization: Types.ObjectId;
|
||||||
|
authProvider: AuthProvider;
|
||||||
|
isActive: boolean;
|
||||||
|
encryptedEntryPoint: string;
|
||||||
|
entryPointIV: string;
|
||||||
|
entryPointTag: string;
|
||||||
|
encryptedIssuer: string;
|
||||||
|
issuerIV: string;
|
||||||
|
issuerTag: string;
|
||||||
|
encryptedCert: string;
|
||||||
|
certIV: string;
|
||||||
|
certTag: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ssoConfigSchema = new Schema<ISSOConfig>(
|
||||||
|
{
|
||||||
|
organization: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Organization"
|
||||||
|
},
|
||||||
|
authProvider: {
|
||||||
|
type: String,
|
||||||
|
enum: AuthProvider,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
isActive: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
encryptedEntryPoint: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
entryPointIV: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
entryPointTag: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
encryptedIssuer: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
issuerIV: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
issuerTag: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
encryptedCert: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
certIV: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
certTag: {
|
||||||
|
type: String
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const SSOConfig = model<ISSOConfig>("SSOConfig", ssoConfigSchema);
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export interface ITag {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
name: string;
|
||||||
|
tagColor: string;
|
||||||
|
slug: string;
|
||||||
|
user: Types.ObjectId;
|
||||||
|
workspace: Types.ObjectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tagSchema = new Schema<ITag>(
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
trim: true,
|
||||||
|
},
|
||||||
|
tagColor: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
trim: true,
|
||||||
|
},
|
||||||
|
slug: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
trim: true,
|
||||||
|
lowercase: true,
|
||||||
|
validate: [
|
||||||
|
function (value: any) {
|
||||||
|
return value.indexOf(" ") === -1;
|
||||||
|
},
|
||||||
|
"slug cannot contain spaces",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "User",
|
||||||
|
},
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Workspace",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
tagSchema.index({ slug: 1, workspace: 1 }, { unique: true })
|
||||||
|
tagSchema.index({ workspace: 1 })
|
||||||
|
|
||||||
|
export const Tag = model<ITag>("Tag", tagSchema);
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { Schema, model } from "mongoose";
|
||||||
|
|
||||||
|
export interface IToken {
|
||||||
|
email: string;
|
||||||
|
token: string;
|
||||||
|
createdAt: Date;
|
||||||
|
ttl: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tokenSchema = new Schema<IToken>({
|
||||||
|
email: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
token: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
createdAt: {
|
||||||
|
type: Date,
|
||||||
|
default: Date.now,
|
||||||
|
},
|
||||||
|
ttl: {
|
||||||
|
type: Number,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
tokenSchema.index({ email: 1 });
|
||||||
|
|
||||||
|
export const Token = model<IToken>("Token", tokenSchema);
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export interface ITokenData {
|
||||||
|
type: string;
|
||||||
|
email?: string;
|
||||||
|
phoneNumber?: string;
|
||||||
|
organization?: Types.ObjectId;
|
||||||
|
tokenHash: string;
|
||||||
|
triesLeft?: number;
|
||||||
|
expiresAt: Date;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tokenDataSchema = new Schema<ITokenData>({
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
enum: [
|
||||||
|
"emailConfirmation",
|
||||||
|
"emailMfa",
|
||||||
|
"organizationInvitation",
|
||||||
|
"passwordReset",
|
||||||
|
],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
email: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
phoneNumber: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
organization: { // organizationInvitation-specific field
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Organization",
|
||||||
|
},
|
||||||
|
tokenHash: {
|
||||||
|
type: String,
|
||||||
|
select: false,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
triesLeft: {
|
||||||
|
type: Number,
|
||||||
|
},
|
||||||
|
expiresAt: {
|
||||||
|
type: Date,
|
||||||
|
expires: 0,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
timestamps: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const TokenData = model<ITokenData>("TokenData", tokenDataSchema);
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import { Document, Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export interface ITokenVersion extends Document {
|
||||||
|
user: Types.ObjectId;
|
||||||
|
ip: string;
|
||||||
|
userAgent: string;
|
||||||
|
refreshVersion: number;
|
||||||
|
accessVersion: number;
|
||||||
|
lastUsed: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tokenVersionSchema = new Schema<ITokenVersion>(
|
||||||
|
{
|
||||||
|
user: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "User",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
ip: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
userAgent: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
refreshVersion: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
accessVersion: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
lastUsed: {
|
||||||
|
type: Date,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const TokenVersion = model<ITokenVersion>("TokenVersion", tokenVersionSchema);
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export enum IPType {
|
||||||
|
IPV4 = "ipv4",
|
||||||
|
IPV6 = "ipv6"
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ITrustedIP {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
workspace: Types.ObjectId;
|
||||||
|
ipAddress: string;
|
||||||
|
type: "ipv4" | "ipv6", // either IPv4/IPv6 address or network IPv4/IPv6 address
|
||||||
|
isActive: boolean;
|
||||||
|
comment: string;
|
||||||
|
prefix?: number; // CIDR
|
||||||
|
}
|
||||||
|
|
||||||
|
const trustedIpSchema = new Schema<ITrustedIP>(
|
||||||
|
{
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Workspace",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
ipAddress: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
enum: [
|
||||||
|
IPType.IPV4,
|
||||||
|
IPType.IPV6
|
||||||
|
],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
prefix: {
|
||||||
|
type: Number,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
isActive: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
comment: {
|
||||||
|
type: String
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const TrustedIP = model<ITrustedIP>("TrustedIP", trustedIpSchema);
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
import { Document, Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export enum AuthMethod {
|
||||||
|
EMAIL = "email",
|
||||||
|
GOOGLE = "google",
|
||||||
|
GITHUB = "github",
|
||||||
|
GITLAB = "gitlab",
|
||||||
|
OKTA_SAML = "okta-saml",
|
||||||
|
AZURE_SAML = "azure-saml",
|
||||||
|
JUMPCLOUD_SAML = "jumpcloud-saml"
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IUser extends Document {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
authProvider?: AuthMethod;
|
||||||
|
authMethods: AuthMethod[];
|
||||||
|
email: string;
|
||||||
|
superAdmin?: boolean;
|
||||||
|
firstName?: string;
|
||||||
|
lastName?: string;
|
||||||
|
encryptionVersion: number;
|
||||||
|
protectedKey: string;
|
||||||
|
protectedKeyIV: string;
|
||||||
|
protectedKeyTag: string;
|
||||||
|
publicKey?: string;
|
||||||
|
encryptedPrivateKey?: string;
|
||||||
|
iv?: string;
|
||||||
|
tag?: string;
|
||||||
|
salt?: string;
|
||||||
|
verifier?: string;
|
||||||
|
isMfaEnabled: boolean;
|
||||||
|
mfaMethods: boolean;
|
||||||
|
devices: {
|
||||||
|
ip: string;
|
||||||
|
userAgent: string;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const userSchema = new Schema<IUser>(
|
||||||
|
{
|
||||||
|
authProvider: {
|
||||||
|
// TODO field: deprecate
|
||||||
|
type: String,
|
||||||
|
enum: AuthMethod
|
||||||
|
},
|
||||||
|
authMethods: {
|
||||||
|
type: [
|
||||||
|
{
|
||||||
|
type: String,
|
||||||
|
enum: AuthMethod
|
||||||
|
}
|
||||||
|
],
|
||||||
|
default: [AuthMethod.EMAIL],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
email: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
unique: true
|
||||||
|
},
|
||||||
|
firstName: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
lastName: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
encryptionVersion: {
|
||||||
|
type: Number,
|
||||||
|
select: false,
|
||||||
|
default: 1 // to resolve backward-compatibility issues
|
||||||
|
},
|
||||||
|
protectedKey: {
|
||||||
|
// introduced as part of encryption version 2
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
protectedKeyIV: {
|
||||||
|
// introduced as part of encryption version 2
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
protectedKeyTag: {
|
||||||
|
// introduced as part of encryption version 2
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
publicKey: {
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
encryptedPrivateKey: {
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
superAdmin: {
|
||||||
|
type: Boolean
|
||||||
|
},
|
||||||
|
iv: {
|
||||||
|
// iv of [encryptedPrivateKey]
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
tag: {
|
||||||
|
// tag of [encryptedPrivateKey]
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
salt: {
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
verifier: {
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
isMfaEnabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
mfaMethods: [
|
||||||
|
{
|
||||||
|
type: String
|
||||||
|
}
|
||||||
|
],
|
||||||
|
devices: {
|
||||||
|
type: [
|
||||||
|
{
|
||||||
|
ip: String,
|
||||||
|
userAgent: String
|
||||||
|
}
|
||||||
|
],
|
||||||
|
default: [],
|
||||||
|
select: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const User = model<IUser>("User", userSchema);
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export interface IUserAction {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
user: Types.ObjectId;
|
||||||
|
action: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const userActionSchema = new Schema<IUserAction>(
|
||||||
|
{
|
||||||
|
user: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "User",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const UserAction = model<IUserAction>("UserAction", userActionSchema);
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
import { Document, Schema, Types, model } from "mongoose";
|
||||||
|
import { ALGORITHM_AES_256_GCM, ENCODING_SCHEME_BASE64, ENCODING_SCHEME_UTF8 } from "../variables";
|
||||||
|
|
||||||
|
export interface IWebhook extends Document {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
workspace: Types.ObjectId;
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
url: string;
|
||||||
|
lastStatus: "success" | "failed";
|
||||||
|
lastRunErrorMessage?: string;
|
||||||
|
isDisabled: boolean;
|
||||||
|
encryptedSecretKey: string;
|
||||||
|
iv: string;
|
||||||
|
tag: string;
|
||||||
|
algorithm: "aes-256-gcm";
|
||||||
|
keyEncoding: "base64" | "utf8";
|
||||||
|
}
|
||||||
|
|
||||||
|
const WebhookSchema = new Schema<IWebhook>(
|
||||||
|
{
|
||||||
|
workspace: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Workspace",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
environment: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
secretPath: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
default: "/"
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
lastStatus: {
|
||||||
|
type: String,
|
||||||
|
enum: ["success", "failed"]
|
||||||
|
},
|
||||||
|
lastRunErrorMessage: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
isDisabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// used for webhook signature
|
||||||
|
encryptedSecretKey: {
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
iv: {
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
tag: {
|
||||||
|
type: String,
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
algorithm: {
|
||||||
|
// the encryption algorithm used
|
||||||
|
type: String,
|
||||||
|
enum: [ALGORITHM_AES_256_GCM],
|
||||||
|
select: false
|
||||||
|
},
|
||||||
|
keyEncoding: {
|
||||||
|
type: String,
|
||||||
|
enum: [ENCODING_SCHEME_UTF8, ENCODING_SCHEME_BASE64],
|
||||||
|
select: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const Webhook = model<IWebhook>("Webhook", WebhookSchema);
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
|
export interface IWorkspace {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
name: string;
|
||||||
|
organization: Types.ObjectId;
|
||||||
|
environments: Array<{
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
}>;
|
||||||
|
autoCapitalization: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const workspaceSchema = new Schema<IWorkspace>({
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
autoCapitalization: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
organization: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: "Organization",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
environments: {
|
||||||
|
type: [
|
||||||
|
{
|
||||||
|
name: String,
|
||||||
|
slug: String,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: [
|
||||||
|
{
|
||||||
|
name: "Development",
|
||||||
|
slug: "dev",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Staging",
|
||||||
|
slug: "staging",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Production",
|
||||||
|
slug: "prod",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const Workspace = model<IWorkspace>("Workspace", workspaceSchema);
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// Code generated by automation script, DO NOT EDIT.
|
||||||
|
// Automated by pulling database and generating zod schema
|
||||||
|
// To update. Just run npm run generate:schema
|
||||||
|
// Written by akhilmhdh.
|
||||||
|
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { TImmutableDBKeys } from "./models";
|
||||||
|
|
||||||
|
export const ApiKeysSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
name: z.string(),
|
||||||
|
lastUsed: z.date().nullable().optional(),
|
||||||
|
expiresAt: z.date().nullable().optional(),
|
||||||
|
secretHash: z.string(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date(),
|
||||||
|
userId: z.string().uuid(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TApiKeys = z.infer<typeof ApiKeysSchema>;
|
||||||
|
export type TApiKeysInsert = Omit<TApiKeys, TImmutableDBKeys>;
|
||||||
|
export type TApiKeysUpdate = Partial<Omit<TApiKeys, TImmutableDBKeys>>;
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// Code generated by automation script, DO NOT EDIT.
|
||||||
|
// Automated by pulling database and generating zod schema
|
||||||
|
// To update. Just run npm run generate:schema
|
||||||
|
// Written by akhilmhdh.
|
||||||
|
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { TImmutableDBKeys } from "./models";
|
||||||
|
|
||||||
|
export const AuditLogsSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
actor: z.string(),
|
||||||
|
actorMetadata: z.unknown(),
|
||||||
|
ipAddress: z.string().nullable().optional(),
|
||||||
|
eventType: z.string(),
|
||||||
|
eventMetadata: z.unknown().nullable().optional(),
|
||||||
|
userAgent: z.string().nullable().optional(),
|
||||||
|
userAgentType: z.string().nullable().optional(),
|
||||||
|
expiresAt: z.date().nullable().optional(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date(),
|
||||||
|
orgId: z.string().uuid().nullable().optional(),
|
||||||
|
projectId: z.string().nullable().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TAuditLogs = z.infer<typeof AuditLogsSchema>;
|
||||||
|
export type TAuditLogsInsert = Omit<TAuditLogs, TImmutableDBKeys>;
|
||||||
|
export type TAuditLogsUpdate = Partial<Omit<TAuditLogs, TImmutableDBKeys>>;
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
// Code generated by automation script, DO NOT EDIT.
|
||||||
|
// Automated by pulling database and generating zod schema
|
||||||
|
// To update. Just run npm run generate:schema
|
||||||
|
// Written by akhilmhdh.
|
||||||
|
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { TImmutableDBKeys } from "./models";
|
||||||
|
|
||||||
|
export const AuthTokenSessionsSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
ip: z.string(),
|
||||||
|
userAgent: z.string().nullable().optional(),
|
||||||
|
refreshVersion: z.number().default(1),
|
||||||
|
accessVersion: z.number().default(1),
|
||||||
|
lastUsed: z.date(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date(),
|
||||||
|
userId: z.string().uuid(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TAuthTokenSessions = z.infer<typeof AuthTokenSessionsSchema>;
|
||||||
|
export type TAuthTokenSessionsInsert = Omit<TAuthTokenSessions, TImmutableDBKeys>;
|
||||||
|
export type TAuthTokenSessionsUpdate = Partial<Omit<TAuthTokenSessions, TImmutableDBKeys>>;
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user