feat(infisical-pg): fixing minor compatiability issues with frontend and backend on identity

This commit is contained in:
Akhil Mohan
2024-01-27 12:38:23 +05:30
parent d154f68a59
commit a6a60b7bbb
59 changed files with 1714 additions and 337 deletions
+65 -1
View File
@@ -13,6 +13,16 @@ import { authPaswordServiceFactory } from "@app/services/auth/auth-password-serv
import { authSignupServiceFactory } from "@app/services/auth/auth-signup-service";
import { tokenDalFactory } from "@app/services/auth-token/auth-token-dal";
import { tokenServiceFactory } from "@app/services/auth-token/auth-token-service";
import { identityDalFactory } from "@app/services/identity/identity-dal";
import { identityOrgDalFactory } from "@app/services/identity/identity-org-dal";
import { identityServiceFactory } from "@app/services/identity/identity-service";
import { identityAccessTokenDalFactory } from "@app/services/identity-access-token/identity-access-token-dal";
import { identityAccessTokenServiceFactory } from "@app/services/identity-access-token/identity-access-token-service";
import { identityProjectDalFactory } from "@app/services/identity-project/identity-project-dal";
import { identityProjectServiceFactory } from "@app/services/identity-project/identity-project-service";
import { identityUaClientSecretDalFactory } from "@app/services/identity-ua/identity-ua-client-secret-dal";
import { identityUaDalFactory } from "@app/services/identity-ua/identity-ua-dal";
import { identityUaServiceFactory } from "@app/services/identity-ua/identity-ua-service";
import { integrationDalFactory } from "@app/services/integration/integration-dal";
import { integrationServiceFactory } from "@app/services/integration/integration-service";
import { integrationAuthDalFactory } from "@app/services/integration-auth/integration-auth-dal";
@@ -43,11 +53,16 @@ import { secretFolderServiceFactory } from "@app/services/secret-folder/secret-f
import { secretImportDalFactory } from "@app/services/secret-import/secret-import-dal";
import { secretImportServiceFactory } from "@app/services/secret-import/secret-import-service";
import { secretTagDalFactory } from "@app/services/secret-tag/secret-tag-dal";
import { secretTagServiceFactory } from "@app/services/secret-tag/secret-tag-service";
import { serviceTokenDalFactory } from "@app/services/service-token/service-token-dal";
import { serviceTokenServiceFactory } from "@app/services/service-token/service-token-service";
import { TSmtpService } from "@app/services/smtp/smtp-service";
import { superAdminDalFactory } from "@app/services/super-admin/super-admin-dal";
import { superAdminServiceFactory } from "@app/services/super-admin/super-admin-service";
import { userDalFactory } from "@app/services/user/user-dal";
import { userServiceFactory } from "@app/services/user/user-service";
import { webhookDalFactory } from "@app/services/webhook/webhook-dal";
import { webhookServiceFactory } from "@app/services/webhook/webhook-service";
import { injectIdentity } from "../plugins/auth/inject-identity";
import { injectPermission } from "../plugins/auth/inject-permission";
@@ -85,6 +100,16 @@ export const registerRoutes = async (
const integrationDal = integrationDalFactory(db);
const integrationAuthDal = integrationAuthDalFactory(db);
const webhookDal = webhookDalFactory(db);
const serviceTokenDal = serviceTokenDalFactory(db);
const identityDal = identityDalFactory(db);
const identityAccessTokenDal = identityAccessTokenDalFactory(db);
const identityOrgMembershipDal = identityOrgDalFactory(db);
const identityProjectDal = identityProjectDalFactory(db);
const identityUaDal = identityUaDalFactory(db);
const identityUaClientSecretDal = identityUaClientSecretDalFactory(db);
// ee db layer ops
const permissionDal = permissionDalFactory(db);
@@ -161,6 +186,7 @@ export const registerRoutes = async (
secretDal,
secretTagDal
});
const secretTagService = secretTagServiceFactory({ secretTagDal, permissionService });
const folderService = secretFolderServiceFactory({
permissionService,
folderDal,
@@ -186,6 +212,37 @@ export const registerRoutes = async (
projectBotDal,
projectBotService
});
const webhookService = webhookServiceFactory({
permissionService,
webhookDal,
projectEnvDal
});
const serviceTokenService = serviceTokenServiceFactory({
projectEnvDal,
serviceTokenDal,
permissionService
});
const identityService = identityServiceFactory({
permissionService,
identityDal,
identityOrgMembershipDal
});
const identityAccessTokenService = identityAccessTokenServiceFactory({ identityAccessTokenDal });
const identityProjectService = identityProjectServiceFactory({
permissionService,
projectDal,
identityProjectDal,
identityOrgMembershipDal
});
const identityUaService = identityUaServiceFactory({
identityOrgMembershipDal,
permissionService,
identityDal,
identityAccessTokenDal,
identityUaClientSecretDal,
identityUaDal
});
await superAdminService.initServerCfg();
// inject all services
@@ -206,11 +263,18 @@ export const registerRoutes = async (
projectEnv: projectEnvService,
projectRole: projectRoleService,
secret: secretService,
secretTag: secretTagService,
folder: folderService,
secretImport: secretImportService,
projectBot: projectBotService,
integration: integrationService,
integrationAuth: integrationAuthService
integrationAuth: integrationAuthService,
webhook: webhookService,
serviceToken: serviceTokenService,
identity: identityService,
identityAccessToken: identityAccessTokenService,
identityProject: identityProjectService,
identityUa: identityUaService
});
server.decorate<FastifyZodProvider["store"]>("store", {
@@ -0,0 +1,15 @@
import { IntegrationAuthsSchema } from "@app/db/schemas";
// sometimes the return data must be santizied to avoid leaking important values
// always prefer pick over omit in zod
export const integrationAuthPubSchema = IntegrationAuthsSchema.pick({
projectId: true,
integration: true,
teamId: true,
url: true,
namespace: true,
accountId: true,
metadata: true,
createdAt: true,
updatedAt: true
});
+14 -16
View File
@@ -10,17 +10,16 @@ export const registerProjectBotRouter = async (server: FastifyZodProvider) => {
method: "GET",
schema: {
params: z.object({
workspaceId: z.string().trim()
projectId: z.string().trim()
}),
response: {
200: z.object({
bot: ProjectBotsSchema.pick({
name: true,
projectId: true,
isActive: true,
publicKey: true,
createdAt: true,
updatedAt: true
bot: ProjectBotsSchema.omit({
iv: true,
encryptedPrivateKey: true,
tag: true,
algorithm: true,
keyEncoding: true
})
})
}
@@ -30,7 +29,7 @@ export const registerProjectBotRouter = async (server: FastifyZodProvider) => {
const bot = await server.services.projectBot.findBotByProjectId({
actor: req.permission.type,
actorId: req.permission.id,
projectId: req.params.workspaceId
projectId: req.params.projectId
});
return { bot };
}
@@ -54,13 +53,12 @@ export const registerProjectBotRouter = async (server: FastifyZodProvider) => {
}),
response: {
200: z.object({
bot: ProjectBotsSchema.pick({
name: true,
projectId: true,
isActive: true,
publicKey: true,
createdAt: true,
updatedAt: true
bot: ProjectBotsSchema.omit({
iv: true,
encryptedPrivateKey: true,
tag: true,
algorithm: true,
keyEncoding: true
})
})
}
@@ -0,0 +1,33 @@
import { z } from "zod";
export const registerIdentityAccessTokenRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/token/renew",
method: "POST",
schema: {
body: z.object({
accessToken: z.string().trim()
}),
response: {
200: z.object({
accessToken: z.string(),
expiresIn: z.number(),
accessTokenMaxTTL: z.number(),
tokenType: z.literal("Bearer")
})
}
},
handler: async (req) => {
const { accessToken, identityAccessToken } =
await server.services.identityAccessToken.renewAccessToken({
accessToken: req.body.accessToken
});
return {
accessToken,
tokenType: "Bearer" as const,
expiresIn: identityAccessToken.accessTokenTTL,
accessTokenMaxTTL: identityAccessToken.accessTokenMaxTTL
};
}
});
};
@@ -0,0 +1,87 @@
import { z } from "zod";
import { IdentitiesSchema, OrgMembershipRole } from "@app/db/schemas";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
export const registerIdentityRouter = async (server: FastifyZodProvider) => {
server.route({
method: "POST",
url: "/",
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
body: z.object({
name: z.string().trim(),
organizationId: z.string().trim(),
role: z.string().trim().min(1).default(OrgMembershipRole.NoAccess)
}),
response: {
200: z.object({
identity: IdentitiesSchema
})
}
},
handler: async (req) => {
const identity = await server.services.identity.createIdentity({
actor: req.permission.type,
actorId: req.permission.id,
...req.body,
orgId: req.body.organizationId
});
return { identity };
}
});
server.route({
method: "PATCH",
url: "/:identityId",
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
identityId: z.string()
}),
body: z.object({
name: z.string().trim().optional(),
role: z.string().trim().min(1).optional()
}),
response: {
200: z.object({
identity: IdentitiesSchema
})
}
},
handler: async (req) => {
const identity = await server.services.identity.updateIdentity({
actor: req.permission.type,
actorId: req.permission.id,
id: req.params.identityId,
...req.body
});
return { identity };
}
});
server.route({
method: "DELETE",
url: "/:identityId",
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
identityId: z.string()
}),
response: {
200: z.object({
identity: IdentitiesSchema
})
}
},
handler: async (req) => {
const identity = await server.services.identity.deleteIdentity({
actor: req.permission.type,
actorId: req.permission.id,
id: req.params.identityId
});
return { identity };
}
});
};
@@ -0,0 +1,264 @@
import { z } from "zod";
import { IdentityUaClientSecretsSchema, IdentityUniversalAuthsSchema } from "@app/db/schemas";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
export const sanitizedClientSecretSchema = IdentityUaClientSecretsSchema.pick({
id: true,
createdAt: true,
updatedAt: true,
description: true,
clientSecretPrefix: true,
clientSecretNumUses: true,
clientSecretNumUsesLimit: true,
clientSecretTTL: true,
identityUAId: true,
isClientSecretRevoked: true
});
export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/universal-auth/login",
method: "POST",
schema: {
body: z.object({
clientId: z.string().trim(),
clientSecret: z.string().trim()
}),
response: {
200: z.object({
accessToken: z.string(),
expiresIn: z.number(),
accessTokenMaxTTL: z.number(),
tokenType: z.literal("Bearer")
})
}
},
handler: async (req) => {
const { identityUa, accessToken } = await server.services.identityUa.login(
req.body.clientId,
req.body.clientSecret
);
return {
accessToken,
tokenType: "Bearer" as const,
expiresIn: identityUa.accessTokenTTL,
accessTokenMaxTTL: identityUa.accessTokenMaxTTL
};
}
});
server.route({
url: "/universal-auth/identities/:identityId",
method: "POST",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
params: z.object({
identityId: z.string().trim()
}),
body: z.object({
clientSecretTrustedIps: z
.object({
ipAddress: z.string().trim()
})
.array()
.min(1)
.default([{ ipAddress: "0.0.0.0/0" }]),
accessTokenTrustedIps: z
.object({
ipAddress: z.string().trim()
})
.array()
.min(1)
.default([{ ipAddress: "0.0.0.0/0" }]),
accessTokenTTL: z
.number()
.int()
.min(1)
.refine((value) => value !== 0, {
message: "accessTokenTTL must have a non zero number"
})
.default(2592000),
accessTokenMaxTTL: z
.number()
.int()
.refine((value) => value !== 0, {
message: "accessTokenMaxTTL must have a non zero number"
})
.default(2592000), // 30 days
accessTokenNumUsesLimit: z.number().int().min(0).default(0)
}),
response: {
200: z.object({
identityUniversalAuth: IdentityUniversalAuthsSchema
})
}
},
handler: async (req) => {
const identityUniversalAuth = await server.services.identityUa.attachUa({
actor: req.permission.type,
actorId: req.permission.id,
...req.body,
identityId: req.params.identityId
});
return { identityUniversalAuth };
}
});
server.route({
url: "/universal-auth/identities/:identityId",
method: "PATCH",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
params: z.object({
identityId: z.string()
}),
body: z.object({
clientSecretTrustedIps: z
.object({
ipAddress: z.string().trim()
})
.array()
.min(1)
.optional(),
accessTokenTrustedIps: z
.object({
ipAddress: z.string().trim()
})
.array()
.min(1)
.optional(),
accessTokenTTL: z.number().int().min(0).optional(),
accessTokenNumUsesLimit: z.number().int().min(0).optional(),
accessTokenMaxTTL: z
.number()
.int()
.refine((value) => value !== 0, {
message: "accessTokenMaxTTL must have a non zero number"
})
.optional()
}),
response: {
200: z.object({
identityUniversalAuth: IdentityUniversalAuthsSchema
})
}
},
handler: async (req) => {
const identityUniversalAuth = await server.services.identityUa.updateUa({
actor: req.permission.type,
actorId: req.permission.id,
...req.body,
identityId: req.params.identityId
});
return { identityUniversalAuth };
}
});
server.route({
url: "/universal-auth/identities/:identityId",
method: "GET",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
params: z.object({
identityId: z.string()
}),
response: {
200: z.object({
identityUniversalAuth: IdentityUniversalAuthsSchema
})
}
},
handler: async (req) => {
const identityUniversalAuth = await server.services.identityUa.getIdentityUa({
actor: req.permission.type,
actorId: req.permission.id,
identityId: req.params.identityId
});
return { identityUniversalAuth };
}
});
server.route({
url: "/universal-auth/identities/:identityId/client-secrets",
method: "POST",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
params: z.object({
identityId: z.string()
}),
body: z.object({
description: z.string().trim().default(""),
numUsesLimit: z.number().min(0).default(0),
ttl: z.number().min(0).default(0)
}),
response: {
200: z.object({
clientSecret: z.string(),
clientSecretData: sanitizedClientSecretSchema
})
}
},
handler: async (req) => {
const { clientSecret, clientSecretData } =
await server.services.identityUa.createUaClientSecret({
actor: req.permission.type,
actorId: req.permission.id,
identityId: req.params.identityId,
...req.body
});
return { clientSecret, clientSecretData };
}
});
server.route({
url: "/universal-auth/identities/:identityId/client-secrets",
method: "GET",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
params: z.object({
identityId: z.string()
}),
response: {
200: z.object({
clientSecretData: sanitizedClientSecretSchema.array()
})
}
},
handler: async (req) => {
const clientSecretData = await server.services.identityUa.getUaClientSecrets({
actor: req.permission.type,
actorId: req.permission.id,
identityId: req.params.identityId
});
return { clientSecretData };
}
});
server.route({
url: "/universal-auth/identities/:identityId/client-secrets/:clientSecretId/revoke",
method: "POST",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
params: z.object({
identityId: z.string(),
clientSecretId: z.string()
}),
response: {
200: z.object({
clientSecretData: sanitizedClientSecretSchema
})
}
},
handler: async (req) => {
const clientSecretData = await server.services.identityUa.revokeUaClientSecret({
actor: req.permission.type,
actorId: req.permission.id,
identityId: req.params.identityId,
clientSecretId: req.params.clientSecretId
});
return { clientSecretData };
}
});
};
+16 -1
View File
@@ -1,6 +1,9 @@
import { registerAdminRouter } from "./admin-router";
import { registerAuthRoutes } from "./auth-router";
import { registerProjectBotRouter } from "./bot-router";
import { registerIdentityAccessTokenRouter } from "./identity-access-token-router";
import { registerIdentityRouter } from "./identity-router";
import { registerIdentityUaRouter } from "./identity-ua";
import { registerIntegrationAuthRouter } from "./integration-auth-router";
import { registerIntegrationRouter } from "./integration-router";
import { registerInviteOrgRouter } from "./invite-org-router";
@@ -12,13 +15,22 @@ import { registerProjectMembershipRouter } from "./project-membership-router";
import { registerProjectRouter } from "./project-router";
import { registerSecretFolderRouter } from "./secret-folder-router";
import { registerSecretImportRouter } from "./secret-import-router";
import { registerSecretTagRouter } from "./secret-tag-router";
import { registerSsoRouter } from "./sso-router";
import { registerUserActionRouter } from "./user-action-router";
import { registerUserRouter } from "./user-router";
import { registerWebhookRouter } from "./webhook-router";
export const registerV1Routes = async (server: FastifyZodProvider) => {
await server.register(registerSsoRouter, { prefix: "/sso" });
await server.register(registerAuthRoutes, { prefix: "/auth" });
await server.register(
async (authServer) => {
await authServer.register(registerAuthRoutes);
await authServer.register(registerIdentityUaRouter);
await authServer.register(registerIdentityAccessTokenRouter);
},
{ prefix: "/auth" }
);
await server.register(registerPasswordRouter, { prefix: "/password" });
await server.register(registerOrgRouter, { prefix: "/organization" });
await server.register(registerAdminRouter, { prefix: "/admin" });
@@ -34,6 +46,7 @@ export const registerV1Routes = async (server: FastifyZodProvider) => {
await projectServer.register(registerProjectEnvRouter);
await projectServer.register(registerProjectKeyRouter);
await projectServer.register(registerProjectMembershipRouter);
await projectServer.register(registerSecretTagRouter);
},
{ prefix: "/workspace" }
);
@@ -41,4 +54,6 @@ export const registerV1Routes = async (server: FastifyZodProvider) => {
await server.register(registerProjectBotRouter, { prefix: "/bot" });
await server.register(registerIntegrationRouter, { prefix: "/integration" });
await server.register(registerIntegrationAuthRouter, { prefix: "/integration-auth" });
await server.register(registerWebhookRouter, { prefix: "/webhooks" });
await server.register(registerIdentityRouter, { prefix: "/identities" });
};
@@ -1,9 +1,10 @@
import { z } from "zod";
import { IntegrationAuthsSchema } from "@app/db/schemas";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { integrationAuthPubSchema } from "../sanitizedSchemas";
export const registerIntegrationAuthRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/integration-options",
@@ -32,18 +33,6 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
}
});
const integrationPublicSchema = IntegrationAuthsSchema.pick({
projectId: true,
integration: true,
teamId: true,
url: true,
namespace: true,
accountId: true,
metadata: true,
createdAt: true,
updatedAt: true
});
server.route({
url: "/:integrationAuthId",
method: "GET",
@@ -54,7 +43,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
}),
response: {
200: z.object({
integrationAuth: integrationPublicSchema
integrationAuth: integrationAuthPubSchema
})
}
},
@@ -78,7 +67,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
}),
response: {
200: z.object({
integrationAuth: integrationPublicSchema
integrationAuth: integrationAuthPubSchema
})
}
},
@@ -108,7 +97,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
}),
response: {
200: z.object({
integrationAuth: integrationPublicSchema
integrationAuth: integrationAuthPubSchema
})
}
},
@@ -1,6 +1,7 @@
import { z } from "zod";
import {
IntegrationsSchema,
ProjectKeysSchema,
ProjectMembershipsSchema,
ProjectsSchema,
@@ -10,6 +11,9 @@ import {
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { integrationAuthPubSchema } from "../sanitizedSchemas";
import { sanitizedServiceTokenSchema } from "../v2/service-token-router";
const projectWithEnv = ProjectsSchema.merge(
z.object({
environments: z.object({ name: z.string(), slug: z.string(), id: z.string() }).array()
@@ -264,4 +268,76 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
return { invitee, latestKey };
}
});
server.route({
url: "/:workspaceId/integrations",
method: "GET",
schema: {
params: z.object({
workspaceId: z.string().trim()
}),
response: {
200: z.object({
integrations: IntegrationsSchema.array()
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const integrations = await server.services.integration.listIntegrationByProject({
actorId: req.permission.id,
actor: req.permission.type,
projectId: req.params.workspaceId
});
return { integrations };
}
});
server.route({
url: "/:workspaceId/authorizations",
method: "GET",
schema: {
params: z.object({
workspaceId: z.string().trim()
}),
response: {
200: z.object({
authorizations: integrationAuthPubSchema.array()
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const authorizations = await server.services.integration.listIntegrationByProject({
actorId: req.permission.id,
actor: req.permission.type,
projectId: req.params.workspaceId
});
return { authorizations };
}
});
server.route({
url: "/:workspaceId/service-token-data",
method: "GET",
schema: {
params: z.object({
workspaceId: z.string().trim()
}),
response: {
200: z.object({
serviceTokenData: sanitizedServiceTokenSchema.array()
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const serviceTokenData = await server.services.serviceToken.getProjectServiceTokens({
actorId: req.permission.id,
actor: req.permission.type,
projectId: req.params.workspaceId
});
return { serviceTokenData };
}
});
};
@@ -0,0 +1,86 @@
import { z } from "zod";
import { SecretTagsSchema } from "@app/db/schemas";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
export const registerSecretTagRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/:projectId/tags",
method: "GET",
schema: {
params: z.object({
projectId: z.string().trim()
}),
response: {
200: z.object({
workspaceTags: SecretTagsSchema.array()
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const workspaceTags = await server.services.secretTag.getProjectTags({
actor: req.permission.type,
actorId: req.permission.id,
projectId: req.params.projectId
});
return { workspaceTags };
}
});
server.route({
url: "/:projectId/tags",
method: "POST",
schema: {
params: z.object({
projectId: z.string().trim()
}),
body: z.object({
name: z.string().trim(),
slug: z.string().trim(),
color: z.string()
}),
response: {
200: z.object({
workspaceTag: SecretTagsSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const workspaceTag = await server.services.secretTag.createTag({
actor: req.permission.type,
actorId: req.permission.id,
projectId: req.params.projectId,
...req.body
});
return { workspaceTag };
}
});
server.route({
url: "/:projectId/tags/:tagId",
method: "DELETE",
schema: {
params: z.object({
projectId: z.string().trim(),
tagId: z.string().trim()
}),
response: {
200: z.object({
workspaceTag: SecretTagsSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const workspaceTag = await server.services.secretTag.deleteTag({
actor: req.permission.type,
actorId: req.permission.id,
id: req.params.tagId
});
return { workspaceTag };
}
});
};
@@ -0,0 +1,155 @@
import { z } from "zod";
import { WebhooksSchema } from "@app/db/schemas";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
export const sanitizedWebhookSchema = WebhooksSchema.omit({
encryptedSecretKey: true,
iv: true,
tag: true,
algorithm: true,
keyEncoding: true,
}).merge(
z.object({
projectId:z.string(),
environment: z.object({
id: z.string(),
name: z.string(),
slug: z.string()
})
})
);
export const registerWebhookRouter = async (server: FastifyZodProvider) => {
server.route({
method: "POST",
url: "/",
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
body: z.object({
workspaceId: z.string().trim(),
environment: z.string().trim(),
webhookUrl: z.string().url().trim(),
webhookSecretKey: z.string().trim().optional(),
secretPath: z.string().trim().default("/")
}),
response: {
200: z.object({
message: z.string(),
webhook: sanitizedWebhookSchema
})
}
},
handler: async (req) => {
const webhook = await server.services.webhook.createWebhook({
actor: req.permission.type,
actorId: req.permission.id,
projectId: req.body.workspaceId,
...req.body
});
return { message: "Successfully created webhook", webhook };
}
});
server.route({
method: "PATCH",
url: "/:webhookId",
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
webhookId: z.string().trim()
}),
body: z.object({
isDisabled: z.boolean().default(false)
}),
response: {
200: z.object({
message: z.string(),
webhook: sanitizedWebhookSchema
})
}
},
handler: async (req) => {
const webhook = await server.services.webhook.updateWebhook({
actor: req.permission.type,
actorId: req.permission.id,
id: req.params.webhookId,
isDisabled: req.body.isDisabled
});
return { message: "Successfully updated webhook", webhook };
}
});
server.route({
method: "DELETE",
url: "/:webhookId",
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
webhookId: z.string().trim()
})
},
handler: async (req) => {
const webhook = await server.services.webhook.deleteWebhook({
actor: req.permission.type,
actorId: req.permission.id,
id: req.params.webhookId
});
return { message: "Successfully deleted webhook", webhook };
}
});
server.route({
method: "POST",
url: "/:webhookId/test",
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
webhookId: z.string().trim()
}),
response: {
200: z.object({
message: z.string(),
webhook: sanitizedWebhookSchema
})
}
},
handler: async (req) => {
const webhook = await server.services.webhook.testWebhook({
actor: req.permission.type,
actorId: req.permission.id,
id: req.params.webhookId
});
return { message: "Successfully tested webhook", webhook };
}
});
server.route({
method: "GET",
url: "/",
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
querystring: z.object({
workspaceId: z.string().trim(),
environment: z.string().trim().optional(),
secretPath: z.string().trim().optional()
}),
response: {
200: z.object({
message: z.string(),
webhooks: sanitizedWebhookSchema.array()
})
}
},
handler: async (req) => {
const webhooks = await server.services.webhook.listWebhooks({
actor: req.permission.type,
actorId: req.permission.id,
...req.query,
projectId: req.query.workspaceId
});
return { message: "Successfully fetched webhook", webhooks };
}
});
};
@@ -0,0 +1,42 @@
import { z } from "zod";
import { IdentitiesSchema, IdentityOrgMembershipsSchema, OrgRolesSchema } from "@app/db/schemas";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
export const registerIdentityOrgRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/:orgId/identity-memberships",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
params: z.object({
orgId: z.string().trim()
}),
response: {
200: z.object({
identityMemberships: IdentityOrgMembershipsSchema.merge(
z.object({
customRole: OrgRolesSchema.pick({
id: true,
name: true,
slug: true,
permissions: true,
description: true
}).optional(),
identity: IdentitiesSchema.pick({ name: true, id: true, authMethod: true })
})
).array()
})
}
},
handler: async (req) => {
const identityMemberships = await server.services.identity.listOrgIdentities({
actor: req.permission.type,
actorId: req.permission.id,
orgId: req.params.orgId
});
return { identityMemberships };
}
});
};
@@ -0,0 +1,133 @@
import { z } from "zod";
import {
IdentitiesSchema,
IdentityProjectMembershipsSchema,
ProjectMembershipRole,
ProjectRolesSchema
} from "@app/db/schemas";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
export const registerIdentityProjectRouter = async (server: FastifyZodProvider) => {
server.route({
method: "POST",
url: "/:projectId/identity-memberships/:identityId",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
params: z.object({
projectId: z.string().trim(),
identityId: z.string().trim()
}),
body: z.object({
role: z.string().trim().min(1).default(ProjectMembershipRole.NoAccess)
}),
response: {
200: z.object({
identityMembership: IdentityProjectMembershipsSchema
})
}
},
handler: async (req) => {
const identityMembership = await server.services.identityProject.createProjectIdentity({
actor: req.permission.type,
actorId: req.permission.id,
identityId: req.params.identityId,
projectId: req.params.projectId,
role: req.body.role
});
return { identityMembership };
}
});
server.route({
method: "PATCH",
url: "/:projectId/identity-memberships/:identityId",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
params: z.object({
projectId: z.string().trim(),
identityId: z.string().trim()
}),
body: z.object({
role: z.string().trim().min(1).default(ProjectMembershipRole.NoAccess)
}),
response: {
200: z.object({
identityMembership: IdentityProjectMembershipsSchema
})
}
},
handler: async (req) => {
const identityMembership = await server.services.identityProject.updateProjectIdentity({
actor: req.permission.type,
actorId: req.permission.id,
identityId: req.params.identityId,
projectId: req.params.projectId,
role: req.body.role
});
return { identityMembership };
}
});
server.route({
method: "DELETE",
url: "/:projectId/identity-memberships/:identityId",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
params: z.object({
projectId: z.string().trim(),
identityId: z.string().trim()
}),
response: {
200: z.object({
identityMembership: IdentityProjectMembershipsSchema
})
}
},
handler: async (req) => {
const identityMembership = await server.services.identityProject.deleteProjectIdentity({
actor: req.permission.type,
actorId: req.permission.id,
identityId: req.params.identityId,
projectId: req.params.projectId
});
return { identityMembership };
}
});
server.route({
method: "GET",
url: "/:projectId/identity-memberships",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
params: z.object({
projectId: z.string().trim()
}),
response: {
200: z.object({
identityMemberships: IdentityProjectMembershipsSchema.merge(
z.object({
customRole: ProjectRolesSchema.pick({
id: true,
name: true,
slug: true,
permissions: true,
description: true
}).optional(),
identity: IdentitiesSchema.pick({ name: true, id: true, authMethod: true })
})
).array()
})
}
},
handler: async (req) => {
const identityMemberships = await server.services.identityProject.listProjectIdentities({
actor: req.permission.type,
actorId: req.permission.id,
projectId: req.params.projectId
});
return { identityMemberships };
}
});
};
+13
View File
@@ -1,13 +1,26 @@
import { registerIdentityOrgRouter } from "./identity-org-router";
import { registerIdentityProjectRouter } from "./identity-project-router";
import { registerMfaRouter } from "./mfa-router";
import { registerOrgRouter } from "./organization-router";
import { registerProjectRouter } from "./project-router";
import { registerServiceTokenRouter } from "./service-token-router";
import { registerUserRouter } from "./user-router";
export const registerV2Routes = async (server: FastifyZodProvider) => {
await server.register(registerMfaRouter, { prefix: "/auth" });
await server.register(registerUserRouter, { prefix: "/users" });
await server.register(registerServiceTokenRouter, { prefix: "/service-token" });
await server.register(
async (orgRouter) => {
await orgRouter.register(registerOrgRouter);
await orgRouter.register(registerIdentityOrgRouter);
},
{ prefix: "/organizations" }
);
await server.register(
async (projectServer) => {
projectServer.register(registerProjectRouter);
projectServer.register(registerIdentityProjectRouter);
},
{ prefix: "/workspace" }
);
@@ -0,0 +1,98 @@
import { z } from "zod";
import { ServiceTokensSchema } from "@app/db/schemas";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
export const sanitizedServiceTokenSchema = ServiceTokensSchema.omit({
secretHash: true,
encryptedKey: true,
iv: true,
tag: true
});
export const registerServiceTokenRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/",
method: "GET",
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
serviceTokenId: z.string().trim()
}),
response: {
200: sanitizedServiceTokenSchema
}
},
handler: async (req) => {
const serviceTokenData = await server.services.serviceToken.getServiceToken({
actorId: req.permission.id,
actor: req.permission.type
});
return serviceTokenData;
}
});
server.route({
url: "/",
method: "POST",
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
body: z.object({
name: z.string().trim(),
workspaceId: z.string().trim(),
scopes: z
.object({
environment: z.string().trim(),
secretPath: z.string().trim()
})
.array()
.min(1),
encryptedKey: z.string().trim(),
iv: z.string().trim(),
tag: z.string().trim(),
expiresIn: z.number(),
permissions: z.enum(["read", "write"]).array()
}),
response: {
200: z.object({
serviceToken: z.string(),
serviceTokenData: sanitizedServiceTokenSchema
})
}
},
handler: async (req) => {
const { serviceToken, token } = await server.services.serviceToken.createServiceToken({
actorId: req.permission.id,
actor: req.permission.type,
...req.body,
projectId: req.body.workspaceId
});
return { serviceToken: token, serviceTokenData: serviceToken };
}
});
server.route({
url: "/:serviceTokenId",
method: "DELETE",
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
serviceTokenId: z.string().trim()
}),
response: {
200: z.object({
serviceTokenData: sanitizedServiceTokenSchema
})
}
},
handler: async (req) => {
const serviceTokenData = await server.services.serviceToken.deleteServiceToken({
actorId: req.permission.id,
actor: req.permission.type,
id: req.params.serviceTokenId
});
return { serviceTokenData };
}
});
};