Files
infisical/backend/src/server/routes/v1/secret-sharing-router.ts
T

249 lines
6.5 KiB
TypeScript

import { z } from "zod";
import { SecretSharingSchema } from "@app/db/schemas";
import { SecretSharingAccessType } from "@app/lib/types";
import {
publicEndpointLimit,
publicSecretShareCreationLimit,
readLimit,
writeLimit
} from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
export const registerSecretSharingRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/",
config: {
rateLimit: readLimit
},
schema: {
querystring: z.object({
offset: z.coerce.number().min(0).max(100).default(0),
limit: z.coerce.number().min(1).max(100).default(25)
}),
response: {
200: z.object({
secrets: z.array(SecretSharingSchema),
totalCount: z.number()
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const { secrets, totalCount } = await req.server.services.secretSharing.getSharedSecrets({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.query
});
return {
secrets,
totalCount
};
}
});
server.route({
method: "GET",
url: "/public/:id",
config: {
rateLimit: publicEndpointLimit
},
schema: {
params: z.object({
id: z.string().uuid()
}),
querystring: z.object({
hashedHex: z.string().min(1)
}),
response: {
200: SecretSharingSchema.pick({
encryptedValue: true,
iv: true,
tag: true,
expiresAt: true,
expiresAfterViews: true,
accessType: true
}).extend({
orgName: z.string().optional()
})
}
},
handler: async (req) => {
const sharedSecret = await req.server.services.secretSharing.getActiveSharedSecretById({
sharedSecretId: req.params.id,
hashedHex: req.query.hashedHex,
orgId: req.permission?.orgId
});
// return undefined if it does not exist, has password set or has no more views allowed.
if (!sharedSecret || sharedSecret.password) return undefined;
return {
encryptedValue: sharedSecret.encryptedValue,
iv: sharedSecret.iv,
tag: sharedSecret.tag,
expiresAt: sharedSecret.expiresAt,
expiresAfterViews: sharedSecret.expiresAfterViews,
accessType: sharedSecret.accessType,
orgName: sharedSecret.orgName
};
}
});
server.route({
method: "POST",
url: "/public/:id/validate",
config: {
rateLimit: publicEndpointLimit
},
schema: {
params: z.object({
id: z.string().uuid()
}),
body: z.object({
password: z.string().min(1),
hashedHex: z.string()
}),
response: {
200: SecretSharingSchema.pick({
encryptedValue: true,
iv: true,
tag: true,
expiresAt: true,
expiresAfterViews: true,
accessType: true,
}).extend({
orgName: z.string().optional()
})
}
},
handler: async (req) => {
const { id } = req.params;
const { password, hashedHex } = req.body;
const sharedSecret = await req.server.services.secretSharing.validateSecretPassword({
sharedSecretId: id,
hashedHex,
orgId: req.permission?.orgId,
password
});
if (!sharedSecret) return undefined;
return {
encryptedValue: sharedSecret.encryptedValue,
iv: sharedSecret.iv,
tag: sharedSecret.tag,
expiresAt: sharedSecret.expiresAt,
expiresAfterViews: sharedSecret.expiresAfterViews,
accessType: sharedSecret.accessType,
orgName: sharedSecret.orgName
};
}
});
server.route({
method: "POST",
url: "/public",
config: {
rateLimit: writeLimit
},
schema: {
body: z.object({
encryptedValue: z.string(),
password: z.string().optional(),
hashedHex: z.string(),
iv: z.string(),
tag: z.string(),
expiresAt: z.string(),
expiresAfterViews: z.number().min(1).optional()
}),
response: {
200: z.object({
id: z.string().uuid()
})
}
},
handler: async (req) => {
const sharedSecret = await req.server.services.secretSharing.createPublicSharedSecret({
...req.body,
accessType: SecretSharingAccessType.Anyone
});
return { id: sharedSecret.id };
}
});
server.route({
method: "POST",
url: "/",
config: {
rateLimit: publicSecretShareCreationLimit
},
schema: {
body: z.object({
name: z.string().max(50).optional(),
password: z.string().optional(),
encryptedValue: z.string(),
hashedHex: z.string(),
iv: z.string(),
tag: z.string(),
expiresAt: z.string(),
expiresAfterViews: z.number().min(1).optional(),
accessType: z.nativeEnum(SecretSharingAccessType).default(SecretSharingAccessType.Organization)
}),
response: {
200: z.object({
id: z.string().uuid()
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const sharedSecret = await req.server.services.secretSharing.createSharedSecret({
actor: req.permission.type,
actorId: req.permission.id,
orgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.body
});
return { id: sharedSecret.id };
}
});
server.route({
method: "DELETE",
url: "/:sharedSecretId",
config: {
rateLimit: writeLimit
},
schema: {
params: z.object({
sharedSecretId: z.string().uuid()
}),
response: {
200: SecretSharingSchema
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const { sharedSecretId } = req.params;
const deletedSharedSecret = await req.server.services.secretSharing.deleteSharedSecretById({
actor: req.permission.type,
actorId: req.permission.id,
orgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
sharedSecretId
});
return { ...deletedSharedSecret };
}
});
};