Skip to content

Commit

Permalink
Merge pull request #248 from sasjs/cookies-management
Browse files Browse the repository at this point in the history
fix(cookie): XSRF cookie is removed and passed token in head section
  • Loading branch information
allanbowe authored Aug 4, 2022
2 parents 78bea7c + f7fcc77 commit 3671736
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 19 deletions.
5 changes: 3 additions & 2 deletions api/src/app.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import path from 'path'
import express, { ErrorRequestHandler } from 'express'
import csrf from 'csurf'
import csrf, { CookieOptions } from 'csurf'
import cookieParser from 'cookie-parser'
import dotenv from 'dotenv'

Expand Down Expand Up @@ -32,9 +32,10 @@ const app = express()

const { PROTOCOL } = process.env

export const cookieOptions = {
export const cookieOptions: CookieOptions = {
secure: PROTOCOL === ProtocolType.HTTPS,
httpOnly: true,
sameSite: PROTOCOL === ProtocolType.HTTPS ? 'none' : undefined,
maxAge: 24 * 60 * 60 * 1000 // 24 hours
}

Expand Down
23 changes: 11 additions & 12 deletions api/src/routes/api/spec/web.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,11 @@ describe('web', () => {

describe('home', () => {
it('should respond with CSRF Token', async () => {
await request(app)
.get('/')
.expect(
'set-cookie',
/_csrf=.*; Max-Age=86400000; Path=\/; HttpOnly,XSRF-TOKEN=.*; Path=\//
)
const res = await request(app).get('/').expect(200)

expect(res.text).toMatch(
/<script>document.cookie = '(XSRF-TOKEN=.*; Max-Age=86400; SameSite=Strict; Path=\/;)'<\/script>/
)
})
})

Expand Down Expand Up @@ -154,10 +153,10 @@ describe('web', () => {

const getCSRF = async (app: Express) => {
// make request to get CSRF
const { header } = await request(app).get('/')
const { header, text } = await request(app).get('/')
const cookies = header['set-cookie'].join()

const csrfToken = extractCSRF(cookies)
const csrfToken = extractCSRF(text)
return { csrfToken, cookies }
}

Expand All @@ -177,7 +176,7 @@ const performLogin = async (
return { cookies: newCookies }
}

const extractCSRF = (cookies: string) =>
/_csrf=(.*); Max-Age=86400000; Path=\/; HttpOnly,XSRF-TOKEN=(.*); Path=\//.exec(
cookies
)![2]
const extractCSRF = (text: string) =>
/<script>document.cookie = 'XSRF-TOKEN=(.*); Max-Age=86400; SameSite=Strict; Path=\/;'<\/script>/.exec(
text
)![1]
1 change: 1 addition & 0 deletions api/src/routes/appStream/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const style = `<style>
}
.app-container .app img{
width: 100%;
height: calc(100% - 30px);
margin-bottom: 10px;
border-radius: 10px;
}
Expand Down
10 changes: 7 additions & 3 deletions api/src/routes/web/web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@ webRouter.get('/', async (req, res) => {
try {
response = await controller.home()
} catch (_) {
response = 'Web Build is not present'
response = '<html><head></head><body>Web Build is not present</body></html>'
} finally {
res.cookie('XSRF-TOKEN', req.csrfToken())
const codeToInject = `<script>document.cookie = 'XSRF-TOKEN=${req.csrfToken()}; Max-Age=86400; SameSite=Strict; Path=/;'</script>`
const injectedContent = response?.replace(
'</head>',
`${codeToInject}</head>`
)

return res.send(response)
return res.send(injectedContent)
}
})

Expand Down
19 changes: 19 additions & 0 deletions api/src/utils/verifyEnvVariables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,27 @@ const verifyCORS = (): string[] => {

if (CORS) {
const corsTypes = Object.values(CorsType)

if (!corsTypes.includes(CORS as CorsType))
errors.push(`- CORS '${CORS}'\n - valid options ${corsTypes}`)

if (CORS === CorsType.ENABLED) {
const { WHITELIST } = process.env

const urls = WHITELIST?.trim()
.split(' ')
.filter((url) => !!url)
if (urls?.length) {
urls.forEach((url) => {
if (!url.startsWith('http://') && !url.startsWith('https://'))
errors.push(
`- CORS '${CORS}'\n - provided WHITELIST ${url} is not valid`
)
})
} else {
errors.push(`- CORS '${CORS}'\n - provide at least one WHITELIST URL`)
}
}
} else {
const { MODE } = process.env
process.env.CORS =
Expand Down
2 changes: 1 addition & 1 deletion web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function App() {
<HashRouter>
<Header />
<Routes>
<Route path="/" element={<Login />} />
<Route path="*" element={<Login />} />
</Routes>
</HashRouter>
</ThemeProvider>
Expand Down
13 changes: 12 additions & 1 deletion web/src/context/appContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,18 @@ const AppContextProvider = (props: { children: ReactNode }) => {
})
.catch(() => {
setLoggedIn(false)
axios.get('/') // get CSRF TOKEN
// get CSRF TOKEN and set cookie
axios
.get('/')
.then((res) => res.data)
.then((data: string) => {
const result =
/<script>document.cookie = '(XSRF-TOKEN=.*; Max-Age=86400; SameSite=Strict; Path=\/;)'<\/script>/.exec(
data
)?.[1]

if (result) document.cookie = result
})
})

axios
Expand Down

0 comments on commit 3671736

Please sign in to comment.