UNPKG

minauth

Version:

A TypeScript library for building authentication systems on top of the Mina blockchain and other zero-knowledge proofs solutions.

69 lines 4.04 kB
import bodyParser from 'body-parser'; import * as RTE from 'fp-ts/lib/ReaderTaskEither.js'; import * as TE from 'fp-ts/lib/TaskEither.js'; import { pipe } from 'fp-ts/lib/function.js'; import { z } from 'zod'; import { wrapTrivialExpressHandler } from '../../plugin/express.js'; import { installCustomRoutes, validateOutput, verifyProof } from '../../server/plugin-fp-api.js'; import { askActivePluginNames } from '../../server/pluginruntime.js'; import { launchTE, liftZodParseResult } from '../../utils/fp/taskeither.js'; import { askConfig, askPluginRuntimeEnv, askRootLogger, liftPluginRuntime, useExpressApp, useRootLogger, withExpressApp } from './types.js'; import { MinAuthPluginInputSchema } from '../../common/proof.js'; /** Handle a POST request to /verifyProof */ const handleVerifyProof = (env) => wrapTrivialExpressHandler((req) => { const parseResults = MinAuthPluginInputSchema.safeParse(req.body); if (!parseResults.success) { env.logger.info(`Failed to parse incoming MinAuthProof:\b ${parseResults.error}`); return TE.left('Failed to parse incoming MinAuthProof'); } const body = parseResults.data; env.logger.info(`Parsed incoming MinAuthProof with body:\b ${JSON.stringify(body, null, 2)}`); return pipe(verifyProof(body.input, body.plugin)(env), TE.map((output) => { return { output }; }), TE.mapLeft(() => 'unknown error')); }); const validateOutputDataSchema = z.object({ plugin: z.string(), output: z.unknown() }); /** Handle a GET request to /activePlugins */ const handleActivePlugins = (env) => wrapTrivialExpressHandler(() => { return askActivePluginNames()(env); }); /** Handle a POST request to /validateOutput */ const handleValidateOutput = (env) => async (req, resp) => launchTE(pipe(liftZodParseResult(validateOutputDataSchema.safeParse(req.body)), TE.tapIO((body) => () => env.logger.info(`parsed body: ${JSON.stringify(body, null, 2)}`)), TE.chain((body) => validateOutput(body.plugin, body.output)(env)), TE.tapIO((val) => () => val.isValid ? resp.status(200).json({}) : resp.status(400).json({ message: val.reason })), TE.asUnit)); /** * Install the basic routes for the plugin server: * - POST /verifyProof * - POST /validateOutput * - GET /health */ const installBasicRoutes = () => pipe(askPluginRuntimeEnv(), RTE.chain((env) => useExpressApp((app) => app .use(bodyParser.json()) .post('/verifyProof', handleVerifyProof(env)) .post('/validateOutput', handleValidateOutput(env)) .get('/plugins/activePlugins', handleActivePlugins(env)) .get('/health', (_, resp) => resp.status(200).json({}))))); /** * If a request is not handled by any of the routes above, * Return a 404 error and 500 if an error occurs. */ const installFallbackHandlers = () => pipe(askRootLogger(), RTE.chain((logger) => useExpressApp((app) => app .all('*', (_, resp) => resp.status(404).json({ error: 'bad route' })) .use((err, _req, resp) => { logger.error('encountered unhandled express error', err); resp.status(500).json({ error: 'internal server error' }); })))); /** * Plugins can define their own routes to communicate with provers. */ const installPluginCustomRoutes = () => pipe(useRootLogger((logger) => logger.info('installing custom routes for plugins')), RTE.chain(() => withExpressApp((app) => liftPluginRuntime(installCustomRoutes(app))))); export const setupAllRoutes = () => pipe(useExpressApp((app) => app.use(bodyParser.json())), RTE.chain(installPluginCustomRoutes), RTE.chain(installBasicRoutes), RTE.chain(installFallbackHandlers), RTE.asUnit); /** * Calls app.listen() to start serving the plugin server * the configuration is read from the plugin server environment */ export const startServing = () => pipe(RTE.Do, RTE.bind('logger', askRootLogger), RTE.bind('cfg', askConfig), RTE.chain(({ logger, cfg }) => useExpressApp((app) => app.listen(cfg.port, cfg.address, () => logger.info(`server is running on http://${cfg.address}:${cfg.port}`))))); //# sourceMappingURL=express.js.map