mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-10 13:28:34 +00:00
Move ssh back to project level
This commit is contained in:
Vendored
+8
@@ -317,6 +317,9 @@ import {
|
|||||||
TSshCertificateAuthoritySecrets,
|
TSshCertificateAuthoritySecrets,
|
||||||
TSshCertificateAuthoritySecretsInsert,
|
TSshCertificateAuthoritySecretsInsert,
|
||||||
TSshCertificateAuthoritySecretsUpdate,
|
TSshCertificateAuthoritySecretsUpdate,
|
||||||
|
TSshCertificateBodies,
|
||||||
|
TSshCertificateBodiesInsert,
|
||||||
|
TSshCertificateBodiesUpdate,
|
||||||
TSshCertificates,
|
TSshCertificates,
|
||||||
TSshCertificatesInsert,
|
TSshCertificatesInsert,
|
||||||
TSshCertificatesUpdate,
|
TSshCertificatesUpdate,
|
||||||
@@ -404,6 +407,11 @@ declare module "knex/types/tables" {
|
|||||||
TSshCertificatesInsert,
|
TSshCertificatesInsert,
|
||||||
TSshCertificatesUpdate
|
TSshCertificatesUpdate
|
||||||
>;
|
>;
|
||||||
|
[TableName.SshCertificateBody]: KnexOriginal.CompositeTableType<
|
||||||
|
TSshCertificateBodies,
|
||||||
|
TSshCertificateBodiesInsert,
|
||||||
|
TSshCertificateBodiesUpdate
|
||||||
|
>;
|
||||||
[TableName.CertificateAuthority]: KnexOriginal.CompositeTableType<
|
[TableName.CertificateAuthority]: KnexOriginal.CompositeTableType<
|
||||||
TCertificateAuthorities,
|
TCertificateAuthorities,
|
||||||
TCertificateAuthoritiesInsert,
|
TCertificateAuthoritiesInsert,
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
await knex.schema.createTable(TableName.SshCertificateAuthority, (t) => {
|
await knex.schema.createTable(TableName.SshCertificateAuthority, (t) => {
|
||||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
t.timestamps(true, true, true);
|
t.timestamps(true, true, true);
|
||||||
t.uuid("orgId").notNullable();
|
t.string("projectId").notNullable();
|
||||||
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
t.string("status").notNullable(); // active / disabled
|
t.string("status").notNullable(); // active / disabled
|
||||||
t.string("friendlyName").notNullable();
|
t.string("friendlyName").notNullable();
|
||||||
t.string("keyAlgorithm").notNullable();
|
t.string("keyAlgorithm").notNullable();
|
||||||
@@ -60,7 +60,6 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
.onDelete("SET NULL");
|
.onDelete("SET NULL");
|
||||||
t.string("serialNumber").notNullable().unique();
|
t.string("serialNumber").notNullable().unique();
|
||||||
t.string("certType").notNullable(); // user or host
|
t.string("certType").notNullable(); // user or host
|
||||||
t.text("publicKey").notNullable(); // public key in OpenSSH format
|
|
||||||
t.specificType("principals", "text[]").notNullable();
|
t.specificType("principals", "text[]").notNullable();
|
||||||
t.string("keyId").notNullable();
|
t.string("keyId").notNullable();
|
||||||
t.datetime("notBefore").notNullable();
|
t.datetime("notBefore").notNullable();
|
||||||
@@ -68,9 +67,24 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
});
|
});
|
||||||
await createOnUpdateTrigger(knex, TableName.SshCertificate);
|
await createOnUpdateTrigger(knex, TableName.SshCertificate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SshCertificateBody))) {
|
||||||
|
await knex.schema.createTable(TableName.SshCertificateBody, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.uuid("sshCertId").notNullable().unique();
|
||||||
|
t.foreign("sshCertId").references("id").inTable(TableName.SshCertificate).onDelete("CASCADE");
|
||||||
|
t.binary("encryptedCertificate").notNullable();
|
||||||
|
});
|
||||||
|
|
||||||
|
await createOnUpdateTrigger(knex, TableName.SshCertificateBody);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function down(knex: Knex): Promise<void> {
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SshCertificateBody);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.SshCertificateBody);
|
||||||
|
|
||||||
await knex.schema.dropTableIfExists(TableName.SshCertificate);
|
await knex.schema.dropTableIfExists(TableName.SshCertificate);
|
||||||
await dropOnUpdateTrigger(knex, TableName.SshCertificate);
|
await dropOnUpdateTrigger(knex, TableName.SshCertificate);
|
||||||
|
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ export * from "./service-tokens";
|
|||||||
export * from "./slack-integrations";
|
export * from "./slack-integrations";
|
||||||
export * from "./ssh-certificate-authorities";
|
export * from "./ssh-certificate-authorities";
|
||||||
export * from "./ssh-certificate-authority-secrets";
|
export * from "./ssh-certificate-authority-secrets";
|
||||||
|
export * from "./ssh-certificate-bodies";
|
||||||
export * from "./ssh-certificate-templates";
|
export * from "./ssh-certificate-templates";
|
||||||
export * from "./ssh-certificates";
|
export * from "./ssh-certificates";
|
||||||
export * from "./super-admin";
|
export * from "./super-admin";
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export enum TableName {
|
|||||||
SshCertificateAuthoritySecret = "ssh_certificate_authority_secrets",
|
SshCertificateAuthoritySecret = "ssh_certificate_authority_secrets",
|
||||||
SshCertificateTemplate = "ssh_certificate_templates",
|
SshCertificateTemplate = "ssh_certificate_templates",
|
||||||
SshCertificate = "ssh_certificates",
|
SshCertificate = "ssh_certificates",
|
||||||
|
SshCertificateBody = "ssh_certificate_bodies",
|
||||||
CertificateAuthority = "certificate_authorities",
|
CertificateAuthority = "certificate_authorities",
|
||||||
CertificateTemplateEstConfig = "certificate_template_est_configs",
|
CertificateTemplateEstConfig = "certificate_template_est_configs",
|
||||||
CertificateAuthorityCert = "certificate_authority_certs",
|
CertificateAuthorityCert = "certificate_authority_certs",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const SshCertificateAuthoritiesSchema = z.object({
|
|||||||
id: z.string().uuid(),
|
id: z.string().uuid(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
orgId: z.string().uuid(),
|
projectId: z.string(),
|
||||||
status: z.string(),
|
status: z.string(),
|
||||||
friendlyName: z.string(),
|
friendlyName: z.string(),
|
||||||
keyAlgorithm: z.string()
|
keyAlgorithm: z.string()
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// 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 { zodBuffer } from "@app/lib/zod";
|
||||||
|
|
||||||
|
import { TImmutableDBKeys } from "./models";
|
||||||
|
|
||||||
|
export const SshCertificateBodiesSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date(),
|
||||||
|
sshCertId: z.string().uuid(),
|
||||||
|
encryptedCertificate: zodBuffer
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TSshCertificateBodies = z.infer<typeof SshCertificateBodiesSchema>;
|
||||||
|
export type TSshCertificateBodiesInsert = Omit<z.input<typeof SshCertificateBodiesSchema>, TImmutableDBKeys>;
|
||||||
|
export type TSshCertificateBodiesUpdate = Partial<Omit<z.input<typeof SshCertificateBodiesSchema>, TImmutableDBKeys>>;
|
||||||
@@ -15,7 +15,6 @@ export const SshCertificatesSchema = z.object({
|
|||||||
sshCertificateTemplateId: z.string().uuid().nullable().optional(),
|
sshCertificateTemplateId: z.string().uuid().nullable().optional(),
|
||||||
serialNumber: z.string(),
|
serialNumber: z.string(),
|
||||||
certType: z.string(),
|
certType: z.string(),
|
||||||
publicKey: z.string(),
|
|
||||||
principals: z.string().array(),
|
principals: z.string().array(),
|
||||||
keyId: z.string(),
|
keyId: z.string(),
|
||||||
notBefore: z.date(),
|
notBefore: z.date(),
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export const registerSshCaRouter = async (server: FastifyZodProvider) => {
|
|||||||
schema: {
|
schema: {
|
||||||
description: "Create SSH CA",
|
description: "Create SSH CA",
|
||||||
body: z.object({
|
body: z.object({
|
||||||
|
projectId: z.string().describe(SSH_CERTIFICATE_AUTHORITIES.CREATE.projectId),
|
||||||
friendlyName: z.string().describe(SSH_CERTIFICATE_AUTHORITIES.CREATE.friendlyName),
|
friendlyName: z.string().describe(SSH_CERTIFICATE_AUTHORITIES.CREATE.friendlyName),
|
||||||
keyAlgorithm: z
|
keyAlgorithm: z
|
||||||
.nativeEnum(CertKeyAlgorithm)
|
.nativeEnum(CertKeyAlgorithm)
|
||||||
@@ -46,7 +47,7 @@ export const registerSshCaRouter = async (server: FastifyZodProvider) => {
|
|||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: ca.orgId,
|
projectId: ca.projectId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.CREATE_SSH_CA,
|
type: EventType.CREATE_SSH_CA,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -93,7 +94,7 @@ export const registerSshCaRouter = async (server: FastifyZodProvider) => {
|
|||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: ca.orgId,
|
projectId: ca.projectId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.GET_SSH_CA,
|
type: EventType.GET_SSH_CA,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -169,7 +170,7 @@ export const registerSshCaRouter = async (server: FastifyZodProvider) => {
|
|||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: ca.orgId,
|
projectId: ca.projectId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.UPDATE_SSH_CA,
|
type: EventType.UPDATE_SSH_CA,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -215,7 +216,7 @@ export const registerSshCaRouter = async (server: FastifyZodProvider) => {
|
|||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: ca.orgId,
|
projectId: ca.projectId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.DELETE_SSH_CA,
|
type: EventType.DELETE_SSH_CA,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -260,7 +261,7 @@ export const registerSshCaRouter = async (server: FastifyZodProvider) => {
|
|||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: ca.orgId,
|
projectId: ca.projectId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.GET_SSH_CA_CERTIFICATE_TEMPLATES,
|
type: EventType.GET_SSH_CA_CERTIFICATE_TEMPLATES,
|
||||||
metadata: {
|
metadata: {
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export const registerSshCertificateTemplateRouter = async (server: FastifyZodPro
|
|||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: certificateTemplate.orgId,
|
projectId: certificateTemplate.projectId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.GET_SSH_CERTIFICATE_TEMPLATE,
|
type: EventType.GET_SSH_CERTIFICATE_TEMPLATE,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -107,7 +107,7 @@ export const registerSshCertificateTemplateRouter = async (server: FastifyZodPro
|
|||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: ca.orgId,
|
projectId: ca.projectId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.CREATE_SSH_CERTIFICATE_TEMPLATE,
|
type: EventType.CREATE_SSH_CERTIFICATE_TEMPLATE,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -178,7 +178,7 @@ export const registerSshCertificateTemplateRouter = async (server: FastifyZodPro
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { certificateTemplate, orgId } = await server.services.sshCertificateTemplate.updateSshCertTemplate({
|
const { certificateTemplate, projectId } = await server.services.sshCertificateTemplate.updateSshCertTemplate({
|
||||||
...req.body,
|
...req.body,
|
||||||
id: req.params.certificateTemplateId,
|
id: req.params.certificateTemplateId,
|
||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
@@ -189,7 +189,7 @@ export const registerSshCertificateTemplateRouter = async (server: FastifyZodPro
|
|||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId,
|
projectId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.UPDATE_SSH_CERTIFICATE_TEMPLATE,
|
type: EventType.UPDATE_SSH_CERTIFICATE_TEMPLATE,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -238,7 +238,7 @@ export const registerSshCertificateTemplateRouter = async (server: FastifyZodPro
|
|||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: certificateTemplate.orgId,
|
projectId: certificateTemplate.projectId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.DELETE_SSH_CERTIFICATE_TEMPLATE,
|
type: EventType.DELETE_SSH_CERTIFICATE_TEMPLATE,
|
||||||
metadata: {
|
metadata: {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export const registerSshRouter = async (server: FastifyZodProvider) => {
|
|||||||
schema: {
|
schema: {
|
||||||
description: "Sign SSH public key",
|
description: "Sign SSH public key",
|
||||||
body: z.object({
|
body: z.object({
|
||||||
|
projectId: z.string().trim().describe(SSH_CERTIFICATE_AUTHORITIES.SIGN_SSH_KEY.projectId),
|
||||||
templateName: z.string().trim().describe(SSH_CERTIFICATE_AUTHORITIES.SIGN_SSH_KEY.templateName),
|
templateName: z.string().trim().describe(SSH_CERTIFICATE_AUTHORITIES.SIGN_SSH_KEY.templateName),
|
||||||
publicKey: z.string().trim().describe(SSH_CERTIFICATE_AUTHORITIES.SIGN_SSH_KEY.publicKey),
|
publicKey: z.string().trim().describe(SSH_CERTIFICATE_AUTHORITIES.SIGN_SSH_KEY.publicKey),
|
||||||
certType: z
|
certType: z
|
||||||
@@ -86,6 +87,7 @@ export const registerSshRouter = async (server: FastifyZodProvider) => {
|
|||||||
schema: {
|
schema: {
|
||||||
description: "Issue SSH credentials (certificate + key)",
|
description: "Issue SSH credentials (certificate + key)",
|
||||||
body: z.object({
|
body: z.object({
|
||||||
|
projectId: z.string().trim().describe(SSH_CERTIFICATE_AUTHORITIES.ISSUE_SSH_CREDENTIALS.projectId),
|
||||||
templateName: z.string().trim().describe(SSH_CERTIFICATE_AUTHORITIES.ISSUE_SSH_CREDENTIALS.templateName),
|
templateName: z.string().trim().describe(SSH_CERTIFICATE_AUTHORITIES.ISSUE_SSH_CREDENTIALS.templateName),
|
||||||
keyAlgorithm: z
|
keyAlgorithm: z
|
||||||
.nativeEnum(CertKeyAlgorithm)
|
.nativeEnum(CertKeyAlgorithm)
|
||||||
|
|||||||
@@ -27,10 +27,7 @@ export enum OrgPermissionSubjects {
|
|||||||
Kms = "kms",
|
Kms = "kms",
|
||||||
AdminConsole = "organization-admin-console",
|
AdminConsole = "organization-admin-console",
|
||||||
AuditLogs = "audit-logs",
|
AuditLogs = "audit-logs",
|
||||||
ProjectTemplates = "project-templates",
|
ProjectTemplates = "project-templates"
|
||||||
SshCertificates = "ssh-certificates",
|
|
||||||
SshCertificateAuthorities = "ssh-certificate-authorities",
|
|
||||||
SshCertificateTemplates = "ssh-certificate-templates"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type OrgPermissionSet =
|
export type OrgPermissionSet =
|
||||||
@@ -49,10 +46,7 @@ export type OrgPermissionSet =
|
|||||||
| [OrgPermissionActions, OrgPermissionSubjects.Kms]
|
| [OrgPermissionActions, OrgPermissionSubjects.Kms]
|
||||||
| [OrgPermissionActions, OrgPermissionSubjects.AuditLogs]
|
| [OrgPermissionActions, OrgPermissionSubjects.AuditLogs]
|
||||||
| [OrgPermissionActions, OrgPermissionSubjects.ProjectTemplates]
|
| [OrgPermissionActions, OrgPermissionSubjects.ProjectTemplates]
|
||||||
| [OrgPermissionAdminConsoleAction, OrgPermissionSubjects.AdminConsole]
|
| [OrgPermissionAdminConsoleAction, OrgPermissionSubjects.AdminConsole];
|
||||||
| [OrgPermissionActions, OrgPermissionSubjects.SshCertificateAuthorities]
|
|
||||||
| [OrgPermissionActions, OrgPermissionSubjects.SshCertificates]
|
|
||||||
| [OrgPermissionActions, OrgPermissionSubjects.SshCertificateTemplates];
|
|
||||||
|
|
||||||
const buildAdminPermission = () => {
|
const buildAdminPermission = () => {
|
||||||
const { can, rules } = new AbilityBuilder<MongoAbility<OrgPermissionSet>>(createMongoAbility);
|
const { can, rules } = new AbilityBuilder<MongoAbility<OrgPermissionSet>>(createMongoAbility);
|
||||||
@@ -129,19 +123,6 @@ const buildAdminPermission = () => {
|
|||||||
can(OrgPermissionActions.Edit, OrgPermissionSubjects.ProjectTemplates);
|
can(OrgPermissionActions.Edit, OrgPermissionSubjects.ProjectTemplates);
|
||||||
can(OrgPermissionActions.Delete, OrgPermissionSubjects.ProjectTemplates);
|
can(OrgPermissionActions.Delete, OrgPermissionSubjects.ProjectTemplates);
|
||||||
|
|
||||||
can(OrgPermissionActions.Read, OrgPermissionSubjects.SshCertificates);
|
|
||||||
can(OrgPermissionActions.Create, OrgPermissionSubjects.SshCertificates);
|
|
||||||
|
|
||||||
can(OrgPermissionActions.Read, OrgPermissionSubjects.SshCertificateAuthorities);
|
|
||||||
can(OrgPermissionActions.Create, OrgPermissionSubjects.SshCertificateAuthorities);
|
|
||||||
can(OrgPermissionActions.Edit, OrgPermissionSubjects.SshCertificateAuthorities);
|
|
||||||
can(OrgPermissionActions.Delete, OrgPermissionSubjects.SshCertificateAuthorities);
|
|
||||||
|
|
||||||
can(OrgPermissionActions.Read, OrgPermissionSubjects.SshCertificateTemplates);
|
|
||||||
can(OrgPermissionActions.Create, OrgPermissionSubjects.SshCertificateTemplates);
|
|
||||||
can(OrgPermissionActions.Edit, OrgPermissionSubjects.SshCertificateTemplates);
|
|
||||||
can(OrgPermissionActions.Delete, OrgPermissionSubjects.SshCertificateTemplates);
|
|
||||||
|
|
||||||
can(OrgPermissionAdminConsoleAction.AccessAllProjects, OrgPermissionSubjects.AdminConsole);
|
can(OrgPermissionAdminConsoleAction.AccessAllProjects, OrgPermissionSubjects.AdminConsole);
|
||||||
|
|
||||||
return rules;
|
return rules;
|
||||||
@@ -172,11 +153,6 @@ const buildMemberPermission = () => {
|
|||||||
|
|
||||||
can(OrgPermissionActions.Read, OrgPermissionSubjects.AuditLogs);
|
can(OrgPermissionActions.Read, OrgPermissionSubjects.AuditLogs);
|
||||||
|
|
||||||
can(OrgPermissionActions.Read, OrgPermissionSubjects.SshCertificateAuthorities);
|
|
||||||
can(OrgPermissionActions.Read, OrgPermissionSubjects.SshCertificates);
|
|
||||||
can(OrgPermissionActions.Create, OrgPermissionSubjects.SshCertificates);
|
|
||||||
can(OrgPermissionActions.Read, OrgPermissionSubjects.SshCertificateTemplates);
|
|
||||||
|
|
||||||
return rules;
|
return rules;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ export enum ProjectPermissionSub {
|
|||||||
CertificateAuthorities = "certificate-authorities",
|
CertificateAuthorities = "certificate-authorities",
|
||||||
Certificates = "certificates",
|
Certificates = "certificates",
|
||||||
CertificateTemplates = "certificate-templates",
|
CertificateTemplates = "certificate-templates",
|
||||||
|
SshCertificateAuthorities = "ssh-certificate-authorities",
|
||||||
|
SshCertificates = "ssh-certificates",
|
||||||
|
SshCertificateTemplates = "ssh-certificate-templates",
|
||||||
PkiAlerts = "pki-alerts",
|
PkiAlerts = "pki-alerts",
|
||||||
PkiCollections = "pki-collections",
|
PkiCollections = "pki-collections",
|
||||||
Kms = "kms",
|
Kms = "kms",
|
||||||
@@ -125,6 +128,9 @@ export type ProjectPermissionSet =
|
|||||||
| [ProjectPermissionActions, ProjectPermissionSub.CertificateAuthorities]
|
| [ProjectPermissionActions, ProjectPermissionSub.CertificateAuthorities]
|
||||||
| [ProjectPermissionActions, ProjectPermissionSub.Certificates]
|
| [ProjectPermissionActions, ProjectPermissionSub.Certificates]
|
||||||
| [ProjectPermissionActions, ProjectPermissionSub.CertificateTemplates]
|
| [ProjectPermissionActions, ProjectPermissionSub.CertificateTemplates]
|
||||||
|
| [ProjectPermissionActions, ProjectPermissionSub.SshCertificateAuthorities]
|
||||||
|
| [ProjectPermissionActions, ProjectPermissionSub.SshCertificates]
|
||||||
|
| [ProjectPermissionActions, ProjectPermissionSub.SshCertificateTemplates]
|
||||||
| [ProjectPermissionActions, ProjectPermissionSub.PkiAlerts]
|
| [ProjectPermissionActions, ProjectPermissionSub.PkiAlerts]
|
||||||
| [ProjectPermissionActions, ProjectPermissionSub.PkiCollections]
|
| [ProjectPermissionActions, ProjectPermissionSub.PkiCollections]
|
||||||
| [ProjectPermissionCmekActions, ProjectPermissionSub.Cmek]
|
| [ProjectPermissionCmekActions, ProjectPermissionSub.Cmek]
|
||||||
@@ -322,6 +328,28 @@ const GeneralPermissionSchema = [
|
|||||||
"Describe what action an entity can take."
|
"Describe what action an entity can take."
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
|
z.object({
|
||||||
|
subject: z
|
||||||
|
.literal(ProjectPermissionSub.SshCertificateAuthorities)
|
||||||
|
.describe("The entity this permission pertains to."),
|
||||||
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
|
"Describe what action an entity can take."
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
subject: z.literal(ProjectPermissionSub.SshCertificates).describe("The entity this permission pertains to."),
|
||||||
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
|
"Describe what action an entity can take."
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
subject: z
|
||||||
|
.literal(ProjectPermissionSub.SshCertificateTemplates)
|
||||||
|
.describe("The entity this permission pertains to."),
|
||||||
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
|
"Describe what action an entity can take."
|
||||||
|
)
|
||||||
|
}),
|
||||||
z.object({
|
z.object({
|
||||||
subject: z.literal(ProjectPermissionSub.PkiAlerts).describe("The entity this permission pertains to."),
|
subject: z.literal(ProjectPermissionSub.PkiAlerts).describe("The entity this permission pertains to."),
|
||||||
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
@@ -448,7 +476,10 @@ const buildAdminPermissionRules = () => {
|
|||||||
ProjectPermissionSub.Certificates,
|
ProjectPermissionSub.Certificates,
|
||||||
ProjectPermissionSub.CertificateTemplates,
|
ProjectPermissionSub.CertificateTemplates,
|
||||||
ProjectPermissionSub.PkiAlerts,
|
ProjectPermissionSub.PkiAlerts,
|
||||||
ProjectPermissionSub.PkiCollections
|
ProjectPermissionSub.PkiCollections,
|
||||||
|
ProjectPermissionSub.SshCertificateAuthorities,
|
||||||
|
ProjectPermissionSub.SshCertificates,
|
||||||
|
ProjectPermissionSub.SshCertificateTemplates
|
||||||
].forEach((el) => {
|
].forEach((el) => {
|
||||||
can(
|
can(
|
||||||
[
|
[
|
||||||
@@ -633,6 +664,11 @@ const buildMemberPermissionRules = () => {
|
|||||||
can([ProjectPermissionActions.Read], ProjectPermissionSub.PkiAlerts);
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.PkiAlerts);
|
||||||
can([ProjectPermissionActions.Read], ProjectPermissionSub.PkiCollections);
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.PkiCollections);
|
||||||
|
|
||||||
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.SshCertificateAuthorities);
|
||||||
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.SshCertificates);
|
||||||
|
can([ProjectPermissionActions.Create], ProjectPermissionSub.SshCertificates);
|
||||||
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.SshCertificateTemplates);
|
||||||
|
|
||||||
can(
|
can(
|
||||||
[
|
[
|
||||||
ProjectPermissionCmekActions.Create,
|
ProjectPermissionCmekActions.Create,
|
||||||
@@ -675,6 +711,9 @@ const buildViewerPermissionRules = () => {
|
|||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.CertificateAuthorities);
|
can(ProjectPermissionActions.Read, ProjectPermissionSub.CertificateAuthorities);
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.Certificates);
|
can(ProjectPermissionActions.Read, ProjectPermissionSub.Certificates);
|
||||||
can(ProjectPermissionCmekActions.Read, ProjectPermissionSub.Cmek);
|
can(ProjectPermissionCmekActions.Read, ProjectPermissionSub.Cmek);
|
||||||
|
can(ProjectPermissionActions.Read, ProjectPermissionSub.SshCertificateAuthorities);
|
||||||
|
can(ProjectPermissionActions.Read, ProjectPermissionSub.SshCertificates);
|
||||||
|
can(ProjectPermissionActions.Read, ProjectPermissionSub.SshCertificateTemplates);
|
||||||
|
|
||||||
return rules;
|
return rules;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ export const sshCertificateTemplateDALFactory = (db: TDbClient) => {
|
|||||||
`${TableName.SshCertificateAuthority}.id`,
|
`${TableName.SshCertificateAuthority}.id`,
|
||||||
`${TableName.SshCertificateTemplate}.sshCaId`
|
`${TableName.SshCertificateTemplate}.sshCaId`
|
||||||
)
|
)
|
||||||
.join(TableName.Organization, `${TableName.Organization}.id`, `${TableName.SshCertificateAuthority}.orgId`)
|
.join(TableName.Project, `${TableName.Project}.id`, `${TableName.SshCertificateAuthority}.projectId`)
|
||||||
.where(`${TableName.SshCertificateTemplate}.id`, "=", id)
|
.where(`${TableName.SshCertificateTemplate}.id`, "=", id)
|
||||||
.select(selectAllTableCols(TableName.SshCertificateTemplate))
|
.select(selectAllTableCols(TableName.SshCertificateTemplate))
|
||||||
.select(
|
.select(
|
||||||
db.ref("orgId").withSchema(TableName.SshCertificateAuthority),
|
db.ref("projectId").withSchema(TableName.SshCertificateAuthority),
|
||||||
db.ref("friendlyName").as("caName").withSchema(TableName.SshCertificateAuthority),
|
db.ref("friendlyName").as("caName").withSchema(TableName.SshCertificateAuthority),
|
||||||
db.ref("status").as("caStatus").withSchema(TableName.SshCertificateAuthority)
|
db.ref("status").as("caStatus").withSchema(TableName.SshCertificateAuthority)
|
||||||
)
|
)
|
||||||
@@ -34,7 +34,10 @@ export const sshCertificateTemplateDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getByName = async (name: string, orgId: string, tx?: Knex) => {
|
/**
|
||||||
|
* Returns the SSH certificate template named [name] within project with id [projectId]
|
||||||
|
*/
|
||||||
|
const getByName = async (name: string, projectId: string, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const certTemplate = await (tx || db.replicaNode())(TableName.SshCertificateTemplate)
|
const certTemplate = await (tx || db.replicaNode())(TableName.SshCertificateTemplate)
|
||||||
.join(
|
.join(
|
||||||
@@ -42,12 +45,12 @@ export const sshCertificateTemplateDALFactory = (db: TDbClient) => {
|
|||||||
`${TableName.SshCertificateAuthority}.id`,
|
`${TableName.SshCertificateAuthority}.id`,
|
||||||
`${TableName.SshCertificateTemplate}.sshCaId`
|
`${TableName.SshCertificateTemplate}.sshCaId`
|
||||||
)
|
)
|
||||||
.join(TableName.Organization, `${TableName.Organization}.id`, `${TableName.SshCertificateAuthority}.orgId`)
|
.join(TableName.Project, `${TableName.Project}.id`, `${TableName.SshCertificateAuthority}.projectId`)
|
||||||
.where(`${TableName.SshCertificateTemplate}.name`, "=", name)
|
.where(`${TableName.SshCertificateTemplate}.name`, "=", name)
|
||||||
.where(`${TableName.Organization}.id`, "=", orgId)
|
.where(`${TableName.Project}.id`, "=", projectId)
|
||||||
.select(selectAllTableCols(TableName.SshCertificateTemplate))
|
.select(selectAllTableCols(TableName.SshCertificateTemplate))
|
||||||
.select(
|
.select(
|
||||||
db.ref("orgId").withSchema(TableName.SshCertificateAuthority),
|
db.ref("projectId").withSchema(TableName.SshCertificateAuthority),
|
||||||
db.ref("friendlyName").as("caName").withSchema(TableName.SshCertificateAuthority),
|
db.ref("friendlyName").as("caName").withSchema(TableName.SshCertificateAuthority),
|
||||||
db.ref("status").as("caStatus").withSchema(TableName.SshCertificateAuthority)
|
db.ref("status").as("caStatus").withSchema(TableName.SshCertificateAuthority)
|
||||||
)
|
)
|
||||||
|
|||||||
+21
-21
@@ -1,8 +1,8 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
import ms from "ms";
|
import ms from "ms";
|
||||||
|
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||||
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
||||||
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
|
|
||||||
import { TSshCertificateAuthorityDALFactory } from "../ssh/ssh-certificate-authority-dal";
|
import { TSshCertificateAuthorityDALFactory } from "../ssh/ssh-certificate-authority-dal";
|
||||||
@@ -21,7 +21,7 @@ type TSshCertificateTemplateServiceFactoryDep = {
|
|||||||
"transaction" | "getByName" | "create" | "updateById" | "deleteById" | "getById"
|
"transaction" | "getByName" | "create" | "updateById" | "deleteById" | "getById"
|
||||||
>;
|
>;
|
||||||
sshCertificateAuthorityDAL: Pick<TSshCertificateAuthorityDALFactory, "findById">;
|
sshCertificateAuthorityDAL: Pick<TSshCertificateAuthorityDALFactory, "findById">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TSshCertificateTemplateServiceFactory = ReturnType<typeof sshCertificateTemplateServiceFactory>;
|
export type TSshCertificateTemplateServiceFactory = ReturnType<typeof sshCertificateTemplateServiceFactory>;
|
||||||
@@ -53,17 +53,17 @@ export const sshCertificateTemplateServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getProjectPermission(
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
ca.orgId,
|
ca.projectId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
);
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Create,
|
ProjectPermissionActions.Create,
|
||||||
OrgPermissionSubjects.SshCertificateTemplates
|
ProjectPermissionSub.SshCertificateTemplates
|
||||||
);
|
);
|
||||||
|
|
||||||
if (ms(ttl) > ms(maxTTL)) {
|
if (ms(ttl) > ms(maxTTL)) {
|
||||||
@@ -73,7 +73,7 @@ export const sshCertificateTemplateServiceFactory = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const newCertificateTemplate = await sshCertificateTemplateDAL.transaction(async (tx) => {
|
const newCertificateTemplate = await sshCertificateTemplateDAL.transaction(async (tx) => {
|
||||||
const existingTemplate = await sshCertificateTemplateDAL.getByName(name, ca.orgId, tx);
|
const existingTemplate = await sshCertificateTemplateDAL.getByName(name, ca.projectId, tx);
|
||||||
if (existingTemplate) {
|
if (existingTemplate) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: `SSH certificate template with name ${name} already exists`
|
message: `SSH certificate template with name ${name} already exists`
|
||||||
@@ -125,22 +125,22 @@ export const sshCertificateTemplateServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getProjectPermission(
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
certTemplate.orgId,
|
certTemplate.projectId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
);
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Edit,
|
ProjectPermissionActions.Edit,
|
||||||
OrgPermissionSubjects.SshCertificateTemplates
|
ProjectPermissionSub.SshCertificateTemplates
|
||||||
);
|
);
|
||||||
|
|
||||||
const updatedCertificateTemplate = await sshCertificateTemplateDAL.transaction(async (tx) => {
|
const updatedCertificateTemplate = await sshCertificateTemplateDAL.transaction(async (tx) => {
|
||||||
if (name) {
|
if (name) {
|
||||||
const existingTemplate = await sshCertificateTemplateDAL.getByName(name, actorOrgId, tx);
|
const existingTemplate = await sshCertificateTemplateDAL.getByName(name, certTemplate.projectId, tx);
|
||||||
if (existingTemplate && existingTemplate.id !== id) {
|
if (existingTemplate && existingTemplate.id !== id) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: `SSH certificate template with name ${name} already exists`
|
message: `SSH certificate template with name ${name} already exists`
|
||||||
@@ -175,7 +175,7 @@ export const sshCertificateTemplateServiceFactory = ({
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
certificateTemplate: updatedCertificateTemplate,
|
certificateTemplate: updatedCertificateTemplate,
|
||||||
orgId: certTemplate.orgId
|
projectId: certTemplate.projectId
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -193,17 +193,17 @@ export const sshCertificateTemplateServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getProjectPermission(
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
certificateTemplate.orgId,
|
certificateTemplate.projectId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
);
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Delete,
|
ProjectPermissionActions.Delete,
|
||||||
OrgPermissionSubjects.SshCertificateTemplates
|
ProjectPermissionSub.SshCertificateTemplates
|
||||||
);
|
);
|
||||||
|
|
||||||
await sshCertificateTemplateDAL.deleteById(certificateTemplate.id);
|
await sshCertificateTemplateDAL.deleteById(certificateTemplate.id);
|
||||||
@@ -219,17 +219,17 @@ export const sshCertificateTemplateServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getProjectPermission(
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
certTemplate.orgId,
|
certTemplate.projectId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
);
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
OrgPermissionSubjects.SshCertificateTemplates
|
ProjectPermissionSub.SshCertificateTemplates
|
||||||
);
|
);
|
||||||
|
|
||||||
return certTemplate;
|
return certTemplate;
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { TDbClient } from "@app/db";
|
||||||
|
import { TableName } from "@app/db/schemas";
|
||||||
|
import { ormify } from "@app/lib/knex";
|
||||||
|
|
||||||
|
export type TSshCertificateBodyDALFactory = ReturnType<typeof sshCertificateBodyDALFactory>;
|
||||||
|
|
||||||
|
export const sshCertificateBodyDALFactory = (db: TDbClient) => {
|
||||||
|
const sshCertificateBodyOrm = ormify(db, TableName.SshCertificateBody);
|
||||||
|
return sshCertificateBodyOrm;
|
||||||
|
};
|
||||||
@@ -8,7 +8,7 @@ export type TSshCertificateDALFactory = ReturnType<typeof sshCertificateDALFacto
|
|||||||
export const sshCertificateDALFactory = (db: TDbClient) => {
|
export const sshCertificateDALFactory = (db: TDbClient) => {
|
||||||
const sshCertificateOrm = ormify(db, TableName.SshCertificate);
|
const sshCertificateOrm = ormify(db, TableName.SshCertificate);
|
||||||
|
|
||||||
const countSshCertificatesInOrg = async (orgId: string) => {
|
const countSshCertificatesInProject = async (projectId: string) => {
|
||||||
try {
|
try {
|
||||||
interface CountResult {
|
interface CountResult {
|
||||||
count: string;
|
count: string;
|
||||||
@@ -21,18 +21,18 @@ export const sshCertificateDALFactory = (db: TDbClient) => {
|
|||||||
`${TableName.SshCertificate}.sshCaId`,
|
`${TableName.SshCertificate}.sshCaId`,
|
||||||
`${TableName.SshCertificateAuthority}.id`
|
`${TableName.SshCertificateAuthority}.id`
|
||||||
)
|
)
|
||||||
.join(TableName.Organization, `${TableName.SshCertificateAuthority}.orgId`, `${TableName.Organization}.id`)
|
.join(TableName.Project, `${TableName.SshCertificateAuthority}.projectId`, `${TableName.Project}.id`)
|
||||||
.where(`${TableName.Organization}.id`, orgId);
|
.where(`${TableName.Project}.id`, projectId);
|
||||||
|
|
||||||
const count = await query.count("*").first();
|
const count = await query.count("*").first();
|
||||||
|
|
||||||
return parseInt((count as unknown as CountResult).count || "0", 10);
|
return parseInt((count as unknown as CountResult).count || "0", 10);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Count all SSH certificates in organization" });
|
throw new DatabaseError({ error, name: "Count all SSH certificates in project" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
...sshCertificateOrm,
|
...sshCertificateOrm,
|
||||||
countSshCertificatesInOrg
|
countSshCertificatesInProject
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { SshCertificateAuthoritiesSchema } from "@app/db/schemas";
|
|||||||
|
|
||||||
export const sanitizedSshCa = SshCertificateAuthoritiesSchema.pick({
|
export const sanitizedSshCa = SshCertificateAuthoritiesSchema.pick({
|
||||||
id: true,
|
id: true,
|
||||||
orgId: true,
|
projectId: true,
|
||||||
friendlyName: true,
|
friendlyName: true,
|
||||||
status: true,
|
status: true,
|
||||||
keyAlgorithm: true
|
keyAlgorithm: true
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||||
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
||||||
import { TSshCertificateAuthorityDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-dal";
|
import { TSshCertificateAuthorityDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-dal";
|
||||||
import { TSshCertificateAuthoritySecretDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-secret-dal";
|
import { TSshCertificateAuthoritySecretDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-secret-dal";
|
||||||
|
import { TSshCertificateBodyDALFactory } from "@app/ee/services/ssh-certificate/ssh-certificate-body-dal";
|
||||||
import { TSshCertificateDALFactory } from "@app/ee/services/ssh-certificate/ssh-certificate-dal";
|
import { TSshCertificateDALFactory } from "@app/ee/services/ssh-certificate/ssh-certificate-dal";
|
||||||
import { TSshCertificateTemplateDALFactory } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-dal";
|
import { TSshCertificateTemplateDALFactory } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-dal";
|
||||||
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||||
|
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||||
|
|
||||||
import { SshCertTemplateStatus } from "../ssh-certificate-template/ssh-certificate-template-types";
|
import { SshCertTemplateStatus } from "../ssh-certificate-template/ssh-certificate-template-types";
|
||||||
import {
|
import {
|
||||||
@@ -37,18 +39,25 @@ type TSshCertificateAuthorityServiceFactoryDep = {
|
|||||||
>;
|
>;
|
||||||
sshCertificateAuthoritySecretDAL: Pick<TSshCertificateAuthoritySecretDALFactory, "create" | "findOne">;
|
sshCertificateAuthoritySecretDAL: Pick<TSshCertificateAuthoritySecretDALFactory, "create" | "findOne">;
|
||||||
sshCertificateTemplateDAL: Pick<TSshCertificateTemplateDALFactory, "find" | "getByName">;
|
sshCertificateTemplateDAL: Pick<TSshCertificateTemplateDALFactory, "find" | "getByName">;
|
||||||
sshCertificateDAL: Pick<TSshCertificateDALFactory, "create">;
|
sshCertificateDAL: Pick<TSshCertificateDALFactory, "create" | "transaction">;
|
||||||
kmsService: Pick<TKmsServiceFactory, "generateKmsKey" | "encryptWithKmsKey" | "decryptWithKmsKey" | "getOrgKmsKeyId">;
|
sshCertificateBodyDAL: Pick<TSshCertificateBodyDALFactory, "create">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
kmsService: Pick<
|
||||||
|
TKmsServiceFactory,
|
||||||
|
"generateKmsKey" | "encryptWithKmsKey" | "decryptWithKmsKey" | "getOrgKmsKeyId" | "createCipherPairWithDataKey"
|
||||||
|
>;
|
||||||
|
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TSshCertificateAuthorityServiceFactory = ReturnType<typeof sshCertificateAuthorityServiceFactory>;
|
export type TSshCertificateAuthorityServiceFactory = ReturnType<typeof sshCertificateAuthorityServiceFactory>;
|
||||||
|
|
||||||
|
// TODO: secretManagerEncryptor -> sshEncryptor (cc akhil)
|
||||||
|
|
||||||
export const sshCertificateAuthorityServiceFactory = ({
|
export const sshCertificateAuthorityServiceFactory = ({
|
||||||
sshCertificateAuthorityDAL,
|
sshCertificateAuthorityDAL,
|
||||||
sshCertificateAuthoritySecretDAL,
|
sshCertificateAuthoritySecretDAL,
|
||||||
sshCertificateTemplateDAL,
|
sshCertificateTemplateDAL,
|
||||||
sshCertificateDAL,
|
sshCertificateDAL,
|
||||||
|
sshCertificateBodyDAL,
|
||||||
kmsService,
|
kmsService,
|
||||||
permissionService
|
permissionService
|
||||||
}: TSshCertificateAuthorityServiceFactoryDep) => {
|
}: TSshCertificateAuthorityServiceFactoryDep) => {
|
||||||
@@ -56,6 +65,7 @@ export const sshCertificateAuthorityServiceFactory = ({
|
|||||||
* Generates a new SSH CA
|
* Generates a new SSH CA
|
||||||
*/
|
*/
|
||||||
const createSshCa = async ({
|
const createSshCa = async ({
|
||||||
|
projectId,
|
||||||
friendlyName,
|
friendlyName,
|
||||||
keyAlgorithm,
|
keyAlgorithm,
|
||||||
actorId,
|
actorId,
|
||||||
@@ -63,23 +73,23 @@ export const sshCertificateAuthorityServiceFactory = ({
|
|||||||
actor,
|
actor,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
}: TCreateSshCaDTO) => {
|
}: TCreateSshCaDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getProjectPermission(
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
projectId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
);
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Create,
|
ProjectPermissionActions.Create,
|
||||||
OrgPermissionSubjects.SshCertificateAuthorities
|
ProjectPermissionSub.SshCertificateAuthorities
|
||||||
);
|
);
|
||||||
|
|
||||||
const newCa = await sshCertificateAuthorityDAL.transaction(async (tx) => {
|
const newCa = await sshCertificateAuthorityDAL.transaction(async (tx) => {
|
||||||
const ca = await sshCertificateAuthorityDAL.create(
|
const ca = await sshCertificateAuthorityDAL.create(
|
||||||
{
|
{
|
||||||
orgId: actorOrgId,
|
projectId,
|
||||||
friendlyName,
|
friendlyName,
|
||||||
status: SshCaStatus.ACTIVE,
|
status: SshCaStatus.ACTIVE,
|
||||||
keyAlgorithm
|
keyAlgorithm
|
||||||
@@ -89,19 +99,16 @@ export const sshCertificateAuthorityServiceFactory = ({
|
|||||||
|
|
||||||
const { publicKey, privateKey } = createSshKeyPair(keyAlgorithm, ca.friendlyName);
|
const { publicKey, privateKey } = createSshKeyPair(keyAlgorithm, ca.friendlyName);
|
||||||
|
|
||||||
const orgKmsKeyId = await kmsService.getOrgKmsKeyId(actorOrgId);
|
// TODO: update to sshEncryptor
|
||||||
const kmsEncryptor = await kmsService.encryptWithKmsKey({
|
const { encryptor: secretManagerEncryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
kmsId: orgKmsKeyId
|
type: KmsDataKey.SecretManager,
|
||||||
});
|
projectId
|
||||||
|
|
||||||
const { cipherTextBlob: encryptedPrivateKey } = await kmsEncryptor({
|
|
||||||
plainText: Buffer.from(privateKey, "utf8")
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await sshCertificateAuthoritySecretDAL.create(
|
await sshCertificateAuthoritySecretDAL.create(
|
||||||
{
|
{
|
||||||
sshCaId: ca.id,
|
sshCaId: ca.id,
|
||||||
encryptedPrivateKey
|
encryptedPrivateKey: secretManagerEncryptor({ plainText: Buffer.from(privateKey, "utf8") }).cipherTextBlob
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
@@ -119,28 +126,28 @@ export const sshCertificateAuthorityServiceFactory = ({
|
|||||||
const ca = await sshCertificateAuthorityDAL.findById(caId);
|
const ca = await sshCertificateAuthorityDAL.findById(caId);
|
||||||
if (!ca) throw new NotFoundError({ message: `SSH CA with ID '${caId}' not found` });
|
if (!ca) throw new NotFoundError({ message: `SSH CA with ID '${caId}' not found` });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getProjectPermission(
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
ca.orgId,
|
ca.projectId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
);
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
OrgPermissionSubjects.SshCertificateAuthorities
|
ProjectPermissionSub.SshCertificateAuthorities
|
||||||
);
|
);
|
||||||
|
|
||||||
const sshCaSecret = await sshCertificateAuthoritySecretDAL.findOne({ sshCaId: ca.id });
|
const sshCaSecret = await sshCertificateAuthoritySecretDAL.findOne({ sshCaId: ca.id });
|
||||||
|
|
||||||
// decrypt secret
|
// TODO: update to sshDecryptor
|
||||||
const orgKmsKeyId = await kmsService.getOrgKmsKeyId(actorOrgId);
|
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
const kmsDecryptor = await kmsService.decryptWithKmsKey({
|
type: KmsDataKey.SecretManager,
|
||||||
kmsId: orgKmsKeyId
|
projectId: ca.projectId
|
||||||
});
|
});
|
||||||
|
|
||||||
const decryptedCaPrivateKey = await kmsDecryptor({
|
const decryptedCaPrivateKey = secretManagerDecryptor({
|
||||||
cipherTextBlob: sshCaSecret.encryptedPrivateKey
|
cipherTextBlob: sshCaSecret.encryptedPrivateKey
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -158,13 +165,13 @@ export const sshCertificateAuthorityServiceFactory = ({
|
|||||||
|
|
||||||
const sshCaSecret = await sshCertificateAuthoritySecretDAL.findOne({ sshCaId: ca.id });
|
const sshCaSecret = await sshCertificateAuthoritySecretDAL.findOne({ sshCaId: ca.id });
|
||||||
|
|
||||||
// decrypt secret
|
// TODO: update to sshDecryptor
|
||||||
const orgKmsKeyId = await kmsService.getOrgKmsKeyId(ca.orgId);
|
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
const kmsDecryptor = await kmsService.decryptWithKmsKey({
|
type: KmsDataKey.SecretManager,
|
||||||
kmsId: orgKmsKeyId
|
projectId: ca.projectId
|
||||||
});
|
});
|
||||||
|
|
||||||
const decryptedCaPrivateKey = await kmsDecryptor({
|
const decryptedCaPrivateKey = secretManagerDecryptor({
|
||||||
cipherTextBlob: sshCaSecret.encryptedPrivateKey
|
cipherTextBlob: sshCaSecret.encryptedPrivateKey
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -189,30 +196,30 @@ export const sshCertificateAuthorityServiceFactory = ({
|
|||||||
const ca = await sshCertificateAuthorityDAL.findById(caId);
|
const ca = await sshCertificateAuthorityDAL.findById(caId);
|
||||||
if (!ca) throw new NotFoundError({ message: `SSH CA with ID '${caId}' not found` });
|
if (!ca) throw new NotFoundError({ message: `SSH CA with ID '${caId}' not found` });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getProjectPermission(
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
ca.orgId,
|
ca.projectId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
);
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Edit,
|
ProjectPermissionActions.Edit,
|
||||||
OrgPermissionSubjects.SshCertificateAuthorities
|
ProjectPermissionSub.SshCertificateAuthorities
|
||||||
);
|
);
|
||||||
|
|
||||||
const updatedCa = await sshCertificateAuthorityDAL.updateById(caId, { friendlyName, status });
|
const updatedCa = await sshCertificateAuthorityDAL.updateById(caId, { friendlyName, status });
|
||||||
|
|
||||||
const sshCaSecret = await sshCertificateAuthoritySecretDAL.findOne({ sshCaId: ca.id });
|
const sshCaSecret = await sshCertificateAuthoritySecretDAL.findOne({ sshCaId: ca.id });
|
||||||
|
|
||||||
// decrypt secret
|
// TODO: update to sshDecryptor
|
||||||
const orgKmsKeyId = await kmsService.getOrgKmsKeyId(actorOrgId);
|
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
const kmsDecryptor = await kmsService.decryptWithKmsKey({
|
type: KmsDataKey.SecretManager,
|
||||||
kmsId: orgKmsKeyId
|
projectId: ca.projectId
|
||||||
});
|
});
|
||||||
|
|
||||||
const decryptedCaPrivateKey = await kmsDecryptor({
|
const decryptedCaPrivateKey = secretManagerDecryptor({
|
||||||
cipherTextBlob: sshCaSecret.encryptedPrivateKey
|
cipherTextBlob: sshCaSecret.encryptedPrivateKey
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -228,17 +235,17 @@ export const sshCertificateAuthorityServiceFactory = ({
|
|||||||
const ca = await sshCertificateAuthorityDAL.findById(caId);
|
const ca = await sshCertificateAuthorityDAL.findById(caId);
|
||||||
if (!ca) throw new NotFoundError({ message: `SSH CA with ID '${caId}' not found` });
|
if (!ca) throw new NotFoundError({ message: `SSH CA with ID '${caId}' not found` });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getProjectPermission(
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
ca.orgId,
|
ca.projectId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
);
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Delete,
|
ProjectPermissionActions.Delete,
|
||||||
OrgPermissionSubjects.SshCertificateAuthorities
|
ProjectPermissionSub.SshCertificateAuthorities
|
||||||
);
|
);
|
||||||
|
|
||||||
const deletedCa = await sshCertificateAuthorityDAL.deleteById(caId);
|
const deletedCa = await sshCertificateAuthorityDAL.deleteById(caId);
|
||||||
@@ -251,6 +258,7 @@ export const sshCertificateAuthorityServiceFactory = ({
|
|||||||
* SSH public key is signed using CA behind SSH certificate with name [templateName].
|
* SSH public key is signed using CA behind SSH certificate with name [templateName].
|
||||||
*/
|
*/
|
||||||
const issueSshCreds = async ({
|
const issueSshCreds = async ({
|
||||||
|
projectId,
|
||||||
templateName,
|
templateName,
|
||||||
keyAlgorithm,
|
keyAlgorithm,
|
||||||
certType,
|
certType,
|
||||||
@@ -262,22 +270,25 @@ export const sshCertificateAuthorityServiceFactory = ({
|
|||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
}: TIssueSshCredsDTO) => {
|
}: TIssueSshCredsDTO) => {
|
||||||
const sshCertificateTemplate = await sshCertificateTemplateDAL.getByName(templateName, actorOrgId);
|
const sshCertificateTemplate = await sshCertificateTemplateDAL.getByName(templateName, projectId);
|
||||||
if (!sshCertificateTemplate) {
|
if (!sshCertificateTemplate) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
message: "No SSH certificate template found with specified name"
|
message: "No SSH certificate template found with specified name"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getProjectPermission(
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
sshCertificateTemplate.projectId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
);
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.SshCertificates);
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionSub.SshCertificates
|
||||||
|
);
|
||||||
|
|
||||||
if (sshCertificateTemplate.caStatus === SshCaStatus.DISABLED) {
|
if (sshCertificateTemplate.caStatus === SshCaStatus.DISABLED) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -307,13 +318,13 @@ export const sshCertificateAuthorityServiceFactory = ({
|
|||||||
|
|
||||||
const sshCaSecret = await sshCertificateAuthoritySecretDAL.findOne({ sshCaId: sshCertificateTemplate.sshCaId });
|
const sshCaSecret = await sshCertificateAuthoritySecretDAL.findOne({ sshCaId: sshCertificateTemplate.sshCaId });
|
||||||
|
|
||||||
// decrypt secret
|
// TODO: update to sshDecryptor
|
||||||
const orgKmsKeyId = await kmsService.getOrgKmsKeyId(actorOrgId);
|
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
const kmsDecryptor = await kmsService.decryptWithKmsKey({
|
type: KmsDataKey.SecretManager,
|
||||||
kmsId: orgKmsKeyId
|
projectId
|
||||||
});
|
});
|
||||||
|
|
||||||
const decryptedCaPrivateKey = await kmsDecryptor({
|
const decryptedCaPrivateKey = secretManagerDecryptor({
|
||||||
cipherTextBlob: sshCaSecret.encryptedPrivateKey
|
cipherTextBlob: sshCaSecret.encryptedPrivateKey
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -329,16 +340,38 @@ export const sshCertificateAuthorityServiceFactory = ({
|
|||||||
certType
|
certType
|
||||||
});
|
});
|
||||||
|
|
||||||
await sshCertificateDAL.create({
|
// TODO: update to sshEncryptor
|
||||||
|
const { encryptor: secretManagerEncryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
|
type: KmsDataKey.SecretManager,
|
||||||
|
projectId: sshCertificateTemplate.projectId
|
||||||
|
});
|
||||||
|
|
||||||
|
const encryptedCertificate = secretManagerEncryptor({
|
||||||
|
plainText: Buffer.from(signedPublicKey, "utf8")
|
||||||
|
}).cipherTextBlob;
|
||||||
|
|
||||||
|
await sshCertificateDAL.transaction(async (tx) => {
|
||||||
|
const cert = await sshCertificateDAL.create(
|
||||||
|
{
|
||||||
sshCaId: sshCertificateTemplate.sshCaId,
|
sshCaId: sshCertificateTemplate.sshCaId,
|
||||||
sshCertificateTemplateId: sshCertificateTemplate.id,
|
sshCertificateTemplateId: sshCertificateTemplate.id,
|
||||||
serialNumber,
|
serialNumber,
|
||||||
certType,
|
certType,
|
||||||
publicKey,
|
|
||||||
principals,
|
principals,
|
||||||
keyId,
|
keyId,
|
||||||
notBefore: new Date(),
|
notBefore: new Date(),
|
||||||
notAfter: new Date(Date.now() + ttl * 1000)
|
notAfter: new Date(Date.now() + ttl * 1000)
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
|
||||||
|
await sshCertificateBodyDAL.create(
|
||||||
|
{
|
||||||
|
sshCertId: cert.id,
|
||||||
|
encryptedCertificate
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -357,6 +390,7 @@ export const sshCertificateAuthorityServiceFactory = ({
|
|||||||
* using CA behind SSH certificate template with name [templateName]
|
* using CA behind SSH certificate template with name [templateName]
|
||||||
*/
|
*/
|
||||||
const signSshKey = async ({
|
const signSshKey = async ({
|
||||||
|
projectId,
|
||||||
templateName,
|
templateName,
|
||||||
publicKey,
|
publicKey,
|
||||||
certType,
|
certType,
|
||||||
@@ -368,22 +402,25 @@ export const sshCertificateAuthorityServiceFactory = ({
|
|||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
}: TSignSshKeyDTO) => {
|
}: TSignSshKeyDTO) => {
|
||||||
const sshCertificateTemplate = await sshCertificateTemplateDAL.getByName(templateName, actorOrgId);
|
const sshCertificateTemplate = await sshCertificateTemplateDAL.getByName(templateName, projectId);
|
||||||
if (!sshCertificateTemplate) {
|
if (!sshCertificateTemplate) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
message: "No SSH certificate template found with specified name"
|
message: "No SSH certificate template found with specified name"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getProjectPermission(
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
sshCertificateTemplate.projectId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
);
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.SshCertificates);
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionSub.SshCertificates
|
||||||
|
);
|
||||||
|
|
||||||
if (sshCertificateTemplate.caStatus === SshCaStatus.DISABLED) {
|
if (sshCertificateTemplate.caStatus === SshCaStatus.DISABLED) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -413,13 +450,13 @@ export const sshCertificateAuthorityServiceFactory = ({
|
|||||||
|
|
||||||
const sshCaSecret = await sshCertificateAuthoritySecretDAL.findOne({ sshCaId: sshCertificateTemplate.sshCaId });
|
const sshCaSecret = await sshCertificateAuthoritySecretDAL.findOne({ sshCaId: sshCertificateTemplate.sshCaId });
|
||||||
|
|
||||||
// decrypt secret
|
// TODO: update to sshDecryptor
|
||||||
const orgKmsKeyId = await kmsService.getOrgKmsKeyId(actorOrgId);
|
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
const kmsDecryptor = await kmsService.decryptWithKmsKey({
|
type: KmsDataKey.SecretManager,
|
||||||
kmsId: orgKmsKeyId
|
projectId
|
||||||
});
|
});
|
||||||
|
|
||||||
const decryptedCaPrivateKey = await kmsDecryptor({
|
const decryptedCaPrivateKey = secretManagerDecryptor({
|
||||||
cipherTextBlob: sshCaSecret.encryptedPrivateKey
|
cipherTextBlob: sshCaSecret.encryptedPrivateKey
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -432,16 +469,38 @@ export const sshCertificateAuthorityServiceFactory = ({
|
|||||||
certType
|
certType
|
||||||
});
|
});
|
||||||
|
|
||||||
await sshCertificateDAL.create({
|
// TODO: update to sshEncryptor
|
||||||
|
const { encryptor: secretManagerEncryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
|
type: KmsDataKey.SecretManager,
|
||||||
|
projectId: sshCertificateTemplate.projectId
|
||||||
|
});
|
||||||
|
|
||||||
|
const encryptedCertificate = secretManagerEncryptor({
|
||||||
|
plainText: Buffer.from(signedPublicKey, "utf8")
|
||||||
|
}).cipherTextBlob;
|
||||||
|
|
||||||
|
await sshCertificateDAL.transaction(async (tx) => {
|
||||||
|
const cert = await sshCertificateDAL.create(
|
||||||
|
{
|
||||||
sshCaId: sshCertificateTemplate.sshCaId,
|
sshCaId: sshCertificateTemplate.sshCaId,
|
||||||
sshCertificateTemplateId: sshCertificateTemplate.id,
|
sshCertificateTemplateId: sshCertificateTemplate.id,
|
||||||
serialNumber,
|
serialNumber,
|
||||||
certType,
|
certType,
|
||||||
publicKey,
|
|
||||||
principals,
|
principals,
|
||||||
keyId,
|
keyId,
|
||||||
notBefore: new Date(),
|
notBefore: new Date(),
|
||||||
notAfter: new Date(Date.now() + ttl * 1000)
|
notAfter: new Date(Date.now() + ttl * 1000)
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
|
||||||
|
await sshCertificateBodyDAL.create(
|
||||||
|
{
|
||||||
|
sshCertId: cert.id,
|
||||||
|
encryptedCertificate
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return { serialNumber, signedPublicKey, certificateTemplate: sshCertificateTemplate, ttl, keyId };
|
return { serialNumber, signedPublicKey, certificateTemplate: sshCertificateTemplate, ttl, keyId };
|
||||||
@@ -457,17 +516,17 @@ export const sshCertificateAuthorityServiceFactory = ({
|
|||||||
const ca = await sshCertificateAuthorityDAL.findById(caId);
|
const ca = await sshCertificateAuthorityDAL.findById(caId);
|
||||||
if (!ca) throw new NotFoundError({ message: `SSH CA with ID '${caId}' not found` });
|
if (!ca) throw new NotFoundError({ message: `SSH CA with ID '${caId}' not found` });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getProjectPermission(
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
ca.projectId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
);
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
OrgPermissionSubjects.SshCertificateTemplates
|
ProjectPermissionSub.SshCertificateTemplates
|
||||||
);
|
);
|
||||||
|
|
||||||
const certificateTemplates = await sshCertificateTemplateDAL.find({ sshCaId: caId });
|
const certificateTemplates = await sshCertificateTemplateDAL.find({ sshCaId: caId });
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { TOrgPermission } from "@app/lib/types";
|
import { TProjectPermission } from "@app/lib/types";
|
||||||
import { CertKeyAlgorithm } from "@app/services/certificate/certificate-types";
|
import { CertKeyAlgorithm } from "@app/services/certificate/certificate-types";
|
||||||
|
|
||||||
export enum SshCaStatus {
|
export enum SshCaStatus {
|
||||||
@@ -14,11 +14,11 @@ export enum SshCertType {
|
|||||||
export type TCreateSshCaDTO = {
|
export type TCreateSshCaDTO = {
|
||||||
friendlyName: string;
|
friendlyName: string;
|
||||||
keyAlgorithm: CertKeyAlgorithm;
|
keyAlgorithm: CertKeyAlgorithm;
|
||||||
} & Omit<TOrgPermission, "orgId">;
|
} & TProjectPermission;
|
||||||
|
|
||||||
export type TGetSshCaDTO = {
|
export type TGetSshCaDTO = {
|
||||||
caId: string;
|
caId: string;
|
||||||
} & Omit<TOrgPermission, "orgId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
export type TGetSshCaPublicKeyDTO = {
|
export type TGetSshCaPublicKeyDTO = {
|
||||||
caId: string;
|
caId: string;
|
||||||
@@ -28,11 +28,11 @@ export type TUpdateSshCaDTO = {
|
|||||||
caId: string;
|
caId: string;
|
||||||
friendlyName?: string;
|
friendlyName?: string;
|
||||||
status?: SshCaStatus;
|
status?: SshCaStatus;
|
||||||
} & Omit<TOrgPermission, "orgId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
export type TDeleteSshCaDTO = {
|
export type TDeleteSshCaDTO = {
|
||||||
caId: string;
|
caId: string;
|
||||||
} & Omit<TOrgPermission, "orgId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
export type TIssueSshCredsDTO = {
|
export type TIssueSshCredsDTO = {
|
||||||
templateName: string;
|
templateName: string;
|
||||||
@@ -41,7 +41,7 @@ export type TIssueSshCredsDTO = {
|
|||||||
principals: string[];
|
principals: string[];
|
||||||
ttl?: string;
|
ttl?: string;
|
||||||
keyId?: string;
|
keyId?: string;
|
||||||
} & Omit<TOrgPermission, "orgId">;
|
} & TProjectPermission;
|
||||||
|
|
||||||
export type TSignSshKeyDTO = {
|
export type TSignSshKeyDTO = {
|
||||||
templateName: string;
|
templateName: string;
|
||||||
@@ -50,11 +50,11 @@ export type TSignSshKeyDTO = {
|
|||||||
principals: string[];
|
principals: string[];
|
||||||
ttl?: string;
|
ttl?: string;
|
||||||
keyId?: string;
|
keyId?: string;
|
||||||
} & Omit<TOrgPermission, "orgId">;
|
} & TProjectPermission;
|
||||||
|
|
||||||
export type TGetSshCaCertificateTemplatesDTO = {
|
export type TGetSshCaCertificateTemplatesDTO = {
|
||||||
caId: string;
|
caId: string;
|
||||||
} & Omit<TOrgPermission, "orgId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
export type TCreateSshCertDTO = {
|
export type TCreateSshCertDTO = {
|
||||||
caPrivateKey: string;
|
caPrivateKey: string;
|
||||||
|
|||||||
@@ -384,17 +384,6 @@ export const ORGANIZATIONS = {
|
|||||||
},
|
},
|
||||||
LIST_GROUPS: {
|
LIST_GROUPS: {
|
||||||
organizationId: "The ID of the organization to list groups for."
|
organizationId: "The ID of the organization to list groups for."
|
||||||
},
|
|
||||||
LIST_SSH_CAS: {
|
|
||||||
organizationId: "The ID of the organization to list SSH CAs for."
|
|
||||||
},
|
|
||||||
LIST_SSH_CERTIFICATES: {
|
|
||||||
organizationId: "The ID of the organization to list SSH certificates for.",
|
|
||||||
offset: "The offset to start from. If you enter 10, it will start from the 10th SSH certificate.",
|
|
||||||
limit: "The number of SSH certificates to return."
|
|
||||||
},
|
|
||||||
LIST_SSH_CERTIFICATE_TEMPLATES: {
|
|
||||||
organizationId: "The ID of the organization to list SSH certificate templates for."
|
|
||||||
}
|
}
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
@@ -455,7 +444,15 @@ export const PROJECTS = {
|
|||||||
workspaceId: "The ID of the project to list integration auths for."
|
workspaceId: "The ID of the project to list integration auths for."
|
||||||
},
|
},
|
||||||
LIST_SSH_CAS: {
|
LIST_SSH_CAS: {
|
||||||
slug: "The slug of the project to list SSH CAs for."
|
projectId: "The ID of the project to list SSH CAs for."
|
||||||
|
},
|
||||||
|
LIST_SSH_CERTIFICATES: {
|
||||||
|
projectId: "The ID of the project to list SSH certificates for.",
|
||||||
|
offset: "The offset to start from. If you enter 10, it will start from the 10th SSH certificate.",
|
||||||
|
limit: "The number of SSH certificates to return."
|
||||||
|
},
|
||||||
|
LIST_SSH_CERTIFICATE_TEMPLATES: {
|
||||||
|
projectId: "The ID of the project to list SSH certificate templates for."
|
||||||
},
|
},
|
||||||
LIST_CAS: {
|
LIST_CAS: {
|
||||||
slug: "The slug of the project to list CAs for.",
|
slug: "The slug of the project to list CAs for.",
|
||||||
@@ -1148,6 +1145,7 @@ export const AUDIT_LOG_STREAMS = {
|
|||||||
|
|
||||||
export const SSH_CERTIFICATE_AUTHORITIES = {
|
export const SSH_CERTIFICATE_AUTHORITIES = {
|
||||||
CREATE: {
|
CREATE: {
|
||||||
|
projectId: "The ID of the project to create the SSH CA in.",
|
||||||
friendlyName: "A friendly name for the SSH CA.",
|
friendlyName: "A friendly name for the SSH CA.",
|
||||||
keyAlgorithm: "The type of public key algorithm and size, in bits, of the key pair for the SSH CA."
|
keyAlgorithm: "The type of public key algorithm and size, in bits, of the key pair for the SSH CA."
|
||||||
},
|
},
|
||||||
@@ -1169,6 +1167,7 @@ export const SSH_CERTIFICATE_AUTHORITIES = {
|
|||||||
sshCaId: "The ID of the SSH CA to get the certificate templates for."
|
sshCaId: "The ID of the SSH CA to get the certificate templates for."
|
||||||
},
|
},
|
||||||
SIGN_SSH_KEY: {
|
SIGN_SSH_KEY: {
|
||||||
|
projectId: "The ID of the project to sign the SSH public key for.",
|
||||||
templateName: "The name of the SSH certificate template to sign the SSH public key with.",
|
templateName: "The name of the SSH certificate template to sign the SSH public key with.",
|
||||||
publicKey: "The SSH public key to sign.",
|
publicKey: "The SSH public key to sign.",
|
||||||
certType: "The type of certificate to issue. This can be one of user or host.",
|
certType: "The type of certificate to issue. This can be one of user or host.",
|
||||||
@@ -1179,6 +1178,7 @@ export const SSH_CERTIFICATE_AUTHORITIES = {
|
|||||||
signedKey: "The SSH certificate or signed SSH public key."
|
signedKey: "The SSH certificate or signed SSH public key."
|
||||||
},
|
},
|
||||||
ISSUE_SSH_CREDENTIALS: {
|
ISSUE_SSH_CREDENTIALS: {
|
||||||
|
projectId: "The ID of the project to issue the SSH credentials for.",
|
||||||
templateName: "The name of the SSH certificate template to issue the SSH credentials with.",
|
templateName: "The name of the SSH certificate template to issue the SSH credentials with.",
|
||||||
keyAlgorithm: "The type of public key algorithm and size, in bits, of the key pair for the SSH CA.",
|
keyAlgorithm: "The type of public key algorithm and size, in bits, of the key pair for the SSH CA.",
|
||||||
certType: "The type of certificate to issue. This can be one of user or host.",
|
certType: "The type of certificate to issue. This can be one of user or host.",
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ import { snapshotSecretV2DALFactory } from "@app/ee/services/secret-snapshot/sna
|
|||||||
import { sshCertificateAuthorityDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-dal";
|
import { sshCertificateAuthorityDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-dal";
|
||||||
import { sshCertificateAuthoritySecretDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-secret-dal";
|
import { sshCertificateAuthoritySecretDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-secret-dal";
|
||||||
import { sshCertificateAuthorityServiceFactory } from "@app/ee/services/ssh/ssh-certificate-authority-service";
|
import { sshCertificateAuthorityServiceFactory } from "@app/ee/services/ssh/ssh-certificate-authority-service";
|
||||||
|
import { sshCertificateBodyDALFactory } from "@app/ee/services/ssh-certificate/ssh-certificate-body-dal";
|
||||||
import { sshCertificateDALFactory } from "@app/ee/services/ssh-certificate/ssh-certificate-dal";
|
import { sshCertificateDALFactory } from "@app/ee/services/ssh-certificate/ssh-certificate-dal";
|
||||||
import { sshCertificateTemplateDALFactory } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-dal";
|
import { sshCertificateTemplateDALFactory } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-dal";
|
||||||
import { sshCertificateTemplateServiceFactory } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-service";
|
import { sshCertificateTemplateServiceFactory } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-service";
|
||||||
@@ -349,6 +350,7 @@ export const registerRoutes = async (
|
|||||||
const dynamicSecretLeaseDAL = dynamicSecretLeaseDALFactory(db);
|
const dynamicSecretLeaseDAL = dynamicSecretLeaseDALFactory(db);
|
||||||
|
|
||||||
const sshCertificateDAL = sshCertificateDALFactory(db);
|
const sshCertificateDAL = sshCertificateDALFactory(db);
|
||||||
|
const sshCertificateBodyDAL = sshCertificateBodyDALFactory(db);
|
||||||
const sshCertificateAuthorityDAL = sshCertificateAuthorityDALFactory(db);
|
const sshCertificateAuthorityDAL = sshCertificateAuthorityDALFactory(db);
|
||||||
const sshCertificateAuthoritySecretDAL = sshCertificateAuthoritySecretDALFactory(db);
|
const sshCertificateAuthoritySecretDAL = sshCertificateAuthoritySecretDALFactory(db);
|
||||||
const sshCertificateTemplateDAL = sshCertificateTemplateDALFactory(db);
|
const sshCertificateTemplateDAL = sshCertificateTemplateDALFactory(db);
|
||||||
@@ -565,10 +567,7 @@ export const registerRoutes = async (
|
|||||||
groupDAL,
|
groupDAL,
|
||||||
orgBotDAL,
|
orgBotDAL,
|
||||||
oidcConfigDAL,
|
oidcConfigDAL,
|
||||||
projectBotService,
|
projectBotService
|
||||||
sshCertificateAuthorityDAL,
|
|
||||||
sshCertificateDAL,
|
|
||||||
sshCertificateTemplateDAL
|
|
||||||
});
|
});
|
||||||
const signupService = authSignupServiceFactory({
|
const signupService = authSignupServiceFactory({
|
||||||
tokenService,
|
tokenService,
|
||||||
@@ -721,6 +720,7 @@ export const registerRoutes = async (
|
|||||||
sshCertificateAuthoritySecretDAL,
|
sshCertificateAuthoritySecretDAL,
|
||||||
sshCertificateTemplateDAL,
|
sshCertificateTemplateDAL,
|
||||||
sshCertificateDAL,
|
sshCertificateDAL,
|
||||||
|
sshCertificateBodyDAL,
|
||||||
kmsService,
|
kmsService,
|
||||||
permissionService
|
permissionService
|
||||||
});
|
});
|
||||||
@@ -817,6 +817,9 @@ export const registerRoutes = async (
|
|||||||
certificateDAL,
|
certificateDAL,
|
||||||
pkiAlertDAL,
|
pkiAlertDAL,
|
||||||
pkiCollectionDAL,
|
pkiCollectionDAL,
|
||||||
|
sshCertificateAuthorityDAL,
|
||||||
|
sshCertificateDAL,
|
||||||
|
sshCertificateTemplateDAL,
|
||||||
projectUserMembershipRoleDAL,
|
projectUserMembershipRoleDAL,
|
||||||
identityProjectMembershipRoleDAL,
|
identityProjectMembershipRoleDAL,
|
||||||
keyStore,
|
keyStore,
|
||||||
|
|||||||
@@ -11,9 +11,6 @@ import {
|
|||||||
UsersSchema
|
UsersSchema
|
||||||
} from "@app/db/schemas";
|
} from "@app/db/schemas";
|
||||||
import { EventType, UserAgentType } from "@app/ee/services/audit-log/audit-log-types";
|
import { EventType, UserAgentType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { sanitizedSshCa } from "@app/ee/services/ssh/ssh-certificate-authority-schema";
|
|
||||||
import { sanitizedSshCertificate } from "@app/ee/services/ssh-certificate/ssh-certificate-schema";
|
|
||||||
import { sanitizedSshCertificateTemplate } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-schema";
|
|
||||||
import { AUDIT_LOGS, ORGANIZATIONS } from "@app/lib/api-docs";
|
import { AUDIT_LOGS, ORGANIZATIONS } from "@app/lib/api-docs";
|
||||||
import { getLastMidnightDateISO } from "@app/lib/fn";
|
import { getLastMidnightDateISO } from "@app/lib/fn";
|
||||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
@@ -407,101 +404,4 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
|
|||||||
return { groups };
|
return { groups };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
server.route({
|
|
||||||
method: "GET",
|
|
||||||
url: "/:organizationId/ssh-certificates",
|
|
||||||
config: {
|
|
||||||
rateLimit: readLimit
|
|
||||||
},
|
|
||||||
schema: {
|
|
||||||
params: z.object({
|
|
||||||
organizationId: z.string().trim().describe(ORGANIZATIONS.LIST_SSH_CAS.organizationId)
|
|
||||||
}),
|
|
||||||
querystring: z.object({
|
|
||||||
offset: z.coerce.number().default(0).describe(ORGANIZATIONS.LIST_SSH_CERTIFICATES.offset),
|
|
||||||
limit: z.coerce.number().default(25).describe(ORGANIZATIONS.LIST_SSH_CERTIFICATES.limit)
|
|
||||||
}),
|
|
||||||
response: {
|
|
||||||
200: z.object({
|
|
||||||
certificates: z.array(sanitizedSshCertificate),
|
|
||||||
totalCount: z.number()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
|
||||||
handler: async (req) => {
|
|
||||||
const { certificates, totalCount } = await server.services.org.listOrgSshCertificates({
|
|
||||||
actorId: req.permission.id,
|
|
||||||
actorOrgId: req.permission.orgId,
|
|
||||||
actorAuthMethod: req.permission.authMethod,
|
|
||||||
actor: req.permission.type,
|
|
||||||
orgId: req.params.organizationId,
|
|
||||||
offset: req.query.offset,
|
|
||||||
limit: req.query.limit
|
|
||||||
});
|
|
||||||
|
|
||||||
return { certificates, totalCount };
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
server.route({
|
|
||||||
method: "GET",
|
|
||||||
url: "/:organizationId/ssh-certificate-templates",
|
|
||||||
config: {
|
|
||||||
rateLimit: readLimit
|
|
||||||
},
|
|
||||||
schema: {
|
|
||||||
params: z.object({
|
|
||||||
organizationId: z.string().trim().describe(ORGANIZATIONS.LIST_SSH_CERTIFICATE_TEMPLATES.organizationId)
|
|
||||||
}),
|
|
||||||
response: {
|
|
||||||
200: z.object({
|
|
||||||
certificateTemplates: z.array(sanitizedSshCertificateTemplate)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
|
||||||
handler: async (req) => {
|
|
||||||
const { certificateTemplates } = await server.services.org.listOrgSshCertificateTemplates({
|
|
||||||
actorId: req.permission.id,
|
|
||||||
actorOrgId: req.permission.orgId,
|
|
||||||
actorAuthMethod: req.permission.authMethod,
|
|
||||||
actor: req.permission.type,
|
|
||||||
orgId: req.params.organizationId
|
|
||||||
});
|
|
||||||
|
|
||||||
return { certificateTemplates };
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
server.route({
|
|
||||||
method: "GET",
|
|
||||||
url: "/:organizationId/ssh-cas",
|
|
||||||
config: {
|
|
||||||
rateLimit: readLimit
|
|
||||||
},
|
|
||||||
schema: {
|
|
||||||
params: z.object({
|
|
||||||
organizationId: z.string().trim().describe(ORGANIZATIONS.LIST_SSH_CAS.organizationId)
|
|
||||||
}),
|
|
||||||
response: {
|
|
||||||
200: z.object({
|
|
||||||
cas: z.array(sanitizedSshCa)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
|
||||||
handler: async (req) => {
|
|
||||||
const cas = await server.services.org.listOrgSshCas({
|
|
||||||
actorId: req.permission.id,
|
|
||||||
actorOrgId: req.permission.orgId,
|
|
||||||
actorAuthMethod: req.permission.authMethod,
|
|
||||||
actor: req.permission.type,
|
|
||||||
orgId: req.params.organizationId
|
|
||||||
});
|
|
||||||
|
|
||||||
return { cas };
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ import {
|
|||||||
} from "@app/db/schemas";
|
} from "@app/db/schemas";
|
||||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { InfisicalProjectTemplate } from "@app/ee/services/project-template/project-template-types";
|
import { InfisicalProjectTemplate } from "@app/ee/services/project-template/project-template-types";
|
||||||
|
import { sanitizedSshCa } from "@app/ee/services/ssh/ssh-certificate-authority-schema";
|
||||||
|
import { sanitizedSshCertificate } from "@app/ee/services/ssh-certificate/ssh-certificate-schema";
|
||||||
|
import { sanitizedSshCertificateTemplate } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-schema";
|
||||||
import { PROJECTS } from "@app/lib/api-docs";
|
import { PROJECTS } from "@app/lib/api-docs";
|
||||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { getTelemetryDistinctId } from "@app/server/lib/telemetry";
|
import { getTelemetryDistinctId } from "@app/server/lib/telemetry";
|
||||||
@@ -517,4 +520,101 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
|||||||
return { certificateTemplates };
|
return { certificateTemplates };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/:projectId/ssh-certificates",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
projectId: z.string().trim().describe(PROJECTS.LIST_SSH_CAS.projectId)
|
||||||
|
}),
|
||||||
|
querystring: z.object({
|
||||||
|
offset: z.coerce.number().default(0).describe(PROJECTS.LIST_SSH_CERTIFICATES.offset),
|
||||||
|
limit: z.coerce.number().default(25).describe(PROJECTS.LIST_SSH_CERTIFICATES.limit)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
certificates: z.array(sanitizedSshCertificate),
|
||||||
|
totalCount: z.number()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { certificates, totalCount } = await server.services.project.listProjectSshCertificates({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actorOrgId: req.permission.orgId,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actor: req.permission.type,
|
||||||
|
projectId: req.params.projectId,
|
||||||
|
offset: req.query.offset,
|
||||||
|
limit: req.query.limit
|
||||||
|
});
|
||||||
|
|
||||||
|
return { certificates, totalCount };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/:projectId/ssh-certificate-templates",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
projectId: z.string().trim().describe(PROJECTS.LIST_SSH_CERTIFICATE_TEMPLATES.projectId)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
certificateTemplates: z.array(sanitizedSshCertificateTemplate)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { certificateTemplates } = await server.services.project.listProjectSshCertificateTemplates({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actorOrgId: req.permission.orgId,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actor: req.permission.type,
|
||||||
|
projectId: req.params.projectId
|
||||||
|
});
|
||||||
|
|
||||||
|
return { certificateTemplates };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/:projectId/ssh-cas",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
projectId: z.string().trim().describe(PROJECTS.LIST_SSH_CAS.projectId)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
cas: z.array(sanitizedSshCa)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const cas = await server.services.project.listProjectSshCas({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actorOrgId: req.permission.orgId,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actor: req.permission.type,
|
||||||
|
projectId: req.params.projectId
|
||||||
|
});
|
||||||
|
|
||||||
|
return { cas };
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -24,9 +24,6 @@ import { TPermissionServiceFactory } from "@app/ee/services/permission/permissio
|
|||||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
||||||
import { TProjectUserAdditionalPrivilegeDALFactory } from "@app/ee/services/project-user-additional-privilege/project-user-additional-privilege-dal";
|
import { TProjectUserAdditionalPrivilegeDALFactory } from "@app/ee/services/project-user-additional-privilege/project-user-additional-privilege-dal";
|
||||||
import { TSamlConfigDALFactory } from "@app/ee/services/saml-config/saml-config-dal";
|
import { TSamlConfigDALFactory } from "@app/ee/services/saml-config/saml-config-dal";
|
||||||
import { TSshCertificateAuthorityDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-dal";
|
|
||||||
import { TSshCertificateDALFactory } from "@app/ee/services/ssh-certificate/ssh-certificate-dal";
|
|
||||||
import { TSshCertificateTemplateDALFactory } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-dal";
|
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { generateAsymmetricKeyPair } from "@app/lib/crypto";
|
import { generateAsymmetricKeyPair } from "@app/lib/crypto";
|
||||||
import { generateSymmetricKey, infisicalSymmetricDecrypt, infisicalSymmetricEncypt } from "@app/lib/crypto/encryption";
|
import { generateSymmetricKey, infisicalSymmetricDecrypt, infisicalSymmetricEncypt } from "@app/lib/crypto/encryption";
|
||||||
@@ -65,9 +62,6 @@ import {
|
|||||||
TGetOrgGroupsDTO,
|
TGetOrgGroupsDTO,
|
||||||
TGetOrgMembershipDTO,
|
TGetOrgMembershipDTO,
|
||||||
TInviteUserToOrgDTO,
|
TInviteUserToOrgDTO,
|
||||||
TListOrgSshCasDTO,
|
|
||||||
TListOrgSshCertificatesDTO,
|
|
||||||
TListOrgSshCertificateTemplatesDTO,
|
|
||||||
TListProjectMembershipsByOrgMembershipIdDTO,
|
TListProjectMembershipsByOrgMembershipIdDTO,
|
||||||
TUpdateOrgDTO,
|
TUpdateOrgDTO,
|
||||||
TUpdateOrgMembershipDTO,
|
TUpdateOrgMembershipDTO,
|
||||||
@@ -104,9 +98,6 @@ type TOrgServiceFactoryDep = {
|
|||||||
projectBotDAL: Pick<TProjectBotDALFactory, "findOne" | "updateById">;
|
projectBotDAL: Pick<TProjectBotDALFactory, "findOne" | "updateById">;
|
||||||
projectUserMembershipRoleDAL: Pick<TProjectUserMembershipRoleDALFactory, "insertMany" | "create">;
|
projectUserMembershipRoleDAL: Pick<TProjectUserMembershipRoleDALFactory, "insertMany" | "create">;
|
||||||
projectBotService: Pick<TProjectBotServiceFactory, "getBotKey">;
|
projectBotService: Pick<TProjectBotServiceFactory, "getBotKey">;
|
||||||
sshCertificateAuthorityDAL: Pick<TSshCertificateAuthorityDALFactory, "find">;
|
|
||||||
sshCertificateDAL: Pick<TSshCertificateDALFactory, "find" | "countSshCertificatesInOrg">;
|
|
||||||
sshCertificateTemplateDAL: Pick<TSshCertificateTemplateDALFactory, "find">;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TOrgServiceFactory = ReturnType<typeof orgServiceFactory>;
|
export type TOrgServiceFactory = ReturnType<typeof orgServiceFactory>;
|
||||||
@@ -134,9 +125,6 @@ export const orgServiceFactory = ({
|
|||||||
projectBotDAL,
|
projectBotDAL,
|
||||||
projectUserMembershipRoleDAL,
|
projectUserMembershipRoleDAL,
|
||||||
identityMetadataDAL,
|
identityMetadataDAL,
|
||||||
sshCertificateAuthorityDAL,
|
|
||||||
sshCertificateDAL,
|
|
||||||
sshCertificateTemplateDAL,
|
|
||||||
projectBotService
|
projectBotService
|
||||||
}: TOrgServiceFactoryDep) => {
|
}: TOrgServiceFactoryDep) => {
|
||||||
/*
|
/*
|
||||||
@@ -1139,91 +1127,6 @@ export const orgServiceFactory = ({
|
|||||||
return incidentContact;
|
return incidentContact;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Return list of SSH CAs for organization
|
|
||||||
*/
|
|
||||||
const listOrgSshCas = async ({ actorId, actorOrgId, actorAuthMethod, actor, orgId }: TListOrgSshCasDTO) => {
|
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
OrgPermissionActions.Read,
|
|
||||||
OrgPermissionSubjects.SshCertificateAuthorities
|
|
||||||
);
|
|
||||||
|
|
||||||
const cas = await sshCertificateAuthorityDAL.find(
|
|
||||||
{
|
|
||||||
orgId
|
|
||||||
},
|
|
||||||
{ sort: [["updatedAt", "desc"]] }
|
|
||||||
);
|
|
||||||
|
|
||||||
return cas;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return list of SSH certificates for organization
|
|
||||||
*/
|
|
||||||
const listOrgSshCertificates = async ({
|
|
||||||
limit = 25,
|
|
||||||
offset = 0,
|
|
||||||
actorId,
|
|
||||||
actorOrgId,
|
|
||||||
actorAuthMethod,
|
|
||||||
actor,
|
|
||||||
orgId
|
|
||||||
}: TListOrgSshCertificatesDTO) => {
|
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.SshCertificates);
|
|
||||||
|
|
||||||
const cas = await sshCertificateAuthorityDAL.find({
|
|
||||||
orgId
|
|
||||||
});
|
|
||||||
|
|
||||||
const certificates = await sshCertificateDAL.find(
|
|
||||||
{
|
|
||||||
$in: {
|
|
||||||
sshCaId: cas.map((ca) => ca.id)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ offset, limit, sort: [["updatedAt", "desc"]] }
|
|
||||||
);
|
|
||||||
|
|
||||||
const count = await sshCertificateDAL.countSshCertificatesInOrg(orgId);
|
|
||||||
|
|
||||||
return { certificates, totalCount: count };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return list of SSH certificate templates for organization
|
|
||||||
*/
|
|
||||||
const listOrgSshCertificateTemplates = async ({
|
|
||||||
actorId,
|
|
||||||
actorOrgId,
|
|
||||||
actorAuthMethod,
|
|
||||||
actor,
|
|
||||||
orgId
|
|
||||||
}: TListOrgSshCertificateTemplatesDTO) => {
|
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
OrgPermissionActions.Read,
|
|
||||||
OrgPermissionSubjects.SshCertificateTemplates
|
|
||||||
);
|
|
||||||
|
|
||||||
const cas = await sshCertificateAuthorityDAL.find({
|
|
||||||
orgId
|
|
||||||
});
|
|
||||||
|
|
||||||
const certificateTemplates = await sshCertificateTemplateDAL.find({
|
|
||||||
$in: {
|
|
||||||
sshCaId: cas.map((ca) => ca.id)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return { certificateTemplates };
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
findOrganizationById,
|
findOrganizationById,
|
||||||
findAllOrgMembers,
|
findAllOrgMembers,
|
||||||
@@ -1245,9 +1148,6 @@ export const orgServiceFactory = ({
|
|||||||
deleteIncidentContact,
|
deleteIncidentContact,
|
||||||
getOrgGroups,
|
getOrgGroups,
|
||||||
listProjectMembershipsByOrgMembershipId,
|
listProjectMembershipsByOrgMembershipId,
|
||||||
findOrgBySlug,
|
findOrgBySlug
|
||||||
listOrgSshCas,
|
|
||||||
listOrgSshCertificates,
|
|
||||||
listOrgSshCertificateTemplates
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -75,13 +75,6 @@ export type TListProjectMembershipsByOrgMembershipIdDTO = {
|
|||||||
orgMembershipId: string;
|
orgMembershipId: string;
|
||||||
} & TOrgPermission;
|
} & TOrgPermission;
|
||||||
|
|
||||||
export type TListOrgSshCasDTO = TOrgPermission;
|
|
||||||
export type TListOrgSshCertificateTemplatesDTO = TOrgPermission;
|
|
||||||
export type TListOrgSshCertificatesDTO = {
|
|
||||||
offset: number;
|
|
||||||
limit: number;
|
|
||||||
} & TOrgPermission;
|
|
||||||
|
|
||||||
export enum OrgAuthMethod {
|
export enum OrgAuthMethod {
|
||||||
OIDC = "oidc",
|
OIDC = "oidc",
|
||||||
SAML = "saml"
|
SAML = "saml"
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ import { TPermissionServiceFactory } from "@app/ee/services/permission/permissio
|
|||||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
||||||
import { TProjectTemplateServiceFactory } from "@app/ee/services/project-template/project-template-service";
|
import { TProjectTemplateServiceFactory } from "@app/ee/services/project-template/project-template-service";
|
||||||
import { InfisicalProjectTemplate } from "@app/ee/services/project-template/project-template-types";
|
import { InfisicalProjectTemplate } from "@app/ee/services/project-template/project-template-types";
|
||||||
|
import { TSshCertificateAuthorityDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-dal";
|
||||||
|
import { TSshCertificateDALFactory } from "@app/ee/services/ssh-certificate/ssh-certificate-dal";
|
||||||
|
import { TSshCertificateTemplateDALFactory } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-dal";
|
||||||
import { TKeyStoreFactory } from "@app/keystore/keystore";
|
import { TKeyStoreFactory } from "@app/keystore/keystore";
|
||||||
import { isAtLeastAsPrivileged } from "@app/lib/casl";
|
import { isAtLeastAsPrivileged } from "@app/lib/casl";
|
||||||
import { infisicalSymmetricEncypt } from "@app/lib/crypto/encryption";
|
import { infisicalSymmetricEncypt } from "@app/lib/crypto/encryption";
|
||||||
@@ -53,6 +56,9 @@ import {
|
|||||||
TListProjectCertificateTemplatesDTO,
|
TListProjectCertificateTemplatesDTO,
|
||||||
TListProjectCertsDTO,
|
TListProjectCertsDTO,
|
||||||
TListProjectsDTO,
|
TListProjectsDTO,
|
||||||
|
TListProjectSshCasDTO,
|
||||||
|
TListProjectSshCertificatesDTO,
|
||||||
|
TListProjectSshCertificateTemplatesDTO,
|
||||||
TLoadProjectKmsBackupDTO,
|
TLoadProjectKmsBackupDTO,
|
||||||
TToggleProjectAutoCapitalizationDTO,
|
TToggleProjectAutoCapitalizationDTO,
|
||||||
TUpdateAuditLogsRetentionDTO,
|
TUpdateAuditLogsRetentionDTO,
|
||||||
@@ -90,6 +96,9 @@ type TProjectServiceFactoryDep = {
|
|||||||
certificateTemplateDAL: Pick<TCertificateTemplateDALFactory, "getCertTemplatesByProjectId">;
|
certificateTemplateDAL: Pick<TCertificateTemplateDALFactory, "getCertTemplatesByProjectId">;
|
||||||
pkiAlertDAL: Pick<TPkiAlertDALFactory, "find">;
|
pkiAlertDAL: Pick<TPkiAlertDALFactory, "find">;
|
||||||
pkiCollectionDAL: Pick<TPkiCollectionDALFactory, "find">;
|
pkiCollectionDAL: Pick<TPkiCollectionDALFactory, "find">;
|
||||||
|
sshCertificateAuthorityDAL: Pick<TSshCertificateAuthorityDALFactory, "find">;
|
||||||
|
sshCertificateDAL: Pick<TSshCertificateDALFactory, "find" | "countSshCertificatesInProject">;
|
||||||
|
sshCertificateTemplateDAL: Pick<TSshCertificateTemplateDALFactory, "find">;
|
||||||
permissionService: TPermissionServiceFactory;
|
permissionService: TPermissionServiceFactory;
|
||||||
orgService: Pick<TOrgServiceFactory, "addGhostUser">;
|
orgService: Pick<TOrgServiceFactory, "addGhostUser">;
|
||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
@@ -133,6 +142,9 @@ export const projectServiceFactory = ({
|
|||||||
certificateTemplateDAL,
|
certificateTemplateDAL,
|
||||||
pkiCollectionDAL,
|
pkiCollectionDAL,
|
||||||
pkiAlertDAL,
|
pkiAlertDAL,
|
||||||
|
sshCertificateAuthorityDAL,
|
||||||
|
sshCertificateDAL,
|
||||||
|
sshCertificateTemplateDAL,
|
||||||
keyStore,
|
keyStore,
|
||||||
kmsService,
|
kmsService,
|
||||||
projectBotDAL,
|
projectBotDAL,
|
||||||
@@ -859,6 +871,115 @@ export const projectServiceFactory = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return list of SSH CAs for project
|
||||||
|
*/
|
||||||
|
const listProjectSshCas = async ({
|
||||||
|
actorId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actor,
|
||||||
|
projectId
|
||||||
|
}: TListProjectSshCasDTO) => {
|
||||||
|
const { permission } = await permissionService.getProjectPermission(
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
projectId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
);
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Read,
|
||||||
|
ProjectPermissionSub.SshCertificateAuthorities
|
||||||
|
);
|
||||||
|
|
||||||
|
const cas = await sshCertificateAuthorityDAL.find(
|
||||||
|
{
|
||||||
|
projectId
|
||||||
|
},
|
||||||
|
{ sort: [["updatedAt", "desc"]] }
|
||||||
|
);
|
||||||
|
|
||||||
|
return cas;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return list of SSH certificates for organization
|
||||||
|
*/
|
||||||
|
const listProjectSshCertificates = async ({
|
||||||
|
limit = 25,
|
||||||
|
offset = 0,
|
||||||
|
actorId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actor,
|
||||||
|
projectId
|
||||||
|
}: TListProjectSshCertificatesDTO) => {
|
||||||
|
const { permission } = await permissionService.getProjectPermission(
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
projectId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
);
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SshCertificates);
|
||||||
|
|
||||||
|
const cas = await sshCertificateAuthorityDAL.find({
|
||||||
|
projectId
|
||||||
|
});
|
||||||
|
|
||||||
|
const certificates = await sshCertificateDAL.find(
|
||||||
|
{
|
||||||
|
$in: {
|
||||||
|
sshCaId: cas.map((ca) => ca.id)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ offset, limit, sort: [["updatedAt", "desc"]] }
|
||||||
|
);
|
||||||
|
|
||||||
|
const count = await sshCertificateDAL.countSshCertificatesInProject(projectId);
|
||||||
|
|
||||||
|
return { certificates, totalCount: count };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return list of SSH certificate templates for organization
|
||||||
|
*/
|
||||||
|
const listProjectSshCertificateTemplates = async ({
|
||||||
|
actorId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actor,
|
||||||
|
projectId
|
||||||
|
}: TListProjectSshCertificateTemplatesDTO) => {
|
||||||
|
const { permission } = await permissionService.getProjectPermission(
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
projectId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
);
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Read,
|
||||||
|
ProjectPermissionSub.SshCertificateTemplates
|
||||||
|
);
|
||||||
|
|
||||||
|
const cas = await sshCertificateAuthorityDAL.find({
|
||||||
|
projectId
|
||||||
|
});
|
||||||
|
|
||||||
|
const certificateTemplates = await sshCertificateTemplateDAL.find({
|
||||||
|
$in: {
|
||||||
|
sshCaId: cas.map((ca) => ca.id)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { certificateTemplates };
|
||||||
|
};
|
||||||
|
|
||||||
const updateProjectKmsKey = async ({
|
const updateProjectKmsKey = async ({
|
||||||
projectId,
|
projectId,
|
||||||
kms,
|
kms,
|
||||||
@@ -1092,6 +1213,9 @@ export const projectServiceFactory = ({
|
|||||||
listProjectAlerts,
|
listProjectAlerts,
|
||||||
listProjectPkiCollections,
|
listProjectPkiCollections,
|
||||||
listProjectCertificateTemplates,
|
listProjectCertificateTemplates,
|
||||||
|
listProjectSshCas,
|
||||||
|
listProjectSshCertificates,
|
||||||
|
listProjectSshCertificateTemplates,
|
||||||
updateVersionLimit,
|
updateVersionLimit,
|
||||||
updateAuditLogsRetention,
|
updateAuditLogsRetention,
|
||||||
updateProjectKmsKey,
|
updateProjectKmsKey,
|
||||||
|
|||||||
@@ -130,6 +130,13 @@ export type TGetProjectKmsKey = TProjectPermission;
|
|||||||
|
|
||||||
export type TListProjectCertificateTemplatesDTO = TProjectPermission;
|
export type TListProjectCertificateTemplatesDTO = TProjectPermission;
|
||||||
|
|
||||||
|
export type TListProjectSshCasDTO = TProjectPermission;
|
||||||
|
export type TListProjectSshCertificateTemplatesDTO = TProjectPermission;
|
||||||
|
export type TListProjectSshCertificatesDTO = {
|
||||||
|
offset: number;
|
||||||
|
limit: number;
|
||||||
|
} & TProjectPermission;
|
||||||
|
|
||||||
export type TGetProjectSlackConfig = TProjectPermission;
|
export type TGetProjectSlackConfig = TProjectPermission;
|
||||||
|
|
||||||
export type TUpdateProjectSlackConfig = {
|
export type TUpdateProjectSlackConfig = {
|
||||||
|
|||||||
@@ -23,10 +23,7 @@ export enum OrgPermissionSubjects {
|
|||||||
Kms = "kms",
|
Kms = "kms",
|
||||||
AdminConsole = "organization-admin-console",
|
AdminConsole = "organization-admin-console",
|
||||||
AuditLogs = "audit-logs",
|
AuditLogs = "audit-logs",
|
||||||
ProjectTemplates = "project-templates",
|
ProjectTemplates = "project-templates"
|
||||||
SshCertificateAuthorities = "ssh-certificate-authorities",
|
|
||||||
SshCertificateTemplates = "ssh-certificate-templates",
|
|
||||||
SshCertificates = "ssh-certificates"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum OrgPermissionAdminConsoleAction {
|
export enum OrgPermissionAdminConsoleAction {
|
||||||
@@ -50,9 +47,6 @@ export type OrgPermissionSet =
|
|||||||
| [OrgPermissionActions, OrgPermissionSubjects.Kms]
|
| [OrgPermissionActions, OrgPermissionSubjects.Kms]
|
||||||
| [OrgPermissionAdminConsoleAction, OrgPermissionSubjects.AdminConsole]
|
| [OrgPermissionAdminConsoleAction, OrgPermissionSubjects.AdminConsole]
|
||||||
| [OrgPermissionActions, OrgPermissionSubjects.AuditLogs]
|
| [OrgPermissionActions, OrgPermissionSubjects.AuditLogs]
|
||||||
| [OrgPermissionActions, OrgPermissionSubjects.ProjectTemplates]
|
| [OrgPermissionActions, OrgPermissionSubjects.ProjectTemplates];
|
||||||
| [OrgPermissionActions, OrgPermissionSubjects.SshCertificateAuthorities]
|
|
||||||
| [OrgPermissionActions, OrgPermissionSubjects.SshCertificates]
|
|
||||||
| [OrgPermissionActions, OrgPermissionSubjects.SshCertificateTemplates];
|
|
||||||
|
|
||||||
export type TOrgPermission = MongoAbility<OrgPermissionSet>;
|
export type TOrgPermission = MongoAbility<OrgPermissionSet>;
|
||||||
|
|||||||
@@ -81,6 +81,9 @@ export enum ProjectPermissionSub {
|
|||||||
CertificateAuthorities = "certificate-authorities",
|
CertificateAuthorities = "certificate-authorities",
|
||||||
Certificates = "certificates",
|
Certificates = "certificates",
|
||||||
CertificateTemplates = "certificate-templates",
|
CertificateTemplates = "certificate-templates",
|
||||||
|
SshCertificateAuthorities = "ssh-certificate-authorities",
|
||||||
|
SshCertificateTemplates = "ssh-certificate-templates",
|
||||||
|
SshCertificates = "ssh-certificates",
|
||||||
PkiAlerts = "pki-alerts",
|
PkiAlerts = "pki-alerts",
|
||||||
PkiCollections = "pki-collections",
|
PkiCollections = "pki-collections",
|
||||||
Kms = "kms",
|
Kms = "kms",
|
||||||
@@ -155,6 +158,9 @@ export type ProjectPermissionSet =
|
|||||||
| [ProjectPermissionActions, ProjectPermissionSub.CertificateAuthorities]
|
| [ProjectPermissionActions, ProjectPermissionSub.CertificateAuthorities]
|
||||||
| [ProjectPermissionActions, ProjectPermissionSub.Certificates]
|
| [ProjectPermissionActions, ProjectPermissionSub.Certificates]
|
||||||
| [ProjectPermissionActions, ProjectPermissionSub.CertificateTemplates]
|
| [ProjectPermissionActions, ProjectPermissionSub.CertificateTemplates]
|
||||||
|
| [ProjectPermissionActions, ProjectPermissionSub.SshCertificateAuthorities]
|
||||||
|
| [ProjectPermissionActions, ProjectPermissionSub.SshCertificateTemplates]
|
||||||
|
| [ProjectPermissionActions, ProjectPermissionSub.SshCertificates]
|
||||||
| [ProjectPermissionActions, ProjectPermissionSub.PkiAlerts]
|
| [ProjectPermissionActions, ProjectPermissionSub.PkiAlerts]
|
||||||
| [ProjectPermissionActions, ProjectPermissionSub.PkiCollections]
|
| [ProjectPermissionActions, ProjectPermissionSub.PkiCollections]
|
||||||
| [ProjectPermissionActions.Delete, ProjectPermissionSub.Project]
|
| [ProjectPermissionActions.Delete, ProjectPermissionSub.Project]
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ export {
|
|||||||
useGetOrgPmtMethods,
|
useGetOrgPmtMethods,
|
||||||
useGetOrgTaxIds,
|
useGetOrgTaxIds,
|
||||||
useGetOrgTrialUrl,
|
useGetOrgTrialUrl,
|
||||||
useListOrgSshCas,
|
|
||||||
useListOrgSshCertificates,
|
|
||||||
useListOrgSshCertificateTemplates,
|
|
||||||
useUpdateOrg,
|
useUpdateOrg,
|
||||||
useUpdateOrgBillingDetails} from "./queries";
|
useUpdateOrgBillingDetails
|
||||||
|
} from "./queries";
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import { apiRequest } from "@app/config/request";
|
|||||||
import { OrderByDirection } from "@app/hooks/api/generic/types";
|
import { OrderByDirection } from "@app/hooks/api/generic/types";
|
||||||
|
|
||||||
import { TGroupOrgMembership } from "../groups/types";
|
import { TGroupOrgMembership } from "../groups/types";
|
||||||
import { TSshCertificate,TSshCertificateAuthority } from "../ssh-ca/types";
|
|
||||||
import { TSshCertificateTemplate } from "../sshCertificateTemplates/types";
|
|
||||||
import { IntegrationAuth } from "../types";
|
import { IntegrationAuth } from "../types";
|
||||||
import {
|
import {
|
||||||
BillingDetails,
|
BillingDetails,
|
||||||
@@ -43,12 +41,7 @@ export const organizationKeys = {
|
|||||||
}: TListOrgIdentitiesDTO) =>
|
}: TListOrgIdentitiesDTO) =>
|
||||||
[...organizationKeys.getOrgIdentityMemberships(orgId), params] as const,
|
[...organizationKeys.getOrgIdentityMemberships(orgId), params] as const,
|
||||||
getOrgGroups: (orgId: string) => [{ orgId }, "organization-groups"] as const,
|
getOrgGroups: (orgId: string) => [{ orgId }, "organization-groups"] as const,
|
||||||
getOrgIntegrationAuths: (orgId: string) => [{ orgId }, "integration-auths"] as const,
|
getOrgIntegrationAuths: (orgId: string) => [{ orgId }, "integration-auths"] as const
|
||||||
getOrgSshCas: ({ orgId }: { orgId: string }) => [{ orgId }, "org-ssh-cas"] as const,
|
|
||||||
allOrgSshCertificates: () => ["org-ssh-certificates"] as const,
|
|
||||||
specificOrgSshCertificates: ({ offset, limit }: { offset: number; limit: number }) =>
|
|
||||||
[...organizationKeys.allOrgSshCertificates(), { offset, limit }] as const,
|
|
||||||
getOrgSshCertificateTemplates: () => ["org-ssh-certificate-templates"] as const
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchOrganizations = async () => {
|
export const fetchOrganizations = async () => {
|
||||||
@@ -502,63 +495,3 @@ export const useGetOrgIntegrationAuths = <TData = IntegrationAuth[],>(
|
|||||||
select
|
select
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useListOrgSshCas = ({ orgId }: { orgId: string }) => {
|
|
||||||
return useQuery({
|
|
||||||
queryKey: organizationKeys.getOrgSshCas({ orgId }),
|
|
||||||
queryFn: async () => {
|
|
||||||
const {
|
|
||||||
data: { cas }
|
|
||||||
} = await apiRequest.get<{ cas: Omit<TSshCertificateAuthority, "publicKey">[] }>(
|
|
||||||
`/api/v1/organization/${orgId}/ssh-cas`
|
|
||||||
);
|
|
||||||
return cas;
|
|
||||||
},
|
|
||||||
enabled: Boolean(orgId)
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useListOrgSshCertificates = ({
|
|
||||||
orgId,
|
|
||||||
offset,
|
|
||||||
limit
|
|
||||||
}: {
|
|
||||||
orgId: string;
|
|
||||||
offset: number;
|
|
||||||
limit: number;
|
|
||||||
}) => {
|
|
||||||
return useQuery({
|
|
||||||
queryKey: organizationKeys.specificOrgSshCertificates({
|
|
||||||
offset,
|
|
||||||
limit
|
|
||||||
}),
|
|
||||||
queryFn: async () => {
|
|
||||||
const params = new URLSearchParams({
|
|
||||||
offset: String(offset),
|
|
||||||
limit: String(limit)
|
|
||||||
});
|
|
||||||
|
|
||||||
const { data } = await apiRequest.get<{
|
|
||||||
certificates: TSshCertificate[];
|
|
||||||
totalCount: number;
|
|
||||||
}>(`/api/v1/organization/${orgId}/ssh-certificates`, {
|
|
||||||
params
|
|
||||||
});
|
|
||||||
return data;
|
|
||||||
},
|
|
||||||
enabled: Boolean(orgId)
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useListOrgSshCertificateTemplates = ({ orgId }: { orgId: string }) => {
|
|
||||||
return useQuery({
|
|
||||||
queryKey: organizationKeys.getOrgSshCertificateTemplates(),
|
|
||||||
queryFn: async () => {
|
|
||||||
const { data } = await apiRequest.get<{ certificateTemplates: TSshCertificateTemplate[] }>(
|
|
||||||
`/api/v1/organization/${orgId}/ssh-certificate-templates`
|
|
||||||
);
|
|
||||||
return data;
|
|
||||||
},
|
|
||||||
enabled: Boolean(orgId)
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|||||||
|
|
||||||
import { apiRequest } from "@app/config/request";
|
import { apiRequest } from "@app/config/request";
|
||||||
|
|
||||||
import { organizationKeys } from "../organization/queries";
|
import { workspaceKeys } from "../workspace/query-keys";
|
||||||
import {
|
import {
|
||||||
TCreateSshCaDTO,
|
TCreateSshCaDTO,
|
||||||
TDeleteSshCaDTO,
|
TDeleteSshCaDTO,
|
||||||
@@ -27,8 +27,8 @@ export const useCreateSshCa = () => {
|
|||||||
} = await apiRequest.post<{ ca: TSshCertificateAuthority }>("/api/v1/ssh/ca/", body);
|
} = await apiRequest.post<{ ca: TSshCertificateAuthority }>("/api/v1/ssh/ca/", body);
|
||||||
return ca;
|
return ca;
|
||||||
},
|
},
|
||||||
onSuccess: ({ orgId }) => {
|
onSuccess: ({ projectId }) => {
|
||||||
queryClient.invalidateQueries(organizationKeys.getOrgSshCas({ orgId }));
|
queryClient.invalidateQueries(workspaceKeys.getWorkspaceSshCas(projectId));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -42,8 +42,8 @@ export const useUpdateSshCa = () => {
|
|||||||
} = await apiRequest.patch<{ ca: TSshCertificateAuthority }>(`/api/v1/ssh/ca/${caId}`, body);
|
} = await apiRequest.patch<{ ca: TSshCertificateAuthority }>(`/api/v1/ssh/ca/${caId}`, body);
|
||||||
return ca;
|
return ca;
|
||||||
},
|
},
|
||||||
onSuccess: ({ orgId }, { caId }) => {
|
onSuccess: ({ projectId }, { caId }) => {
|
||||||
queryClient.invalidateQueries(organizationKeys.getOrgSshCas({ orgId }));
|
queryClient.invalidateQueries(workspaceKeys.getWorkspaceSshCas(projectId));
|
||||||
queryClient.invalidateQueries(sshCaKeys.getSshCaById(caId));
|
queryClient.invalidateQueries(sshCaKeys.getSshCaById(caId));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -58,8 +58,8 @@ export const useDeleteSshCa = () => {
|
|||||||
} = await apiRequest.delete<{ ca: TSshCertificateAuthority }>(`/api/v1/ssh/ca/${caId}`);
|
} = await apiRequest.delete<{ ca: TSshCertificateAuthority }>(`/api/v1/ssh/ca/${caId}`);
|
||||||
return ca;
|
return ca;
|
||||||
},
|
},
|
||||||
onSuccess: ({ orgId }) => {
|
onSuccess: ({ projectId }) => {
|
||||||
queryClient.invalidateQueries(organizationKeys.getOrgSshCas({ orgId }));
|
queryClient.invalidateQueries(workspaceKeys.getWorkspaceSshCas(projectId));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -71,8 +71,8 @@ export const useSignSshKey = () => {
|
|||||||
const { data } = await apiRequest.post<TSignSshKeyResponse>("/api/v1/ssh/sign", body);
|
const { data } = await apiRequest.post<TSignSshKeyResponse>("/api/v1/ssh/sign", body);
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
onSuccess: (_, { projectId }) => {
|
||||||
queryClient.invalidateQueries(organizationKeys.allOrgSshCertificates());
|
queryClient.invalidateQueries(workspaceKeys.allWorkspaceSshCertificates(projectId));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -84,8 +84,8 @@ export const useIssueSshCreds = () => {
|
|||||||
const { data } = await apiRequest.post<TIssueSshCredsResponse>("/api/v1/ssh/issue", body);
|
const { data } = await apiRequest.post<TIssueSshCredsResponse>("/api/v1/ssh/issue", body);
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
onSuccess: (_, { projectId }) => {
|
||||||
queryClient.invalidateQueries(organizationKeys.allOrgSshCertificates());
|
queryClient.invalidateQueries(workspaceKeys.allWorkspaceSshCertificates(projectId));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ export type TSshCertificate = {
|
|||||||
sshCertificateTemplateId: string;
|
sshCertificateTemplateId: string;
|
||||||
serialNumber: string;
|
serialNumber: string;
|
||||||
certType: SshCertType;
|
certType: SshCertType;
|
||||||
publicKey: string;
|
|
||||||
principals: string[];
|
principals: string[];
|
||||||
keyId: string;
|
keyId: string;
|
||||||
notBefore: string;
|
notBefore: string;
|
||||||
@@ -16,7 +15,7 @@ export type TSshCertificate = {
|
|||||||
|
|
||||||
export type TSshCertificateAuthority = {
|
export type TSshCertificateAuthority = {
|
||||||
id: string;
|
id: string;
|
||||||
orgId: string;
|
projectId: string;
|
||||||
status: SshCaStatus;
|
status: SshCaStatus;
|
||||||
friendlyName: string;
|
friendlyName: string;
|
||||||
keyAlgorithm: CertKeyAlgorithm;
|
keyAlgorithm: CertKeyAlgorithm;
|
||||||
@@ -26,6 +25,7 @@ export type TSshCertificateAuthority = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type TCreateSshCaDTO = {
|
export type TCreateSshCaDTO = {
|
||||||
|
projectId: string;
|
||||||
friendlyName?: string;
|
friendlyName?: string;
|
||||||
keyAlgorithm: CertKeyAlgorithm;
|
keyAlgorithm: CertKeyAlgorithm;
|
||||||
};
|
};
|
||||||
@@ -41,6 +41,7 @@ export type TDeleteSshCaDTO = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type TSignSshKeyDTO = {
|
export type TSignSshKeyDTO = {
|
||||||
|
projectId: string;
|
||||||
templateName: string;
|
templateName: string;
|
||||||
publicKey?: string;
|
publicKey?: string;
|
||||||
certType: SshCertType;
|
certType: SshCertType;
|
||||||
@@ -55,6 +56,7 @@ export type TSignSshKeyResponse = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type TIssueSshCredsDTO = {
|
export type TIssueSshCredsDTO = {
|
||||||
|
projectId: string;
|
||||||
templateName: string;
|
templateName: string;
|
||||||
keyAlgorithm: CertKeyAlgorithm;
|
keyAlgorithm: CertKeyAlgorithm;
|
||||||
certType: SshCertType;
|
certType: SshCertType;
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ export {
|
|||||||
useListWorkspaceGroups,
|
useListWorkspaceGroups,
|
||||||
useListWorkspacePkiAlerts,
|
useListWorkspacePkiAlerts,
|
||||||
useListWorkspacePkiCollections,
|
useListWorkspacePkiCollections,
|
||||||
|
useListWorkspaceSshCas,
|
||||||
|
useListWorkspaceSshCertificates,
|
||||||
|
useListWorkspaceSshCertificateTemplates,
|
||||||
useNameWorkspaceSecrets,
|
useNameWorkspaceSecrets,
|
||||||
useToggleAutoCapitalization,
|
useToggleAutoCapitalization,
|
||||||
useUpdateIdentityWorkspaceRole,
|
useUpdateIdentityWorkspaceRole,
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ import { TIntegration } from "../integrations/types";
|
|||||||
import { TPkiAlert } from "../pkiAlerts/types";
|
import { TPkiAlert } from "../pkiAlerts/types";
|
||||||
import { TPkiCollection } from "../pkiCollections/types";
|
import { TPkiCollection } from "../pkiCollections/types";
|
||||||
import { EncryptedSecret } from "../secrets/types";
|
import { EncryptedSecret } from "../secrets/types";
|
||||||
|
import { TSshCertificate, TSshCertificateAuthority } from "../ssh-ca/types";
|
||||||
|
import { TSshCertificateTemplate } from "../sshCertificateTemplates/types";
|
||||||
import { userKeys } from "../users/query-keys";
|
import { userKeys } from "../users/query-keys";
|
||||||
import { TWorkspaceUser } from "../users/types";
|
import { TWorkspaceUser } from "../users/types";
|
||||||
import { ProjectSlackConfig } from "../workflowIntegrations/types";
|
import { ProjectSlackConfig } from "../workflowIntegrations/types";
|
||||||
@@ -713,6 +715,67 @@ export const useListWorkspaceCertificateTemplates = ({ workspaceId }: { workspac
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useListWorkspaceSshCertificates = ({
|
||||||
|
offset,
|
||||||
|
limit,
|
||||||
|
projectId
|
||||||
|
}: {
|
||||||
|
offset: number;
|
||||||
|
limit: number;
|
||||||
|
projectId: string;
|
||||||
|
}) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: workspaceKeys.specificWorkspaceSshCertificates({
|
||||||
|
offset,
|
||||||
|
limit,
|
||||||
|
projectId
|
||||||
|
}),
|
||||||
|
queryFn: async () => {
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
offset: String(offset),
|
||||||
|
limit: String(limit)
|
||||||
|
});
|
||||||
|
|
||||||
|
const { data } = await apiRequest.get<{
|
||||||
|
certificates: TSshCertificate[];
|
||||||
|
totalCount: number;
|
||||||
|
}>(`/api/v2/workspace/${projectId}/ssh-certificates`, {
|
||||||
|
params
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
enabled: Boolean(projectId)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useListWorkspaceSshCas = (projectId: string) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: workspaceKeys.getWorkspaceSshCas(projectId),
|
||||||
|
queryFn: async () => {
|
||||||
|
const {
|
||||||
|
data: { cas }
|
||||||
|
} = await apiRequest.get<{ cas: Omit<TSshCertificateAuthority, "publicKey">[] }>(
|
||||||
|
`/api/v2/workspace/${projectId}/ssh-cas`
|
||||||
|
);
|
||||||
|
return cas;
|
||||||
|
},
|
||||||
|
enabled: Boolean(projectId)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useListWorkspaceSshCertificateTemplates = (projectId: string) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: workspaceKeys.getWorkspaceSshCertificateTemplates(projectId),
|
||||||
|
queryFn: async () => {
|
||||||
|
const { data } = await apiRequest.get<{ certificateTemplates: TSshCertificateTemplate[] }>(
|
||||||
|
`/api/v2/workspace/${projectId}/ssh-certificate-templates`
|
||||||
|
);
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
enabled: Boolean(projectId)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const useGetWorkspaceSlackConfig = ({ workspaceId }: { workspaceId: string }) => {
|
export const useGetWorkspaceSlackConfig = ({ workspaceId }: { workspaceId: string }) => {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: workspaceKeys.getWorkspaceSlackConfig(workspaceId),
|
queryKey: workspaceKeys.getWorkspaceSlackConfig(workspaceId),
|
||||||
|
|||||||
@@ -52,5 +52,19 @@ export const workspaceKeys = {
|
|||||||
getWorkspaceCertificateTemplates: (workspaceId: string) =>
|
getWorkspaceCertificateTemplates: (workspaceId: string) =>
|
||||||
[{ workspaceId }, "workspace-certificate-templates"] as const,
|
[{ workspaceId }, "workspace-certificate-templates"] as const,
|
||||||
getWorkspaceSlackConfig: (workspaceId: string) =>
|
getWorkspaceSlackConfig: (workspaceId: string) =>
|
||||||
[{ workspaceId }, "workspace-slack-config"] as const
|
[{ workspaceId }, "workspace-slack-config"] as const,
|
||||||
|
getWorkspaceSshCas: (projectId: string) => [{ projectId }, "workspace-ssh-cas"] as const,
|
||||||
|
allWorkspaceSshCertificates: (projectId: string) =>
|
||||||
|
[{ projectId }, "workspace-ssh-certificates"] as const,
|
||||||
|
specificWorkspaceSshCertificates: ({
|
||||||
|
offset,
|
||||||
|
limit,
|
||||||
|
projectId
|
||||||
|
}: {
|
||||||
|
offset: number;
|
||||||
|
limit: number;
|
||||||
|
projectId: string;
|
||||||
|
}) => [...workspaceKeys.allWorkspaceSshCertificates(projectId), { offset, limit }] as const,
|
||||||
|
getWorkspaceSshCertificateTemplates: (projectId: string) =>
|
||||||
|
[{ projectId }, "workspace-ssh-certificate-templates"] as const
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -424,6 +424,16 @@ export const AppLayout = ({ children }: LayoutProps) => {
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
|
<Link href={`/project/${currentWorkspace?.id}/ssh`} passHref>
|
||||||
|
<a>
|
||||||
|
<MenuItem
|
||||||
|
isSelected={router.asPath === `/project/${currentWorkspace?.id}/ssh`}
|
||||||
|
icon="system-outline-90-lock-closed"
|
||||||
|
>
|
||||||
|
SSH
|
||||||
|
</MenuItem>
|
||||||
|
</a>
|
||||||
|
</Link>
|
||||||
<Link href={`/project/${currentWorkspace?.id}/members`} passHref>
|
<Link href={`/project/${currentWorkspace?.id}/members`} passHref>
|
||||||
<a>
|
<a>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
@@ -513,16 +523,6 @@ export const AppLayout = ({ children }: LayoutProps) => {
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
<Link href={`/org/${currentOrg?.id}/ssh`} passHref>
|
|
||||||
<a>
|
|
||||||
<MenuItem
|
|
||||||
isSelected={router.asPath === `/org/${currentOrg?.id}/ssh`}
|
|
||||||
icon="system-outline-90-lock-closed"
|
|
||||||
>
|
|
||||||
SSH
|
|
||||||
</MenuItem>
|
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
<Link href={`/org/${currentOrg?.id}/secret-scanning`} passHref>
|
<Link href={`/org/${currentOrg?.id}/secret-scanning`} passHref>
|
||||||
<a>
|
<a>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import Head from "next/head";
|
|
||||||
|
|
||||||
import { SshPage } from "@app/views/Org/SshPage";
|
|
||||||
|
|
||||||
const Ssh = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Head>
|
|
||||||
<title>{t("common.head-title", { title: t("approval.title") })}</title>
|
|
||||||
<link rel="icon" href="/infisical.ico" />
|
|
||||||
<meta property="og:image" content="/images/message.png" />
|
|
||||||
<meta property="og:title" content={String(t("approval.og-title"))} />
|
|
||||||
<meta name="og:description" content={String(t("approval.og-description"))} />
|
|
||||||
</Head>
|
|
||||||
<div className="h-full">
|
|
||||||
<SshPage />
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Ssh;
|
|
||||||
|
|
||||||
Ssh.requireAuth = true;
|
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
|
|
||||||
import { SshCaPage } from "@app/views/Org/SshCaPage";
|
import { SshCaPage } from "@app/views/Project/SshCaPage";
|
||||||
|
|
||||||
export default function SshCa() {
|
export default function SshCa() {
|
||||||
return (
|
return (
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import Head from "next/head";
|
||||||
|
|
||||||
|
import { SshPage } from "@app/views/Project/SshPage";
|
||||||
|
|
||||||
|
const Ssh = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="h-full bg-bunker-800">
|
||||||
|
<Head>
|
||||||
|
<title>{t("common.head-title", { title: "Certificates" })}</title>
|
||||||
|
<link rel="icon" href="/infisical.ico" />
|
||||||
|
<meta property="og:image" content="/images/message.png" />
|
||||||
|
</Head>
|
||||||
|
<SshPage />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Ssh;
|
||||||
|
|
||||||
|
Ssh.requireAuth = true;
|
||||||
@@ -49,10 +49,7 @@ export const formSchema = z.object({
|
|||||||
identity: generalPermissionSchema,
|
identity: generalPermissionSchema,
|
||||||
"organization-admin-console": adminConsolePermissionSchmea,
|
"organization-admin-console": adminConsolePermissionSchmea,
|
||||||
[OrgPermissionSubjects.Kms]: generalPermissionSchema,
|
[OrgPermissionSubjects.Kms]: generalPermissionSchema,
|
||||||
[OrgPermissionSubjects.ProjectTemplates]: generalPermissionSchema,
|
[OrgPermissionSubjects.ProjectTemplates]: generalPermissionSchema
|
||||||
[OrgPermissionSubjects.SshCertificateAuthorities]: generalPermissionSchema,
|
|
||||||
[OrgPermissionSubjects.SshCertificates]: generalPermissionSchema,
|
|
||||||
[OrgPermissionSubjects.SshCertificateTemplates]: generalPermissionSchema
|
|
||||||
})
|
})
|
||||||
.optional()
|
.optional()
|
||||||
});
|
});
|
||||||
|
|||||||
+1
-13
@@ -69,19 +69,7 @@ const SIMPLE_PERMISSION_OPTIONS = [
|
|||||||
title: "External KMS",
|
title: "External KMS",
|
||||||
formName: OrgPermissionSubjects.Kms
|
formName: OrgPermissionSubjects.Kms
|
||||||
},
|
},
|
||||||
{ title: "Project Templates", formName: OrgPermissionSubjects.ProjectTemplates },
|
{ title: "Project Templates", formName: OrgPermissionSubjects.ProjectTemplates }
|
||||||
{
|
|
||||||
title: "SSH Certificate Authorities",
|
|
||||||
formName: OrgPermissionSubjects.SshCertificateAuthorities
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "SSH Certificates",
|
|
||||||
formName: OrgPermissionSubjects.SshCertificates
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "SSH Certificate Templates",
|
|
||||||
formName: OrgPermissionSubjects.SshCertificateTemplates
|
|
||||||
}
|
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|||||||
+35
@@ -121,6 +121,11 @@ export const projectRoleFormSchema = z.object({
|
|||||||
[ProjectPermissionSub.PkiAlerts]: GeneralPolicyActionSchema.array().default([]),
|
[ProjectPermissionSub.PkiAlerts]: GeneralPolicyActionSchema.array().default([]),
|
||||||
[ProjectPermissionSub.PkiCollections]: GeneralPolicyActionSchema.array().default([]),
|
[ProjectPermissionSub.PkiCollections]: GeneralPolicyActionSchema.array().default([]),
|
||||||
[ProjectPermissionSub.CertificateTemplates]: GeneralPolicyActionSchema.array().default([]),
|
[ProjectPermissionSub.CertificateTemplates]: GeneralPolicyActionSchema.array().default([]),
|
||||||
|
[ProjectPermissionSub.SshCertificateAuthorities]: GeneralPolicyActionSchema.array().default(
|
||||||
|
[]
|
||||||
|
),
|
||||||
|
[ProjectPermissionSub.SshCertificates]: GeneralPolicyActionSchema.array().default([]),
|
||||||
|
[ProjectPermissionSub.SshCertificateTemplates]: GeneralPolicyActionSchema.array().default([]),
|
||||||
[ProjectPermissionSub.SecretApproval]: GeneralPolicyActionSchema.array().default([]),
|
[ProjectPermissionSub.SecretApproval]: GeneralPolicyActionSchema.array().default([]),
|
||||||
[ProjectPermissionSub.SecretRollback]: SecretRollbackPolicyActionSchema.array().default([]),
|
[ProjectPermissionSub.SecretRollback]: SecretRollbackPolicyActionSchema.array().default([]),
|
||||||
[ProjectPermissionSub.Project]: WorkspacePolicyActionSchema.array().default([]),
|
[ProjectPermissionSub.Project]: WorkspacePolicyActionSchema.array().default([]),
|
||||||
@@ -203,6 +208,9 @@ export const rolePermission2Form = (permissions: TProjectPermission[] = []) => {
|
|||||||
ProjectPermissionSub.PkiAlerts,
|
ProjectPermissionSub.PkiAlerts,
|
||||||
ProjectPermissionSub.PkiCollections,
|
ProjectPermissionSub.PkiCollections,
|
||||||
ProjectPermissionSub.CertificateTemplates,
|
ProjectPermissionSub.CertificateTemplates,
|
||||||
|
ProjectPermissionSub.SshCertificateAuthorities,
|
||||||
|
ProjectPermissionSub.SshCertificates,
|
||||||
|
ProjectPermissionSub.SshCertificateTemplates,
|
||||||
ProjectPermissionSub.SecretApproval,
|
ProjectPermissionSub.SecretApproval,
|
||||||
ProjectPermissionSub.Tags,
|
ProjectPermissionSub.Tags,
|
||||||
ProjectPermissionSub.SecretRotation,
|
ProjectPermissionSub.SecretRotation,
|
||||||
@@ -589,6 +597,33 @@ export const PROJECT_PERMISSION_OBJECT: TProjectPermissionObject = {
|
|||||||
{ label: "Remove", value: "delete" }
|
{ label: "Remove", value: "delete" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
[ProjectPermissionSub.SshCertificateAuthorities]: {
|
||||||
|
title: "SSH Certificate Authorities",
|
||||||
|
actions: [
|
||||||
|
{ label: "Read", value: "read" },
|
||||||
|
{ label: "Create", value: "create" },
|
||||||
|
{ label: "Modify", value: "edit" },
|
||||||
|
{ label: "Remove", value: "delete" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
[ProjectPermissionSub.SshCertificates]: {
|
||||||
|
title: "SSH Certificates",
|
||||||
|
actions: [
|
||||||
|
{ label: "Read", value: "read" },
|
||||||
|
{ label: "Create", value: "create" },
|
||||||
|
{ label: "Modify", value: "edit" },
|
||||||
|
{ label: "Remove", value: "delete" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
[ProjectPermissionSub.SshCertificateTemplates]: {
|
||||||
|
title: "SSH Certificate Templates",
|
||||||
|
actions: [
|
||||||
|
{ label: "Read", value: "read" },
|
||||||
|
{ label: "Create", value: "create" },
|
||||||
|
{ label: "Modify", value: "edit" },
|
||||||
|
{ label: "Remove", value: "delete" }
|
||||||
|
]
|
||||||
|
},
|
||||||
[ProjectPermissionSub.PkiCollections]: {
|
[ProjectPermissionSub.PkiCollections]: {
|
||||||
title: "PKI Collections",
|
title: "PKI Collections",
|
||||||
actions: [
|
actions: [
|
||||||
|
|||||||
+14
-13
@@ -5,7 +5,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|||||||
import { twMerge } from "tailwind-merge";
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
import { createNotification } from "@app/components/notifications";
|
import { createNotification } from "@app/components/notifications";
|
||||||
import { OrgPermissionCan } from "@app/components/permissions";
|
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
DeleteActionModal,
|
DeleteActionModal,
|
||||||
@@ -15,17 +15,18 @@ import {
|
|||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
Tooltip
|
Tooltip
|
||||||
} from "@app/components/v2";
|
} from "@app/components/v2";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects, useOrganization } from "@app/context";
|
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
|
||||||
import { withPermission } from "@app/hoc";
|
import { withProjectPermission } from "@app/hoc";
|
||||||
import { useDeleteSshCa, useGetSshCaById } from "@app/hooks/api";
|
import { useDeleteSshCa, useGetSshCaById } from "@app/hooks/api";
|
||||||
import { usePopUp } from "@app/hooks/usePopUp";
|
import { usePopUp } from "@app/hooks/usePopUp";
|
||||||
|
|
||||||
import { SshCaModal } from "../SshPage/components/SshCaModal";
|
import { SshCaModal } from "../SshPage/components/SshCaModal";
|
||||||
import { SshCaDetailsSection, SshCertificateTemplatesSection } from "./components";
|
import { SshCaDetailsSection, SshCertificateTemplatesSection } from "./components";
|
||||||
|
|
||||||
export const SshCaPage = withPermission(
|
export const SshCaPage = withProjectPermission(
|
||||||
() => {
|
() => {
|
||||||
const { currentOrg } = useOrganization();
|
const { currentWorkspace } = useWorkspace();
|
||||||
|
const projectId = currentWorkspace?.id || "";
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const caId = router.query.caId as string;
|
const caId = router.query.caId as string;
|
||||||
const { data } = useGetSshCaById(caId);
|
const { data } = useGetSshCaById(caId);
|
||||||
@@ -39,7 +40,7 @@ export const SshCaPage = withPermission(
|
|||||||
|
|
||||||
const onRemoveCaSubmit = async (caIdToDelete: string) => {
|
const onRemoveCaSubmit = async (caIdToDelete: string) => {
|
||||||
try {
|
try {
|
||||||
if (!currentOrg?.id) return;
|
if (!projectId) return;
|
||||||
|
|
||||||
await deleteSshCa({ caId: caIdToDelete });
|
await deleteSshCa({ caId: caIdToDelete });
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@ export const SshCaPage = withPermission(
|
|||||||
});
|
});
|
||||||
|
|
||||||
handlePopUpClose("deleteSshCa");
|
handlePopUpClose("deleteSshCa");
|
||||||
router.push(`/org/${currentOrg.id}/ssh`);
|
router.push(`/project/${projectId}/ssh`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
createNotification({
|
createNotification({
|
||||||
@@ -67,7 +68,7 @@ export const SshCaPage = withPermission(
|
|||||||
variant="link"
|
variant="link"
|
||||||
type="submit"
|
type="submit"
|
||||||
leftIcon={<FontAwesomeIcon icon={faChevronLeft} />}
|
leftIcon={<FontAwesomeIcon icon={faChevronLeft} />}
|
||||||
onClick={() => router.push(`/org/${currentOrg?.id}/ssh`)}
|
onClick={() => router.push(`/project/${projectId}/ssh`)}
|
||||||
className="mb-4"
|
className="mb-4"
|
||||||
>
|
>
|
||||||
SSH Certificate Authorities
|
SSH Certificate Authorities
|
||||||
@@ -83,9 +84,9 @@ export const SshCaPage = withPermission(
|
|||||||
</div>
|
</div>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent align="start" className="p-1">
|
<DropdownMenuContent align="start" className="p-1">
|
||||||
<OrgPermissionCan
|
<ProjectPermissionCan
|
||||||
I={OrgPermissionActions.Delete}
|
I={ProjectPermissionActions.Delete}
|
||||||
a={OrgPermissionSubjects.SshCertificateAuthorities}
|
a={ProjectPermissionSub.SshCertificateAuthorities}
|
||||||
>
|
>
|
||||||
{(isAllowed) => (
|
{(isAllowed) => (
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
@@ -104,7 +105,7 @@ export const SshCaPage = withPermission(
|
|||||||
Delete SSH CA
|
Delete SSH CA
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
)}
|
)}
|
||||||
</OrgPermissionCan>
|
</ProjectPermissionCan>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</div>
|
</div>
|
||||||
@@ -131,5 +132,5 @@ export const SshCaPage = withPermission(
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
{ action: OrgPermissionActions.Read, subject: OrgPermissionSubjects.SshCertificateAuthorities }
|
{ action: ProjectPermissionActions.Read, subject: ProjectPermissionSub.SshCertificateAuthorities }
|
||||||
);
|
);
|
||||||
+7
-7
@@ -1,10 +1,10 @@
|
|||||||
import { faCheck, faCopy, faDownload,faPencil } from "@fortawesome/free-solid-svg-icons";
|
import { faCheck, faCopy, faDownload, faPencil } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import FileSaver from "file-saver";
|
import FileSaver from "file-saver";
|
||||||
|
|
||||||
import { OrgPermissionCan } from "@app/components/permissions";
|
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||||
import { IconButton, Tooltip } from "@app/components/v2";
|
import { IconButton, Tooltip } from "@app/components/v2";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context";
|
||||||
import { useTimedReset } from "@app/hooks";
|
import { useTimedReset } from "@app/hooks";
|
||||||
import { useGetSshCaById } from "@app/hooks/api";
|
import { useGetSshCaById } from "@app/hooks/api";
|
||||||
import { caStatusToNameMap } from "@app/hooks/api/ca/constants";
|
import { caStatusToNameMap } from "@app/hooks/api/ca/constants";
|
||||||
@@ -35,9 +35,9 @@ export const SshCaDetailsSection = ({ caId, handlePopUpOpen }: Props) => {
|
|||||||
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||||
<div className="flex items-center justify-between border-b border-mineshaft-400 pb-4">
|
<div className="flex items-center justify-between border-b border-mineshaft-400 pb-4">
|
||||||
<h3 className="text-lg font-semibold text-mineshaft-100">SSH CA Details</h3>
|
<h3 className="text-lg font-semibold text-mineshaft-100">SSH CA Details</h3>
|
||||||
<OrgPermissionCan
|
<ProjectPermissionCan
|
||||||
I={OrgPermissionActions.Edit}
|
I={ProjectPermissionActions.Edit}
|
||||||
a={OrgPermissionSubjects.SshCertificateAuthorities}
|
a={ProjectPermissionSub.SshCertificateAuthorities}
|
||||||
>
|
>
|
||||||
{(isAllowed) => {
|
{(isAllowed) => {
|
||||||
return (
|
return (
|
||||||
@@ -59,7 +59,7 @@ export const SshCaDetailsSection = ({ caId, handlePopUpOpen }: Props) => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</OrgPermissionCan>
|
</ProjectPermissionCan>
|
||||||
</div>
|
</div>
|
||||||
<div className="pt-4">
|
<div className="pt-4">
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
+10
-7
@@ -13,13 +13,14 @@ import {
|
|||||||
Select,
|
Select,
|
||||||
SelectItem
|
SelectItem
|
||||||
} from "@app/components/v2";
|
} from "@app/components/v2";
|
||||||
import { useOrganization } from "@app/context";
|
import { useWorkspace } from "@app/context";
|
||||||
import {
|
import {
|
||||||
SshCertTemplateStatus,
|
SshCertTemplateStatus,
|
||||||
useGetSshCertTemplate,
|
useGetSshCertTemplate,
|
||||||
useIssueSshCreds,
|
useIssueSshCreds,
|
||||||
useListOrgSshCertificateTemplates,
|
useListWorkspaceSshCertificateTemplates,
|
||||||
useSignSshKey} from "@app/hooks/api";
|
useSignSshKey
|
||||||
|
} from "@app/hooks/api";
|
||||||
import { certKeyAlgorithms } from "@app/hooks/api/certificates/constants";
|
import { certKeyAlgorithms } from "@app/hooks/api/certificates/constants";
|
||||||
import { CertKeyAlgorithm } from "@app/hooks/api/certificates/enums";
|
import { CertKeyAlgorithm } from "@app/hooks/api/certificates/enums";
|
||||||
import { SshCertType } from "@app/hooks/api/ssh-ca/constants";
|
import { SshCertType } from "@app/hooks/api/ssh-ca/constants";
|
||||||
@@ -62,7 +63,8 @@ enum SshCertificateOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const SshCertificateModal = ({ popUp, handlePopUpToggle }: Props) => {
|
export const SshCertificateModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||||
const { currentOrg } = useOrganization();
|
const { currentWorkspace } = useWorkspace();
|
||||||
|
const projectId = currentWorkspace?.id || "";
|
||||||
const [operation, setOperation] = useState<SshCertificateOperation>(
|
const [operation, setOperation] = useState<SshCertificateOperation>(
|
||||||
SshCertificateOperation.SIGN_SSH_KEY
|
SshCertificateOperation.SIGN_SSH_KEY
|
||||||
);
|
);
|
||||||
@@ -77,9 +79,7 @@ export const SshCertificateModal = ({ popUp, handlePopUpToggle }: Props) => {
|
|||||||
templateId: string;
|
templateId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const { data: templatesData } = useListOrgSshCertificateTemplates({
|
const { data: templatesData } = useListWorkspaceSshCertificateTemplates(projectId);
|
||||||
orgId: currentOrg?.id || ""
|
|
||||||
});
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
@@ -117,10 +117,12 @@ export const SshCertificateModal = ({ popUp, handlePopUpToggle }: Props) => {
|
|||||||
}: FormData) => {
|
}: FormData) => {
|
||||||
try {
|
try {
|
||||||
if (!templateData) return;
|
if (!templateData) return;
|
||||||
|
if (!projectId) return;
|
||||||
|
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case SshCertificateOperation.SIGN_SSH_KEY: {
|
case SshCertificateOperation.SIGN_SSH_KEY: {
|
||||||
const { serialNumber, signedKey } = await signSshKey({
|
const { serialNumber, signedKey } = await signSshKey({
|
||||||
|
projectId: currentWorkspace?.id || "",
|
||||||
templateName: templateData.name,
|
templateName: templateData.name,
|
||||||
publicKey: existingPublicKey,
|
publicKey: existingPublicKey,
|
||||||
certType,
|
certType,
|
||||||
@@ -137,6 +139,7 @@ export const SshCertificateModal = ({ popUp, handlePopUpToggle }: Props) => {
|
|||||||
}
|
}
|
||||||
case SshCertificateOperation.ISSUE_SSH_CREDS: {
|
case SshCertificateOperation.ISSUE_SSH_CREDS: {
|
||||||
const { serialNumber, publicKey, privateKey, signedKey } = await issueSshCreds({
|
const { serialNumber, publicKey, privateKey, signedKey } = await issueSshCreds({
|
||||||
|
projectId,
|
||||||
templateName: templateData.name,
|
templateName: templateData.name,
|
||||||
keyAlgorithm,
|
keyAlgorithm,
|
||||||
certType,
|
certType,
|
||||||
+4
-6
@@ -14,12 +14,12 @@ import {
|
|||||||
SelectItem,
|
SelectItem,
|
||||||
Switch
|
Switch
|
||||||
} from "@app/components/v2";
|
} from "@app/components/v2";
|
||||||
import { useOrganization } from "@app/context";
|
import { useWorkspace } from "@app/context";
|
||||||
import {
|
import {
|
||||||
useCreateSshCertTemplate,
|
useCreateSshCertTemplate,
|
||||||
useGetSshCaById,
|
useGetSshCaById,
|
||||||
useGetSshCertTemplate,
|
useGetSshCertTemplate,
|
||||||
useListOrgSshCas,
|
useListWorkspaceSshCas,
|
||||||
useUpdateSshCertTemplate
|
useUpdateSshCertTemplate
|
||||||
} from "@app/hooks/api";
|
} from "@app/hooks/api";
|
||||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||||
@@ -48,7 +48,7 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const SshCertificateTemplateModal = ({ popUp, handlePopUpToggle, sshCaId }: Props) => {
|
export const SshCertificateTemplateModal = ({ popUp, handlePopUpToggle, sshCaId }: Props) => {
|
||||||
const { currentOrg } = useOrganization();
|
const { currentWorkspace } = useWorkspace();
|
||||||
|
|
||||||
const { data: ca } = useGetSshCaById(sshCaId);
|
const { data: ca } = useGetSshCaById(sshCaId);
|
||||||
|
|
||||||
@@ -56,9 +56,7 @@ export const SshCertificateTemplateModal = ({ popUp, handlePopUpToggle, sshCaId
|
|||||||
(popUp?.sshCertificateTemplate?.data as { id: string })?.id || ""
|
(popUp?.sshCertificateTemplate?.data as { id: string })?.id || ""
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data: cas } = useListOrgSshCas({
|
const { data: cas } = useListWorkspaceSshCas(currentWorkspace?.id || "");
|
||||||
orgId: currentOrg?.id ?? ""
|
|
||||||
});
|
|
||||||
|
|
||||||
const { mutateAsync: createSshCertTemplate } = useCreateSshCertTemplate();
|
const { mutateAsync: createSshCertTemplate } = useCreateSshCertTemplate();
|
||||||
const { mutateAsync: updateSshCertTemplate } = useUpdateSshCertTemplate();
|
const { mutateAsync: updateSshCertTemplate } = useUpdateSshCertTemplate();
|
||||||
+8
-7
@@ -2,14 +2,15 @@ import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
|||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
|
||||||
import { createNotification } from "@app/components/notifications";
|
import { createNotification } from "@app/components/notifications";
|
||||||
import { OrgPermissionCan } from "@app/components/permissions";
|
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||||
import { DeleteActionModal, IconButton } from "@app/components/v2";
|
import { DeleteActionModal, IconButton } from "@app/components/v2";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context";
|
||||||
import { usePopUp } from "@app/hooks";
|
import { usePopUp } from "@app/hooks";
|
||||||
import {
|
import {
|
||||||
SshCertTemplateStatus,
|
SshCertTemplateStatus,
|
||||||
useDeleteSshCertTemplate,
|
useDeleteSshCertTemplate,
|
||||||
useUpdateSshCertTemplate} from "@app/hooks/api";
|
useUpdateSshCertTemplate
|
||||||
|
} from "@app/hooks/api";
|
||||||
|
|
||||||
import { SshCertificateModal } from "./SshCertificateModal";
|
import { SshCertificateModal } from "./SshCertificateModal";
|
||||||
import { SshCertificateTemplateModal } from "./SshCertificateTemplateModal";
|
import { SshCertificateTemplateModal } from "./SshCertificateTemplateModal";
|
||||||
@@ -85,9 +86,9 @@ export const SshCertificateTemplatesSection = ({ caId }: Props) => {
|
|||||||
<div className="h-full rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
<div className="h-full rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||||
<div className="flex items-center justify-between border-b border-mineshaft-400 pb-4">
|
<div className="flex items-center justify-between border-b border-mineshaft-400 pb-4">
|
||||||
<h3 className="text-lg font-semibold text-mineshaft-100">Certificate Templates</h3>
|
<h3 className="text-lg font-semibold text-mineshaft-100">Certificate Templates</h3>
|
||||||
<OrgPermissionCan
|
<ProjectPermissionCan
|
||||||
I={OrgPermissionActions.Create}
|
I={ProjectPermissionActions.Create}
|
||||||
a={OrgPermissionSubjects.SshCertificateTemplates}
|
a={ProjectPermissionSub.SshCertificateTemplates}
|
||||||
>
|
>
|
||||||
{(isAllowed) => (
|
{(isAllowed) => (
|
||||||
<IconButton
|
<IconButton
|
||||||
@@ -100,7 +101,7 @@ export const SshCertificateTemplatesSection = ({ caId }: Props) => {
|
|||||||
<FontAwesomeIcon icon={faPlus} />
|
<FontAwesomeIcon icon={faPlus} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
)}
|
)}
|
||||||
</OrgPermissionCan>
|
</ProjectPermissionCan>
|
||||||
</div>
|
</div>
|
||||||
<div className="py-4">
|
<div className="py-4">
|
||||||
<SshCertificateTemplatesTable handlePopUpOpen={handlePopUpOpen} sshCaId={caId} />
|
<SshCertificateTemplatesTable handlePopUpOpen={handlePopUpOpen} sshCaId={caId} />
|
||||||
+19
-19
@@ -8,7 +8,7 @@ import {
|
|||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { twMerge } from "tailwind-merge";
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
import { OrgPermissionCan } from "@app/components/permissions";
|
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||||
import {
|
import {
|
||||||
Badge,
|
Badge,
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
@@ -26,8 +26,8 @@ import {
|
|||||||
Tooltip,
|
Tooltip,
|
||||||
Tr
|
Tr
|
||||||
} from "@app/components/v2";
|
} from "@app/components/v2";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context";
|
||||||
import { SshCertTemplateStatus,useGetSshCaCertTemplates } from "@app/hooks/api";
|
import { SshCertTemplateStatus, useGetSshCaCertTemplates } from "@app/hooks/api";
|
||||||
import { caStatusToNameMap, getCaStatusBadgeVariant } from "@app/hooks/api/ca/constants";
|
import { caStatusToNameMap, getCaStatusBadgeVariant } from "@app/hooks/api/ca/constants";
|
||||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||||
|
|
||||||
@@ -89,9 +89,9 @@ export const SshCertificateTemplatesTable = ({ handlePopUpOpen, sshCaId }: Props
|
|||||||
</div>
|
</div>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent align="start" className="p-1">
|
<DropdownMenuContent align="start" className="p-1">
|
||||||
<OrgPermissionCan
|
<ProjectPermissionCan
|
||||||
I={OrgPermissionActions.Edit}
|
I={ProjectPermissionActions.Edit}
|
||||||
a={OrgPermissionSubjects.SshCertificateTemplates}
|
a={ProjectPermissionSub.SshCertificateTemplates}
|
||||||
>
|
>
|
||||||
{(isAllowed) => (
|
{(isAllowed) => (
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
@@ -118,10 +118,10 @@ export const SshCertificateTemplatesTable = ({ handlePopUpOpen, sshCaId }: Props
|
|||||||
} Template`}
|
} Template`}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
)}
|
)}
|
||||||
</OrgPermissionCan>
|
</ProjectPermissionCan>
|
||||||
<OrgPermissionCan
|
<ProjectPermissionCan
|
||||||
I={OrgPermissionActions.Edit}
|
I={ProjectPermissionActions.Edit}
|
||||||
a={OrgPermissionSubjects.SshCertificateTemplates}
|
a={ProjectPermissionSub.SshCertificateTemplates}
|
||||||
>
|
>
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -136,10 +136,10 @@ export const SshCertificateTemplatesTable = ({ handlePopUpOpen, sshCaId }: Props
|
|||||||
>
|
>
|
||||||
Issue Certificate
|
Issue Certificate
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</OrgPermissionCan>
|
</ProjectPermissionCan>
|
||||||
<OrgPermissionCan
|
<ProjectPermissionCan
|
||||||
I={OrgPermissionActions.Edit}
|
I={ProjectPermissionActions.Edit}
|
||||||
a={OrgPermissionSubjects.SshCertificateTemplates}
|
a={ProjectPermissionSub.SshCertificateTemplates}
|
||||||
>
|
>
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
@@ -151,10 +151,10 @@ export const SshCertificateTemplatesTable = ({ handlePopUpOpen, sshCaId }: Props
|
|||||||
>
|
>
|
||||||
Edit Template
|
Edit Template
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</OrgPermissionCan>
|
</ProjectPermissionCan>
|
||||||
<OrgPermissionCan
|
<ProjectPermissionCan
|
||||||
I={OrgPermissionActions.Delete}
|
I={ProjectPermissionActions.Delete}
|
||||||
a={OrgPermissionSubjects.SshCertificateTemplates}
|
a={ProjectPermissionSub.SshCertificateTemplates}
|
||||||
>
|
>
|
||||||
{(isAllowed) => (
|
{(isAllowed) => (
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
@@ -173,7 +173,7 @@ export const SshCertificateTemplatesTable = ({ handlePopUpOpen, sshCaId }: Props
|
|||||||
Delete Template
|
Delete Template
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
)}
|
)}
|
||||||
</OrgPermissionCan>
|
</ProjectPermissionCan>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</Td>
|
</Td>
|
||||||
+4
-4
@@ -1,8 +1,8 @@
|
|||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
|
|
||||||
import { Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
|
import { Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context";
|
||||||
import { withPermission } from "@app/hoc";
|
import { withProjectPermission } from "@app/hoc";
|
||||||
|
|
||||||
import { SshCaSection, SshCertificatesSection } from "./components";
|
import { SshCaSection, SshCertificatesSection } from "./components";
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ enum TabSections {
|
|||||||
SshCertificates = "ssh-certificates"
|
SshCertificates = "ssh-certificates"
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SshPage = withPermission(
|
export const SshPage = withProjectPermission(
|
||||||
() => {
|
() => {
|
||||||
return (
|
return (
|
||||||
<div className="container mx-auto flex flex-col justify-between bg-bunker-800 text-white">
|
<div className="container mx-auto flex flex-col justify-between bg-bunker-800 text-white">
|
||||||
@@ -49,5 +49,5 @@ export const SshPage = withPermission(
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
{ action: OrgPermissionActions.Read, subject: OrgPermissionSubjects.SshCertificateAuthorities }
|
{ action: ProjectPermissionActions.Read, subject: ProjectPermissionSub.SshCertificateAuthorities }
|
||||||
);
|
);
|
||||||
+6
@@ -13,6 +13,7 @@ import {
|
|||||||
Select,
|
Select,
|
||||||
SelectItem
|
SelectItem
|
||||||
} from "@app/components/v2";
|
} from "@app/components/v2";
|
||||||
|
import { useWorkspace } from "@app/context";
|
||||||
import { useCreateSshCa, useGetSshCaById, useUpdateSshCa } from "@app/hooks/api";
|
import { useCreateSshCa, useGetSshCaById, useUpdateSshCa } from "@app/hooks/api";
|
||||||
import { certKeyAlgorithms } from "@app/hooks/api/certificates/constants";
|
import { certKeyAlgorithms } from "@app/hooks/api/certificates/constants";
|
||||||
import { CertKeyAlgorithm } from "@app/hooks/api/certificates/enums";
|
import { CertKeyAlgorithm } from "@app/hooks/api/certificates/enums";
|
||||||
@@ -38,6 +39,8 @@ const schema = z
|
|||||||
export type FormData = z.infer<typeof schema>;
|
export type FormData = z.infer<typeof schema>;
|
||||||
|
|
||||||
export const SshCaModal = ({ popUp, handlePopUpToggle }: Props) => {
|
export const SshCaModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||||
|
const { currentWorkspace } = useWorkspace();
|
||||||
|
const projectId = currentWorkspace?.id || "";
|
||||||
const { data: ca } = useGetSshCaById((popUp?.sshCa?.data as { caId: string })?.caId || "");
|
const { data: ca } = useGetSshCaById((popUp?.sshCa?.data as { caId: string })?.caId || "");
|
||||||
|
|
||||||
const { mutateAsync: createMutateAsync } = useCreateSshCa();
|
const { mutateAsync: createMutateAsync } = useCreateSshCa();
|
||||||
@@ -72,6 +75,8 @@ export const SshCaModal = ({ popUp, handlePopUpToggle }: Props) => {
|
|||||||
|
|
||||||
const onFormSubmit = async ({ friendlyName, keyAlgorithm }: FormData) => {
|
const onFormSubmit = async ({ friendlyName, keyAlgorithm }: FormData) => {
|
||||||
try {
|
try {
|
||||||
|
if (!projectId) return;
|
||||||
|
|
||||||
if (ca) {
|
if (ca) {
|
||||||
await updateMutateAsync({
|
await updateMutateAsync({
|
||||||
caId: ca.id,
|
caId: ca.id,
|
||||||
@@ -79,6 +84,7 @@ export const SshCaModal = ({ popUp, handlePopUpToggle }: Props) => {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await createMutateAsync({
|
await createMutateAsync({
|
||||||
|
projectId,
|
||||||
friendlyName,
|
friendlyName,
|
||||||
keyAlgorithm
|
keyAlgorithm
|
||||||
});
|
});
|
||||||
+6
-6
@@ -2,9 +2,9 @@ import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
|||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
|
||||||
import { createNotification } from "@app/components/notifications";
|
import { createNotification } from "@app/components/notifications";
|
||||||
import { OrgPermissionCan } from "@app/components/permissions";
|
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||||
import { Button, DeleteActionModal } from "@app/components/v2";
|
import { Button, DeleteActionModal } from "@app/components/v2";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context";
|
||||||
import { SshCaStatus, useDeleteSshCa, useUpdateSshCa } from "@app/hooks/api";
|
import { SshCaStatus, useDeleteSshCa, useUpdateSshCa } from "@app/hooks/api";
|
||||||
import { usePopUp } from "@app/hooks/usePopUp";
|
import { usePopUp } from "@app/hooks/usePopUp";
|
||||||
|
|
||||||
@@ -64,9 +64,9 @@ export const SshCaSection = () => {
|
|||||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||||
<div className="mb-4 flex justify-between">
|
<div className="mb-4 flex justify-between">
|
||||||
<p className="text-xl font-semibold text-mineshaft-100">Certificate Authorities</p>
|
<p className="text-xl font-semibold text-mineshaft-100">Certificate Authorities</p>
|
||||||
<OrgPermissionCan
|
<ProjectPermissionCan
|
||||||
I={OrgPermissionActions.Create}
|
I={ProjectPermissionActions.Create}
|
||||||
a={OrgPermissionSubjects.SshCertificateAuthorities}
|
a={ProjectPermissionSub.SshCertificateAuthorities}
|
||||||
>
|
>
|
||||||
{(isAllowed) => (
|
{(isAllowed) => (
|
||||||
<Button
|
<Button
|
||||||
@@ -79,7 +79,7 @@ export const SshCaSection = () => {
|
|||||||
Create SSH CA
|
Create SSH CA
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</OrgPermissionCan>
|
</ProjectPermissionCan>
|
||||||
</div>
|
</div>
|
||||||
<SshCaTable handlePopUpOpen={handlePopUpOpen} />
|
<SshCaTable handlePopUpOpen={handlePopUpOpen} />
|
||||||
<SshCaModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
<SshCaModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||||
+14
-16
@@ -3,7 +3,7 @@ import { faBan, faCertificate, faEllipsis, faTrash } from "@fortawesome/free-sol
|
|||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { twMerge } from "tailwind-merge";
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
import { OrgPermissionCan } from "@app/components/permissions";
|
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||||
import {
|
import {
|
||||||
Badge,
|
Badge,
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
@@ -21,8 +21,8 @@ import {
|
|||||||
Tooltip,
|
Tooltip,
|
||||||
Tr
|
Tr
|
||||||
} from "@app/components/v2";
|
} from "@app/components/v2";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects, useOrganization } from "@app/context";
|
import { ProjectPermissionActions, ProjectPermissionSub,useWorkspace } from "@app/context";
|
||||||
import { SshCaStatus , useListOrgSshCas } from "@app/hooks/api";
|
import { SshCaStatus, useListWorkspaceSshCas } from "@app/hooks/api";
|
||||||
import { caStatusToNameMap, getCaStatusBadgeVariant } from "@app/hooks/api/ca/constants";
|
import { caStatusToNameMap, getCaStatusBadgeVariant } from "@app/hooks/api/ca/constants";
|
||||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||||
|
|
||||||
@@ -35,10 +35,8 @@ type Props = {
|
|||||||
|
|
||||||
export const SshCaTable = ({ handlePopUpOpen }: Props) => {
|
export const SshCaTable = ({ handlePopUpOpen }: Props) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { currentOrg } = useOrganization();
|
const { currentWorkspace } = useWorkspace();
|
||||||
const { data, isLoading } = useListOrgSshCas({
|
const { data, isLoading } = useListWorkspaceSshCas(currentWorkspace?.id || "");
|
||||||
orgId: currentOrg?.id ?? ""
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@@ -61,7 +59,7 @@ export const SshCaTable = ({ handlePopUpOpen }: Props) => {
|
|||||||
<Tr
|
<Tr
|
||||||
className="h-10 cursor-pointer transition-colors duration-100 hover:bg-mineshaft-700"
|
className="h-10 cursor-pointer transition-colors duration-100 hover:bg-mineshaft-700"
|
||||||
key={`ca-${ca.id}`}
|
key={`ca-${ca.id}`}
|
||||||
onClick={() => router.push(`/org/${currentOrg?.id}/ssh/ca/${ca.id}`)}
|
onClick={() => router.push(`/project/${currentWorkspace?.id}/ssh/ca/${ca.id}`)}
|
||||||
>
|
>
|
||||||
<Td>{ca.friendlyName}</Td>
|
<Td>{ca.friendlyName}</Td>
|
||||||
<Td>
|
<Td>
|
||||||
@@ -81,9 +79,9 @@ export const SshCaTable = ({ handlePopUpOpen }: Props) => {
|
|||||||
<DropdownMenuContent align="start" className="p-1">
|
<DropdownMenuContent align="start" className="p-1">
|
||||||
{(ca.status === SshCaStatus.ACTIVE ||
|
{(ca.status === SshCaStatus.ACTIVE ||
|
||||||
ca.status === SshCaStatus.DISABLED) && (
|
ca.status === SshCaStatus.DISABLED) && (
|
||||||
<OrgPermissionCan
|
<ProjectPermissionCan
|
||||||
I={OrgPermissionActions.Edit}
|
I={ProjectPermissionActions.Edit}
|
||||||
a={OrgPermissionSubjects.SshCertificateAuthorities}
|
a={ProjectPermissionSub.SshCertificateAuthorities}
|
||||||
>
|
>
|
||||||
{(isAllowed) => (
|
{(isAllowed) => (
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
@@ -109,11 +107,11 @@ export const SshCaTable = ({ handlePopUpOpen }: Props) => {
|
|||||||
} SSH CA`}
|
} SSH CA`}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
)}
|
)}
|
||||||
</OrgPermissionCan>
|
</ProjectPermissionCan>
|
||||||
)}
|
)}
|
||||||
<OrgPermissionCan
|
<ProjectPermissionCan
|
||||||
I={OrgPermissionActions.Delete}
|
I={ProjectPermissionActions.Delete}
|
||||||
a={OrgPermissionSubjects.SshCertificateAuthorities}
|
a={ProjectPermissionSub.SshCertificateAuthorities}
|
||||||
>
|
>
|
||||||
{(isAllowed) => (
|
{(isAllowed) => (
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
@@ -132,7 +130,7 @@ export const SshCaTable = ({ handlePopUpOpen }: Props) => {
|
|||||||
Delete SSH CA
|
Delete SSH CA
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
)}
|
)}
|
||||||
</OrgPermissionCan>
|
</ProjectPermissionCan>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</Td>
|
</Td>
|
||||||
+7
-4
@@ -1,9 +1,9 @@
|
|||||||
import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
|
||||||
import { OrgPermissionCan } from "@app/components/permissions";
|
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||||
import { Button } from "@app/components/v2";
|
import { Button } from "@app/components/v2";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context";
|
||||||
import { usePopUp } from "@app/hooks/usePopUp";
|
import { usePopUp } from "@app/hooks/usePopUp";
|
||||||
|
|
||||||
import { SshCertificateModal } from "../../SshCaPage/components/SshCertificateModal";
|
import { SshCertificateModal } from "../../SshCaPage/components/SshCertificateModal";
|
||||||
@@ -15,7 +15,10 @@ export const SshCertificatesSection = () => {
|
|||||||
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||||
<div className="mb-4 flex justify-between">
|
<div className="mb-4 flex justify-between">
|
||||||
<p className="text-xl font-semibold text-mineshaft-100">Certificates</p>
|
<p className="text-xl font-semibold text-mineshaft-100">Certificates</p>
|
||||||
<OrgPermissionCan I={OrgPermissionActions.Create} a={OrgPermissionSubjects.SshCertificates}>
|
<ProjectPermissionCan
|
||||||
|
I={ProjectPermissionActions.Create}
|
||||||
|
a={ProjectPermissionSub.SshCertificates}
|
||||||
|
>
|
||||||
{(isAllowed) => (
|
{(isAllowed) => (
|
||||||
<Button
|
<Button
|
||||||
colorSchema="primary"
|
colorSchema="primary"
|
||||||
@@ -27,7 +30,7 @@ export const SshCertificatesSection = () => {
|
|||||||
Request
|
Request
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</OrgPermissionCan>
|
</ProjectPermissionCan>
|
||||||
</div>
|
</div>
|
||||||
<SshCertificatesTable />
|
<SshCertificatesTable />
|
||||||
<SshCertificateModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
<SshCertificateModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||||
+5
-5
@@ -15,20 +15,20 @@ import {
|
|||||||
THead,
|
THead,
|
||||||
Tr
|
Tr
|
||||||
} from "@app/components/v2";
|
} from "@app/components/v2";
|
||||||
import { useOrganization } from "@app/context";
|
import { useWorkspace } from "@app/context";
|
||||||
import { useListOrgSshCertificates } from "@app/hooks/api";
|
import { useListWorkspaceSshCertificates } from "@app/hooks/api";
|
||||||
|
|
||||||
import { getSshCertStatusBadgeDetails } from "./SshCertificatesTable.utils";
|
import { getSshCertStatusBadgeDetails } from "./SshCertificatesTable.utils";
|
||||||
|
|
||||||
const PER_PAGE_INIT = 25;
|
const PER_PAGE_INIT = 25;
|
||||||
|
|
||||||
export const SshCertificatesTable = () => {
|
export const SshCertificatesTable = () => {
|
||||||
const { currentOrg } = useOrganization();
|
const { currentWorkspace } = useWorkspace();
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
const [perPage, setPerPage] = useState(PER_PAGE_INIT);
|
const [perPage, setPerPage] = useState(PER_PAGE_INIT);
|
||||||
|
|
||||||
const { data, isLoading } = useListOrgSshCertificates({
|
const { data, isLoading } = useListWorkspaceSshCertificates({
|
||||||
orgId: currentOrg?.id ?? "",
|
projectId: currentWorkspace?.id || "",
|
||||||
offset: (page - 1) * perPage,
|
offset: (page - 1) * perPage,
|
||||||
limit: perPage
|
limit: perPage
|
||||||
});
|
});
|
||||||
Reference in New Issue
Block a user