import {route, Route, Routes} from "../routes"; import {WithSecurity} from "./withSecurity"; import {BaseRequestLens, RequestLens, RoutingResult} from "../lenses"; import {isFailure, success} from "@http4t/result"; import {HttpRequest} from "@http4t/core/contract"; export type SecuredRoute = Route, any>; export type SecuredRoutes = { [K in keyof TRoutes]: SecuredRoute } export class WithSecurityLens extends BaseRequestLens> { constructor(private readonly unsecuredLens: RequestLens, private readonly tokenLens: RequestLens) { super(); } async get(from: HttpRequest): Promise>> { const routeResult = await this.unsecuredLens.get(from); if (isFailure(routeResult)) return routeResult; const claimsResult = await this.tokenLens.get(from); if (isFailure(claimsResult)) return claimsResult; return success({ security: claimsResult.value, value: routeResult.value }); } async setRequest(into: HttpRequest, value: WithSecurity): Promise { const withToken = await this.tokenLens.set(into, value.security); return this.unsecuredLens.set(withToken, value.value) } } export function securedRoute( unsecuredRoute: TRoute, tokenLens: RequestLens) : SecuredRoute { return route( new WithSecurityLens(unsecuredRoute.request, tokenLens), unsecuredRoute.response as any // ); } export function securedRoutes( unsecuredRoutes: TRoutes, tokenLens: RequestLens) : SecuredRoutes { return Object.entries(unsecuredRoutes) .reduce( (routes, [k, route]) => { routes[k as keyof TRoutes] = securedRoute( route as Route, tokenLens); return routes; }, {} as SecuredRoutes); }