Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: consume swagger api with CSRF #156

Merged
merged 1 commit into from
May 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions api/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
15 changes: 15 additions & 0 deletions api/public/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
26 changes: 26 additions & 0 deletions api/src/controllers/web.ts
Original file line number Diff line number Diff line change
@@ -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
*
Expand All @@ -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
Expand Down
12 changes: 11 additions & 1 deletion api/src/routes/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

request intercepter for swagger to attach CSRF token in request.headers

}
})
)
Expand Down
19 changes: 5 additions & 14 deletions api/src/routes/web/web.ts
Original file line number Diff line number Diff line change
@@ -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')
}
Expand All @@ -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)
Expand All @@ -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())
}
Expand Down