mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-14 19:44:52 +00:00
feat: changed backend-pg to backend
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
import fp from "fastify-plugin";
|
||||
|
||||
import { UserAgentType } from "@app/ee/services/audit-log/audit-log-types";
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
import { ActorType } from "@app/services/auth/auth-type";
|
||||
|
||||
export const getUserAgentType = (userAgent: string | undefined) => {
|
||||
if (userAgent === undefined) {
|
||||
return UserAgentType.OTHER;
|
||||
}
|
||||
if (userAgent === UserAgentType.CLI) {
|
||||
return UserAgentType.CLI;
|
||||
}
|
||||
if (userAgent === UserAgentType.K8_OPERATOR) {
|
||||
return UserAgentType.K8_OPERATOR;
|
||||
}
|
||||
if (userAgent === UserAgentType.TERRAFORM) {
|
||||
return UserAgentType.TERRAFORM;
|
||||
}
|
||||
if (userAgent.toLowerCase().includes("mozilla")) {
|
||||
return UserAgentType.WEB;
|
||||
}
|
||||
if (userAgent.includes(UserAgentType.NODE_SDK)) {
|
||||
return UserAgentType.NODE_SDK;
|
||||
}
|
||||
if (userAgent.includes(UserAgentType.PYTHON_SDK)) {
|
||||
return UserAgentType.PYTHON_SDK;
|
||||
}
|
||||
return UserAgentType.OTHER;
|
||||
};
|
||||
|
||||
export const injectAuditLogInfo = fp(async (server: FastifyZodProvider) => {
|
||||
server.decorateRequest("auditLogInfo", null);
|
||||
server.addHook("onRequest", async (req) => {
|
||||
if (!req.auth) return;
|
||||
const userAgent = req.headers["user-agent"] ?? "";
|
||||
const payload = {
|
||||
ipAddress: req.realIp,
|
||||
userAgent,
|
||||
userAgentType: getUserAgentType(userAgent)
|
||||
} as typeof req.auditLogInfo;
|
||||
if (req.auth.actor === ActorType.USER) {
|
||||
payload.actor = {
|
||||
type: ActorType.USER,
|
||||
metadata: {
|
||||
email: req.auth.user.email,
|
||||
userId: req.permission.id
|
||||
}
|
||||
};
|
||||
} else if (req.auth.actor === ActorType.SERVICE) {
|
||||
payload.actor = {
|
||||
type: ActorType.SERVICE,
|
||||
metadata: {
|
||||
name: req.auth.serviceToken.name,
|
||||
serviceId: req.auth.serviceTokenId
|
||||
}
|
||||
};
|
||||
} else if (req.auth.actor === ActorType.IDENTITY) {
|
||||
payload.actor = {
|
||||
type: ActorType.IDENTITY,
|
||||
metadata: {
|
||||
name: req.auth.identityName,
|
||||
identityId: req.auth.identityId
|
||||
}
|
||||
};
|
||||
} else {
|
||||
throw new BadRequestError({ message: "Missing logic for other actor" });
|
||||
}
|
||||
req.auditLogInfo = payload;
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,129 @@
|
||||
import { FastifyRequest } from "fastify";
|
||||
import fp from "fastify-plugin";
|
||||
import jwt, { JwtPayload } from "jsonwebtoken";
|
||||
|
||||
import { TServiceTokens, TUsers } from "@app/db/schemas";
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { UnauthorizedError } from "@app/lib/errors";
|
||||
import {
|
||||
ActorType,
|
||||
AuthMode,
|
||||
AuthModeJwtTokenPayload,
|
||||
AuthTokenType
|
||||
} from "@app/services/auth/auth-type";
|
||||
import { TIdentityAccessTokenJwtPayload } from "@app/services/identity-access-token/identity-access-token-types";
|
||||
|
||||
export type TAuthMode =
|
||||
| {
|
||||
authMode: AuthMode.JWT;
|
||||
actor: ActorType.USER;
|
||||
userId: string;
|
||||
tokenVersionId: string; // the session id of token used
|
||||
user: TUsers;
|
||||
}
|
||||
| {
|
||||
authMode: AuthMode.API_KEY;
|
||||
actor: ActorType.USER;
|
||||
userId: string;
|
||||
user: TUsers;
|
||||
}
|
||||
| {
|
||||
authMode: AuthMode.SERVICE_TOKEN;
|
||||
serviceToken: TServiceTokens;
|
||||
actor: ActorType.SERVICE;
|
||||
serviceTokenId: string;
|
||||
}
|
||||
| {
|
||||
authMode: AuthMode.IDENTITY_ACCESS_TOKEN;
|
||||
actor: ActorType.IDENTITY;
|
||||
identityId: string;
|
||||
identityName: string;
|
||||
};
|
||||
|
||||
const extractAuth = async (req: FastifyRequest, jwtSecret: string) => {
|
||||
const apiKey = req.headers?.["x-api-key"];
|
||||
if (apiKey) {
|
||||
return { authMode: AuthMode.API_KEY, token: apiKey, actor: ActorType.USER } as const;
|
||||
}
|
||||
const authHeader = req.headers?.authorization;
|
||||
if (!authHeader) return { authMode: null, token: null };
|
||||
|
||||
const authTokenValue = authHeader.slice(7); // slice of after Bearer
|
||||
if (authTokenValue.startsWith("st.")) {
|
||||
return {
|
||||
authMode: AuthMode.SERVICE_TOKEN,
|
||||
token: authTokenValue,
|
||||
actor: ActorType.SERVICE
|
||||
} as const;
|
||||
}
|
||||
|
||||
const decodedToken = jwt.verify(authTokenValue, jwtSecret) as JwtPayload;
|
||||
switch (decodedToken.authTokenType) {
|
||||
case AuthTokenType.ACCESS_TOKEN:
|
||||
return {
|
||||
authMode: AuthMode.JWT,
|
||||
token: decodedToken as AuthModeJwtTokenPayload,
|
||||
actor: ActorType.USER
|
||||
} as const;
|
||||
case AuthTokenType.API_KEY:
|
||||
return { authMode: AuthMode.API_KEY, token: decodedToken, actor: ActorType.USER } as const;
|
||||
case AuthTokenType.IDENTITY_ACCESS_TOKEN:
|
||||
return {
|
||||
authMode: AuthMode.IDENTITY_ACCESS_TOKEN,
|
||||
token: decodedToken as TIdentityAccessTokenJwtPayload,
|
||||
actor: ActorType.IDENTITY
|
||||
} as const;
|
||||
default:
|
||||
return { authMode: null, token: null } as const;
|
||||
}
|
||||
};
|
||||
|
||||
export const injectIdentity = fp(async (server: FastifyZodProvider) => {
|
||||
server.decorateRequest("auth", null);
|
||||
server.addHook("onRequest", async (req) => {
|
||||
const appCfg = getConfig();
|
||||
const { authMode, token, actor } = await extractAuth(req, appCfg.AUTH_SECRET);
|
||||
if (!authMode) return;
|
||||
|
||||
switch (authMode) {
|
||||
case AuthMode.JWT: {
|
||||
const { user, tokenVersionId } =
|
||||
await server.services.authToken.fnValidateJwtIdentity(token);
|
||||
req.auth = { authMode: AuthMode.JWT, user, userId: user.id, tokenVersionId, actor };
|
||||
break;
|
||||
}
|
||||
case AuthMode.IDENTITY_ACCESS_TOKEN: {
|
||||
const identity = await server.services.identityAccessToken.fnValidateIdentityAccessToken(
|
||||
token,
|
||||
req.realIp
|
||||
);
|
||||
req.auth = {
|
||||
authMode: AuthMode.IDENTITY_ACCESS_TOKEN,
|
||||
actor,
|
||||
identityId: identity.identityId,
|
||||
identityName: identity.name
|
||||
};
|
||||
break;
|
||||
}
|
||||
case AuthMode.SERVICE_TOKEN: {
|
||||
const serviceToken = await server.services.serviceToken.fnValidateServiceToken(
|
||||
token as string
|
||||
);
|
||||
req.auth = {
|
||||
authMode: AuthMode.SERVICE_TOKEN as const,
|
||||
serviceToken,
|
||||
serviceTokenId: serviceToken.id,
|
||||
actor
|
||||
};
|
||||
break;
|
||||
}
|
||||
case AuthMode.API_KEY: {
|
||||
const user = await server.services.apiKey.fnValidateApiKey(token as string);
|
||||
req.auth = { authMode: AuthMode.API_KEY as const, userId: user.id, actor, user };
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new UnauthorizedError({ name: "Unknown token strategy" });
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
import fp from "fastify-plugin";
|
||||
|
||||
import { ActorType } from "@app/services/auth/auth-type";
|
||||
|
||||
// inject permission type needed based on auth extracted
|
||||
export const injectPermission = fp(async (server) => {
|
||||
server.decorateRequest("permission", null);
|
||||
server.addHook("onRequest", async (req) => {
|
||||
if (!req.auth) return;
|
||||
|
||||
if (req.auth.actor === ActorType.USER) {
|
||||
req.permission = { type: ActorType.USER, id: req.auth.userId };
|
||||
} else if (req.auth.actor === ActorType.IDENTITY) {
|
||||
req.permission = { type: ActorType.IDENTITY, id: req.auth.identityId };
|
||||
} else if (req.auth.actor === ActorType.SERVICE) {
|
||||
req.permission = { type: ActorType.SERVICE, id: req.auth.serviceTokenId };
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
import { FastifyRequest } from "fastify";
|
||||
|
||||
import { UnauthorizedError } from "@app/lib/errors";
|
||||
import { ActorType } from "@app/services/auth/auth-type";
|
||||
|
||||
export const verifySuperAdmin = async <T extends FastifyRequest>(req: T) => {
|
||||
if (req.auth.actor !== ActorType.USER || !req.auth.user.superAdmin)
|
||||
throw new UnauthorizedError({
|
||||
name: "Unauthorized access",
|
||||
message: "Requires superadmin access"
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
import { FastifyRequest } from "fastify";
|
||||
|
||||
import { UnauthorizedError } from "@app/lib/errors";
|
||||
import { AuthMode } from "@app/services/auth/auth-type";
|
||||
|
||||
export const verifyAuth =
|
||||
<T extends FastifyRequest>(authStrats: AuthMode[]) =>
|
||||
async (req: T) => {
|
||||
if (!Array.isArray(authStrats)) throw new Error("Auth strategy must be array");
|
||||
if (!req.auth)
|
||||
throw new UnauthorizedError({ name: "Unauthorized access", message: "Token missing" });
|
||||
|
||||
const isAccessAllowed = authStrats.some((strat) => strat === req.auth.authMode);
|
||||
if (!isAccessAllowed) {
|
||||
throw new UnauthorizedError({ name: `${req.url} Unauthorized Access` });
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
import { ForbiddenError } from "@casl/ability";
|
||||
import fastifyPlugin from "fastify-plugin";
|
||||
import { ZodError } from "zod";
|
||||
|
||||
import {
|
||||
BadRequestError,
|
||||
DatabaseError,
|
||||
ForbiddenRequestError,
|
||||
InternalServerError,
|
||||
UnauthorizedError
|
||||
} from "@app/lib/errors";
|
||||
|
||||
export const fastifyErrHandler = fastifyPlugin(async (server: FastifyZodProvider) => {
|
||||
server.setErrorHandler((error, req, res) => {
|
||||
req.log.error(error);
|
||||
if (error instanceof BadRequestError) {
|
||||
res.status(400).send({ statusCode: 400, message: error.message, error: error.name });
|
||||
} else if (error instanceof UnauthorizedError || error instanceof ForbiddenRequestError) {
|
||||
res.status(403).send({ statusCode: 403, message: error.message, error: error.name });
|
||||
} else if (error instanceof DatabaseError || error instanceof InternalServerError) {
|
||||
res.status(500).send({ statusCode: 500, message: "Something went wrong", error: error.name });
|
||||
} else if (error instanceof ZodError) {
|
||||
res.status(403).send({ statusCode: 403, error: "ValidationFailure", message: error.issues });
|
||||
} else if (error instanceof ForbiddenError) {
|
||||
res.status(403).send({
|
||||
statusCode: 403,
|
||||
error: "PermissionDenied",
|
||||
message: `You are not allowed to ${error.action} on ${error.subjectType}`
|
||||
});
|
||||
} else {
|
||||
res.send(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
// this plugins allows to run infisical in standalone mode
|
||||
// standalone mode = infisical backend and nextjs frontend in one server
|
||||
// this way users don't need to deploy two things
|
||||
|
||||
import path from "node:path";
|
||||
|
||||
// to enabled this u need to set standalone mode to true
|
||||
export const registerExternalNextjs = async (
|
||||
server: FastifyZodProvider,
|
||||
{
|
||||
standaloneMode,
|
||||
dir,
|
||||
port
|
||||
}: {
|
||||
standaloneMode?: boolean;
|
||||
dir: string;
|
||||
port: number;
|
||||
}
|
||||
) => {
|
||||
if (standaloneMode) {
|
||||
const nextJsBuildPath = path.join(dir, "frontend-build");
|
||||
|
||||
const { default: conf } = await import(
|
||||
path.join(dir, "frontend-build/.next/required-server-files.json"),
|
||||
// @ts-expect-error type
|
||||
{
|
||||
assert: { type: "json" }
|
||||
}
|
||||
);
|
||||
|
||||
const { default: NextServer } = (
|
||||
await import(path.join(dir, "frontend-build/node_modules/next/dist/server/next-server.js"))
|
||||
).default;
|
||||
const nextApp = new NextServer({
|
||||
dev: false,
|
||||
dir: nextJsBuildPath,
|
||||
port,
|
||||
conf: conf.config,
|
||||
hostname: "local",
|
||||
customServer: false
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: ["GET", "PUT", "PATCH", "POST", "DELETE"],
|
||||
url: "/*",
|
||||
handler: (req, res) =>
|
||||
nextApp
|
||||
.getRequestHandler()(req.raw, res.raw)
|
||||
.then(() => {
|
||||
res.hijack();
|
||||
})
|
||||
});
|
||||
server.addHook("onClose", () => nextApp.close());
|
||||
await nextApp.prepare();
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,142 @@
|
||||
/* eslint-disable */
|
||||
// Code taken from https://www.npmjs.com/package/fastify-type-provider-zod
|
||||
// Full credits goes to https://github.com/turkerdev
|
||||
// Code taken to keep in in house
|
||||
import type { FastifySchema, FastifySchemaCompiler, FastifyTypeProvider } from "fastify";
|
||||
import type { FastifySerializerCompiler } from "fastify/types/schema";
|
||||
import type { z, ZodAny, ZodTypeAny } from "zod";
|
||||
import { zodToJsonSchema } from "zod-to-json-schema";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type FreeformRecord = Record<string, any>;
|
||||
|
||||
const defaultSkipList = [
|
||||
"/documentation/",
|
||||
"/documentation/initOAuth",
|
||||
"/documentation/json",
|
||||
"/documentation/uiConfig",
|
||||
"/documentation/yaml",
|
||||
"/documentation/*",
|
||||
"/documentation/static/*"
|
||||
];
|
||||
|
||||
export interface ZodTypeProvider extends FastifyTypeProvider {
|
||||
output: this["input"] extends ZodTypeAny ? z.infer<this["input"]> : never;
|
||||
}
|
||||
|
||||
interface Schema extends FastifySchema {
|
||||
hide?: boolean;
|
||||
}
|
||||
|
||||
const zodToJsonSchemaOptions = {
|
||||
target: "openApi3",
|
||||
$refStrategy: "none"
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function hasOwnProperty<T, K extends PropertyKey>(obj: T, prop: K): obj is T & Record<K, any> {
|
||||
return Object.prototype.hasOwnProperty.call(obj, prop);
|
||||
}
|
||||
|
||||
function resolveSchema(maybeSchema: ZodAny | { properties: ZodAny }): Pick<ZodAny, "safeParse"> {
|
||||
if (hasOwnProperty(maybeSchema, "safeParse")) {
|
||||
return maybeSchema;
|
||||
}
|
||||
if (hasOwnProperty(maybeSchema, "properties")) {
|
||||
return maybeSchema.properties;
|
||||
}
|
||||
throw new Error(`Invalid schema passed: ${JSON.stringify(maybeSchema)}`);
|
||||
}
|
||||
|
||||
export const createJsonSchemaTransform = ({ skipList }: { skipList: readonly string[] }) => {
|
||||
return ({ schema, url }: { schema: Schema; url: string }) => {
|
||||
if (!schema) {
|
||||
return {
|
||||
schema,
|
||||
url
|
||||
};
|
||||
}
|
||||
|
||||
const { response, headers, querystring, body, params, hide, ...rest } = schema;
|
||||
|
||||
const transformed: FreeformRecord = {};
|
||||
|
||||
if (skipList.includes(url) || hide) {
|
||||
transformed.hide = true;
|
||||
return { schema: transformed, url };
|
||||
}
|
||||
|
||||
const zodSchemas: FreeformRecord = { headers, querystring, body, params };
|
||||
|
||||
for (const prop in zodSchemas) {
|
||||
const zodSchema = zodSchemas[prop];
|
||||
if (zodSchema) {
|
||||
transformed[prop] = zodToJsonSchema(zodSchema, zodToJsonSchemaOptions);
|
||||
}
|
||||
}
|
||||
|
||||
if (response) {
|
||||
transformed.response = {};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
for (const prop in response as any) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const schema = resolveSchema((response as any)[prop]);
|
||||
|
||||
const transformedResponse = zodToJsonSchema(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
schema as any,
|
||||
zodToJsonSchemaOptions
|
||||
);
|
||||
transformed.response[prop] = transformedResponse;
|
||||
}
|
||||
}
|
||||
|
||||
for (const prop in rest) {
|
||||
const meta = rest[prop as keyof typeof rest];
|
||||
if (meta) {
|
||||
transformed[prop] = meta;
|
||||
}
|
||||
}
|
||||
|
||||
return { schema: transformed, url };
|
||||
};
|
||||
};
|
||||
|
||||
export const jsonSchemaTransform = createJsonSchemaTransform({
|
||||
skipList: defaultSkipList
|
||||
});
|
||||
|
||||
export const validatorCompiler: FastifySchemaCompiler<ZodAny> =
|
||||
({ schema }) =>
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(data): any => {
|
||||
try {
|
||||
return { value: schema.parse(data) };
|
||||
} catch (error) {
|
||||
return { error };
|
||||
}
|
||||
};
|
||||
|
||||
export class ResponseValidationError extends Error {
|
||||
public details: FreeformRecord;
|
||||
|
||||
constructor(validationResult: FreeformRecord) {
|
||||
super("Response doesn't match the schema");
|
||||
this.name = "ResponseValidationError";
|
||||
this.details = validationResult.error;
|
||||
}
|
||||
}
|
||||
|
||||
export const serializerCompiler: FastifySerializerCompiler<ZodAny | { properties: ZodAny }> =
|
||||
({ schema: maybeSchema }) =>
|
||||
(data) => {
|
||||
const schema: Pick<ZodAny, "safeParse"> = resolveSchema(maybeSchema);
|
||||
|
||||
const result = schema.safeParse(data);
|
||||
if (result.success) {
|
||||
return JSON.stringify(result.data);
|
||||
}
|
||||
|
||||
throw new ResponseValidationError(result);
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
import fp from "fastify-plugin";
|
||||
|
||||
/*! https://github.com/pbojinov/request-ip/blob/9501cdf6e73059cc70fc6890adb086348d7cca46/src/index.js.
|
||||
MIT License. 2022 Petar Bojinov - [email protected] */
|
||||
const headersOrder = [
|
||||
"x-client-ip", // Most common
|
||||
"x-forwarded-for", // Mostly used by proxies
|
||||
"cf-connecting-ip", // Cloudflare
|
||||
"Cf-Pseudo-IPv4", // Cloudflare
|
||||
"fastly-client-ip",
|
||||
"true-client-ip", // Akamai and Cloudflare
|
||||
"x-real-ip", // Nginx
|
||||
"x-cluser-client-ip", // Rackspace LB
|
||||
"forwarded-for",
|
||||
"x-forwarded",
|
||||
"forwarded",
|
||||
"x-appengine-user-ip" // GCP App Engine
|
||||
];
|
||||
|
||||
export const fastifyIp = fp(async (fastify) => {
|
||||
fastify.decorateRequest("realIp", null);
|
||||
fastify.addHook("onRequest", async (req) => {
|
||||
const forwardedIpHeader = headersOrder.find((header) => Boolean(req.headers[header]));
|
||||
const forwardedIp = forwardedIpHeader ? req.headers[forwardedIpHeader] : undefined;
|
||||
if (forwardedIp) {
|
||||
req.realIp = Array.isArray(forwardedIp) ? forwardedIp[0] : forwardedIp;
|
||||
} else {
|
||||
req.realIp = req.ip;
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,65 @@
|
||||
import { Probot } from "probot";
|
||||
import SmeeClient from "smee-client";
|
||||
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { logger } from "@app/lib/logger";
|
||||
|
||||
export const registerSecretScannerGhApp = async (server: FastifyZodProvider) => {
|
||||
const probotApp = (app: Probot) => {
|
||||
app.on("installation.deleted", async (context) => {
|
||||
const { payload } = context;
|
||||
const { installation, repositories } = payload;
|
||||
await server.services.secretScanning.handleRepoDeleteEvent(
|
||||
String(installation.id),
|
||||
(repositories || [])?.map(({ id }) => String(id))
|
||||
);
|
||||
});
|
||||
|
||||
app.on("installation", async (context) => {
|
||||
const { payload } = context;
|
||||
logger.info("Installed secret scanner to:", { repositories: payload.repositories });
|
||||
});
|
||||
|
||||
app.on("push", async (context) => {
|
||||
const { payload } = context;
|
||||
await server.services.secretScanning.handleRepoPushEvent(payload as any);
|
||||
});
|
||||
};
|
||||
|
||||
const appCfg = getConfig();
|
||||
if (appCfg.isSecretScanningConfigured) {
|
||||
const probot = new Probot({
|
||||
appId: appCfg.SECRET_SCANNING_GIT_APP_ID as string,
|
||||
privateKey: appCfg.SECRET_SCANNING_PRIVATE_KEY as string,
|
||||
secret: appCfg.SECRET_SCANNING_WEBHOOK_SECRET as string
|
||||
});
|
||||
|
||||
if (appCfg.NODE_ENV === "development") {
|
||||
const smee = new SmeeClient({
|
||||
source: appCfg.SECRET_SCANNING_WEBHOOK_PROXY as string,
|
||||
target: "http://backend:4000/ss-webhook",
|
||||
logger: console
|
||||
});
|
||||
smee.start();
|
||||
}
|
||||
|
||||
await probot.load(probotApp);
|
||||
|
||||
server.route({
|
||||
method: "POST",
|
||||
url: "/",
|
||||
handler: async (req, res) => {
|
||||
const eventName = req.headers["x-github-event"] as any;
|
||||
const signatureSHA256 = req.headers["x-hub-signature-256"] as string;
|
||||
const id = req.headers["x-github-delivery"] as string;
|
||||
await probot.webhooks.verifyAndReceive({
|
||||
id,
|
||||
name: eventName,
|
||||
payload: req.body as string,
|
||||
signature: signatureSHA256
|
||||
});
|
||||
res.send("ok");
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
import swagger from "@fastify/swagger";
|
||||
import swaggerUI from "@fastify/swagger-ui";
|
||||
import fp from "fastify-plugin";
|
||||
|
||||
import { jsonSchemaTransform } from "./fastify-zod";
|
||||
|
||||
export const fastifySwagger = fp(async (fastify) => {
|
||||
await fastify.register(swagger, {
|
||||
transform: jsonSchemaTransform,
|
||||
openapi: {
|
||||
info: {
|
||||
title: "Infisical API",
|
||||
description: "List of all available APIs that can be consumed",
|
||||
version: "0.0.1"
|
||||
},
|
||||
servers: [
|
||||
{
|
||||
url: "http://localhost:8080",
|
||||
description: "Local server"
|
||||
},
|
||||
{
|
||||
url: "https://app.infisical.com",
|
||||
description: "Production server"
|
||||
}
|
||||
],
|
||||
components: {
|
||||
securitySchemes: {
|
||||
bearer: {
|
||||
type: "http",
|
||||
scheme: "bearer",
|
||||
bearerFormat: "JWT",
|
||||
description: "A service token in Infisical"
|
||||
},
|
||||
apiKey: {
|
||||
type: "apiKey",
|
||||
in: "header",
|
||||
name: "X-API-Key",
|
||||
description: "An API Key in Infisical"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await fastify.register(swaggerUI, {
|
||||
routePrefix: "/docs"
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user