@aimee-blue/ab-service-kit
Version:
Aimee Blue Service Template
1 lines • 9.29 kB
Source Map (JSON)
{"version":3,"sources":["../../../src/shared/auth/epicWithAuth.ts"],"names":["defaultDeps","verifyToken","args","decodeJwt","firstMessageShouldBeAuth","commands","pipe","msg","type","Auth","AUTH","Error","VERIFY_TOKEN_REQUEST_SUCCESS_PREFIX","verifyTokensUsingAuthMessage","allow","deps","auth","token","payload","result","decoded","status","VerifyError","message","epicWithAuth","epic","authForEpic","Utils","setFunctionName","name","cmd","ctx","rest","Observable","subscriber","authOp","authSuccessOrEmpty","authFailed","err","error","Errors","ensureError","isConsole","isHil","logger","log","appError","Apps","ERROR","buffered","add","subscribe","connect"],"mappings":"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","sourcesContent":["import {\n take,\n concatMap,\n catchError,\n switchMap,\n ignoreElements,\n map,\n withLatestFrom,\n buffer,\n skip,\n} from 'rxjs/operators';\nimport {\n Observable,\n from,\n of,\n merge,\n empty,\n concat,\n ObservedValueOf,\n} from 'rxjs';\nimport { Auth, Apps } from '@aimee-blue/ab-contracts';\nimport { IJwt, decodeJwt } from '@aimee-blue/ab-auth';\n\nimport { ISocketEpicAttributes, ISocketEpicContext } from '../kit';\nimport { ofType } from '../ofType';\nimport { verifyToken } from './verifyToken';\nimport { IAction } from '../action';\nimport { publishStream } from '../publishStream';\nimport { Utils, Errors } from '@aimee-blue/ab-shared';\nimport { VerifyError } from './verifyError';\nimport { registerError } from '../registerError';\n\nexport interface IInjectedAuthDetails {\n id: string;\n auth?: IJwt;\n}\n\nexport interface ISocketEpicWithAuth<\n I extends IAction = IAction,\n O extends IAction | Buffer = IAction | Buffer,\n D = {},\n R extends unknown[] = unknown[]\n> extends ISocketEpicAttributes<O, D> {\n (\n commands: Observable<IAction | I>,\n ctx: ISocketEpicContext & IInjectedAuthDetails & D,\n ...rest: R\n ): Observable<O>;\n}\n\nconst defaultDeps = {\n verifyToken: (...args: Parameters<typeof verifyToken>) =>\n from(verifyToken(...args)),\n decodeJwt,\n};\n\nfunction firstMessageShouldBeAuth() {\n return (commands: Observable<IAction>) =>\n commands.pipe(\n take(1),\n map((msg: IAction) => {\n if (msg.type !== Auth.AUTH) {\n throw new Error('No token received');\n }\n return msg;\n }),\n ofType<Auth.IAuthAction>(Auth.AUTH)\n );\n}\n\nconst VERIFY_TOKEN_REQUEST_SUCCESS_PREFIX =\n 'verifyAuth succeeded with non-ok status';\n\nfunction verifyTokensUsingAuthMessage(\n allow: Auth.Role[],\n deps: typeof defaultDeps\n) {\n return (commands: Observable<Auth.IAuthAction>) =>\n commands.pipe(\n concatMap(auth =>\n deps\n .verifyToken({\n token: auth.payload.token,\n allow,\n })\n .pipe(\n switchMap(result => {\n const decoded = deps.decodeJwt(auth.payload.token);\n if (\n typeof result === 'object' &&\n result !== null &&\n result.status === 200\n ) {\n return of(decoded.payload);\n } else {\n throw new VerifyError(\n `${VERIFY_TOKEN_REQUEST_SUCCESS_PREFIX} ${result.status} - ${result.message}`,\n decoded\n );\n }\n })\n )\n )\n );\n}\n\nexport function epicWithAuth<E extends ISocketEpicWithAuth>(\n allow: Auth.Role[],\n epic: E,\n deps = defaultDeps\n) {\n const authForEpic = Utils.setFunctionName(\n `withAuth.${epic.name}`,\n (...[cmd, ctx, ...rest]: Parameters<E>) => {\n return new Observable<Apps.IErrorAction | ObservedValueOf<ReturnType<E>>>(\n subscriber => {\n const commands = publishStream(cmd);\n const authOp = publishStream(\n commands.pipe(\n firstMessageShouldBeAuth(),\n verifyTokensUsingAuthMessage(allow, deps)\n )\n );\n\n const authSuccessOrEmpty = authOp.pipe(catchError(() => empty()));\n\n const authFailed = authOp.pipe(\n ignoreElements(),\n catchError(err => {\n const error = Errors.ensureError(err);\n if (error instanceof VerifyError) {\n const payload = error.token?.payload as\n | {\n isConsole?: boolean;\n isHil?: boolean;\n }\n | undefined;\n if (payload && payload.isConsole && !payload.isHil) {\n registerError(error);\n ctx.logger.error(\n '💥 Console user authentication failed: ',\n error\n );\n } else {\n // probably just a sleeping HIL tab:\n ctx.logger.log(error.message);\n }\n } else {\n ctx.logger.error('💥 Verify token request failed: ', error);\n }\n\n const appError: Apps.IErrorAction = {\n type: Apps.ERROR,\n payload: {\n status: 'UNAUTHENTICATED',\n message: 'Unauthenticated',\n },\n };\n\n return of(appError);\n })\n );\n\n const result = merge(\n authFailed,\n authSuccessOrEmpty.pipe(\n // buffer commands while authOp is in progress:\n withLatestFrom(\n commands.pipe(\n skip(1),\n buffer(authSuccessOrEmpty.pipe(take(1))),\n take(1)\n )\n ),\n switchMap(([auth, buffered]) => {\n ctx.auth = auth;\n return epic(\n concat(from(buffered), commands),\n ctx,\n ...rest\n ) as ReturnType<E>;\n })\n )\n );\n\n subscriber.add(result.subscribe(subscriber));\n subscriber.add(authOp.connect());\n subscriber.add(commands.connect());\n }\n );\n }\n );\n\n return authForEpic;\n}\n"],"file":"epicWithAuth.js"}