import { LocalGitRepoState } from "@superblocksteam/util"; import { ApiToSign, ApiToVerify, AppToSign, AppToVerify, MethodHandlers, RemoteCommitDto, Signature, ViewMode, } from "../types"; import { signResource, verifyResources } from "./signing"; type MethodSchema = (params: Params) => Promise; export interface ClientMethods { v1: { signing: { signApplication: MethodSchema< { branchName: string; toSign: AppToSign }, { signature: Signature } >; signApis: MethodSchema< { branchName: string; toSign: ApiToSign[] }, { signatures: Signature[] } >; verifyApplication: MethodSchema< { branchName: string; toVerify: AppToVerify }, { ok: boolean } >; verifyApi: MethodSchema< { branchName: string; toVerify: ApiToVerify[] }, { ok: boolean } >; }; }; } type ServerMethodSchema = MethodSchema< Params, ResponseDto >; // This file contains the definition of the protocol used for communication between the SB server and clients type ResponseDto = { responseMeta: ResponseMeta; data: T; }; export type ResponseMeta = { status: number; success: boolean; message?: string; error?: APIResponseError; }; type APIResponseError = { code: number; message: string; }; export interface ServerMethods { v1: { echo: MethodSchema<{ message: string }, { message: string }>; public: { application: { component: { register: ServerMethodSchema< { applicationId: string; branchName: string; cliVersion: string; componentEvent: string; components: Record; }, { success: boolean } >; update: ServerMethodSchema< { applicationId: string; branchName?: string; srcFiles: string[]; buildFiles: string[]; registeredComponents: Record; cliVersion: string | undefined; componentBaseUrl: string; signingRequired: boolean; }, { success: boolean } >; }; pushCommit: ServerMethodSchema< { applicationId: string; branchName: string; commitId: string; commitMessage: string; application: Record; page: Record; apis: Record[]; gitState: LocalGitRepoState; }, RemoteCommitDto >; }; api: { pushCommit: ServerMethodSchema< { apiId: string; branchName: string; commitId?: string; commitMessage?: string; apiPb: Record; gitState: LocalGitRepoState; skipCommit: boolean; }, RemoteCommitDto | { updated: Date } >; get: ServerMethodSchema< { apiId: string; branchName?: string; viewMode: ViewMode; commitId?: string; }, any >; }; }; }; v2: { public: { application: { pushCommit: ServerMethodSchema< { applicationId: string; branchName: string; commitId?: string; commitMessage?: string; application: Record; pages: Record[]; apis: Record[]; gitState: LocalGitRepoState; skipCommit: boolean; }, RemoteCommitDto | { updated: Date } >; get: ServerMethodSchema< { applicationId: string; viewMode: ViewMode; branchName?: string; commitId?: string; }, any >; }; }; }; } export function createRequestHandlers({ agentUrl, token, }: { token: string; agentUrl?: string; }) { const requestHandlers: MethodHandlers = { v1: { signing: { signApplication: [ async ({ branchName, toSign, }: { branchName: string; toSign: AppToSign; }) => { if (!agentUrl) { throw new Error( "Agent url not specified. This shouldn't happen.", ); } const signature = await signResource({ agentUrl, token: token, branchName, resource: { literal: { data: toSign.rootHash, }, }, }); return { signature: signature }; }, ], signApis: [ async ({ branchName, toSign, }: { branchName: string; toSign: ApiToSign[]; }) => { const signatures: Signature[] = []; for (const { apiPb } of toSign) { if (!agentUrl) { throw new Error( "Agent url not specified. This shouldn't happen.", ); } const signature = await signResource({ agentUrl, token: token, branchName, resource: { api: apiPb }, }); signatures.push(signature); } return { signatures }; }, ], verifyApplication: [ async ({ branchName, toVerify, }: { branchName: string; toVerify: AppToVerify; }) => { try { if (!agentUrl) { throw new Error( "Agent url not specified. This shouldn't happen.", ); } await verifyResources({ agentUrl, token, branchName, resources: [ { literal: { data: toVerify.rootHash, signature: toVerify.signature, }, }, ], }); return { ok: true }; } catch { return { ok: false }; } }, ], verifyApi: [ async ({ branchName, toVerify, }: { branchName: string; toVerify: ApiToVerify[]; }) => { try { if (!agentUrl) { throw new Error( "Agent url not specified. This shouldn't happen.", ); } await verifyResources({ agentUrl, token, branchName, resources: toVerify.map(({ apiPb }) => ({ api: apiPb, })), }); return { ok: true }; } catch { return { ok: false }; } }, ], }, }, }; return requestHandlers; }