From 5aaac24080362d6ce0c5d1157798a9343f40ae2a Mon Sep 17 00:00:00 2001 From: Saad Jutt Date: Sun, 1 May 2022 06:07:17 +0500 Subject: [PATCH] fix: consume swagger api with CSRF --- api/package-lock.json | 18 +++++++++--------- api/package.json | 2 +- api/public/swagger.yaml | 15 +++++++++++++++ api/src/controllers/web.ts | 26 ++++++++++++++++++++++++++ api/src/routes/api/index.ts | 12 +++++++++++- api/src/routes/web/web.ts | 19 +++++-------------- 6 files changed, 67 insertions(+), 25 deletions(-) diff --git a/api/package-lock.json b/api/package-lock.json index bb2bb39..f925f4b 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -24,7 +24,7 @@ "mongoose-sequence": "^5.3.1", "morgan": "^1.10.0", "multer": "^1.4.3", - "swagger-ui-express": "^4.1.6" + "swagger-ui-express": "4.3.0" }, "bin": { "api": "build/src/server.js" @@ -9434,11 +9434,11 @@ "integrity": "sha512-WvfPSfAAMlE/sKS6YkW47nX/hA7StmhYnAHc6wWCXNL0oclwLj6UXv0hQCkLnDgvebi0MEV40SJJpVjKUgH1IQ==" }, "node_modules/swagger-ui-express": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.2.0.tgz", - "integrity": "sha512-znrHTwh9UpvsjqgWopA4noIet7mi7UGuIYZ465YfUDKQ5Dpas0jxnkfUKCo+0aB17YCBv26AhIjiQYDV4uvJFA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.3.0.tgz", + "integrity": "sha512-jN46SEEe9EoXa3ZgZoKgnSF6z0w3tnM1yqhO4Y+Q4iZVc8JOQB960EZpIAz6rNROrDApVDwcMHR0mhlnc/5Omw==", "dependencies": { - "swagger-ui-dist": ">3.52.5" + "swagger-ui-dist": ">=4.1.3" }, "engines": { "node": ">= v0.10.32" @@ -17601,11 +17601,11 @@ "integrity": "sha512-WvfPSfAAMlE/sKS6YkW47nX/hA7StmhYnAHc6wWCXNL0oclwLj6UXv0hQCkLnDgvebi0MEV40SJJpVjKUgH1IQ==" }, "swagger-ui-express": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.2.0.tgz", - "integrity": "sha512-znrHTwh9UpvsjqgWopA4noIet7mi7UGuIYZ465YfUDKQ5Dpas0jxnkfUKCo+0aB17YCBv26AhIjiQYDV4uvJFA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.3.0.tgz", + "integrity": "sha512-jN46SEEe9EoXa3ZgZoKgnSF6z0w3tnM1yqhO4Y+Q4iZVc8JOQB960EZpIAz6rNROrDApVDwcMHR0mhlnc/5Omw==", "requires": { - "swagger-ui-dist": ">3.52.5" + "swagger-ui-dist": ">=4.1.3" } }, "symbol-tree": { diff --git a/api/package.json b/api/package.json index 2657b7e..bc78d95 100644 --- a/api/package.json +++ b/api/package.json @@ -63,7 +63,7 @@ "mongoose-sequence": "^5.3.1", "morgan": "^1.10.0", "multer": "^1.4.3", - "swagger-ui-express": "^4.1.6" + "swagger-ui-express": "4.3.0" }, "devDependencies": { "@types/bcryptjs": "^2.4.2", diff --git a/api/public/swagger.yaml b/api/public/swagger.yaml index 0cee9b9..ed3b794 100644 --- a/api/public/swagger.yaml +++ b/api/public/swagger.yaml @@ -465,6 +465,21 @@ info: name: '4GL Ltd' openapi: 3.0.0 paths: + /: + get: + operationId: Home + responses: + '200': + description: Ok + content: + application/json: + schema: + type: string + summary: 'Render index.html' + tags: + - Web + security: [] + parameters: [] /login: post: operationId: Login diff --git a/api/src/controllers/web.ts b/api/src/controllers/web.ts index 605d8e8..d11ecad 100644 --- a/api/src/controllers/web.ts +++ b/api/src/controllers/web.ts @@ -1,10 +1,23 @@ +import path from 'path' import express from 'express' import { Request, Route, Tags, Post, Body, Get } from 'tsoa' +import { readFile } from '@sasjs/utils' + import User from '../model/User' +import { getWebBuildFolderPath } from '../utils' @Route('/') @Tags('Web') export class WebController { + /** + * @summary Render index.html + * + */ + @Get('/') + public async home(@Request() req: express.Request) { + return home(req) + } + /** * @summary Accept a valid username/password * @@ -31,6 +44,19 @@ export class WebController { } } +const home = async (req: express.Request) => { + const indexHtmlPath = path.join(getWebBuildFolderPath(), 'index.html') + + // Attention! Cannot use fileExists here, + // due to limitation after building executable + const content = await readFile(indexHtmlPath) + + req.res?.cookie('XSRF-TOKEN', req.csrfToken()) + req.res?.setHeader('Content-Type', 'text/html') + + return content +} + const login = async ( req: express.Request, { username, password }: LoginPayload diff --git a/api/src/routes/api/index.ts b/api/src/routes/api/index.ts index 7b249a9..cfe44ce 100644 --- a/api/src/routes/api/index.ts +++ b/api/src/routes/api/index.ts @@ -36,12 +36,22 @@ router.use('/group', desktopRestrict, groupRouter) router.use('/stp', authenticateAccessToken, stpRouter) router.use('/code', authenticateAccessToken, codeRouter) router.use('/user', desktopRestrict, userRouter) + router.use( '/', swaggerUi.serve, swaggerUi.setup(undefined, { swaggerOptions: { - url: '/swagger.yaml' + url: '/swagger.yaml', + requestInterceptor: (request: any) => { + request.credentials = 'include' + + const cookie = document.cookie + const startIndex = cookie.indexOf('XSRF-TOKEN') + const csrf = cookie.slice(startIndex + 11).split('; ')[0] + request.headers['X-XSRF-TOKEN'] = csrf + return request + } } }) ) diff --git a/api/src/routes/web/web.ts b/api/src/routes/web/web.ts index 289c02b..6a86829 100644 --- a/api/src/routes/web/web.ts +++ b/api/src/routes/web/web.ts @@ -1,21 +1,14 @@ -import path from 'path' import express from 'express' -import { readFile } from '@sasjs/utils' import { WebController } from '../../controllers/web' -import { getWebBuildFolderPath, loginWebValidation } from '../../utils' +import { loginWebValidation } from '../../utils' const webRouter = express.Router() +const controller = new WebController() webRouter.get('/', async (req, res) => { - const indexHtmlPath = path.join(getWebBuildFolderPath(), 'index.html') - try { - // Attention! Cannot use fileExists here, due to limitation after building executable - const content = await readFile(indexHtmlPath) - - res.cookie('XSRF-TOKEN', req.csrfToken()) - res.setHeader('Content-Type', 'text/html') - return res.send(content) + const response = await controller.home(req) + return res.send(response) } catch (_) { return res.send('Web Build is not present') } @@ -25,7 +18,6 @@ webRouter.post('/login', async (req, res) => { const { error, value: body } = loginWebValidation(req.body) if (error) return res.status(400).send(error.details[0].message) - const controller = new WebController() try { const response = await controller.login(req, body) res.send(response) @@ -35,10 +27,9 @@ webRouter.post('/login', async (req, res) => { }) webRouter.get('/logout', async (req, res) => { - const controller = new WebController() try { await controller.logout(req) - res.status(200).send() + res.status(200).send('OK!') } catch (err: any) { res.status(400).send(err.toString()) }