Skip to content

Commit

Permalink
feat: change create session from middleware to function
Browse files Browse the repository at this point in the history
  • Loading branch information
jukerah committed Apr 30, 2024
1 parent d57ddd4 commit 14c6ca1
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 165 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# VkrunJS Releases

## Next version
## 0.35.0

- change create session from middleware to function
- fix export types jwt module
- create mapping from http status code

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "vkrun",
"version": "0.34.3",
"version": "0.35.0",
"description": "Vkrun is a Node.js framework for building server-side applications",
"author": "Mario Elvio",
"license": "MIT",
Expand Down
171 changes: 98 additions & 73 deletions src/modules/session/__tests__/index-e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,29 @@ import { generateSecretKey } from '../helpers'

const secretKey = generateSecretKey()
const session = v.Session({ secretKey, sanitizationEvery: '5m' })
const router = v.Router()

class ExampleController implements v.Controller {
public handle (request: v.Request, response: v.Response): any {
const userData = { userId: 123, email: 'any@mail.com' }
const config = { expiresIn: '15m' }
session.create(request, response, userData, config)
response.status(200).json({ session: request.session })
}
}

router.post('/session',
session.create({ userId: 123, email: 'any@mail.com' }, { expiresIn: '15m' }),
v.controllerAdapter(new ExampleController())
)

const router = v.Router()
router.post('/session', v.controllerAdapter(new ExampleController()))
router.post('/protect', session.protect(), v.controllerAdapter(new ExampleController()))

describe('Session', () => {
let cookie: string
let sessionId: string
let sessionToken: string

const getCookies = (response: any): void => {
const getCookies = (response: any): {
cookie: string
sessionId: string
sessionToken: string
} => {
const setCookie = response.headers['set-cookie']
let sessionId = ''
let sessionToken = ''

setCookie.forEach((cookie: string) => {
if (cookie.startsWith('session-id=')) {
Expand All @@ -33,13 +34,21 @@ describe('Session', () => {
sessionToken = cookie.split('=')[1].split(';')[0]
}
})
cookie = `session-id=${sessionId};session-token=${sessionToken}`

const cookie: string = `session-id=${sessionId};session-token=${sessionToken}`

return { cookie, sessionId, sessionToken }
}

const validateSessionSuccess = (response: any): void => {
const validateSessionSuccess = (
response: any,
sessionId: string,
sessionToken: string
): void => {
expect(response.statusCode).toEqual(200)
expect(response.statusMessage).toEqual('OK')
expect(Object.keys(response.headers).length).toEqual(10)
expect(v.isUUID(response.headers['request-id'])).toBeTruthy()
expect(response.headers['content-security-policy']).toEqual("default-src 'self'; script-src 'self' 'unsafe-inline'")
expect(response.headers['cache-control']).toEqual('no-store, no-cache, must-revalidate')
expect(response.headers.expires).toEqual('0')
Expand Down Expand Up @@ -83,9 +92,16 @@ describe('Session', () => {
const validateProtectSuccess = (response: any): void => {
expect(response.statusCode).toEqual(200)
expect(response.statusMessage).toEqual('OK')
expect(Object.keys(response.headers).length).toEqual(5)
expect(Object.keys(response.headers).length).toEqual(10)
expect(v.isUUID(response.headers['request-id'])).toBeTruthy()
expect(response.headers['content-type']).toEqual('application/json')
expect(response.headers['content-security-policy']).toEqual("default-src 'self'; script-src 'self' 'unsafe-inline'")
expect(response.headers['cache-control']).toEqual('no-store, no-cache, must-revalidate')
expect(response.headers['x-xss-protection']).toEqual('1; mode=block')
const arrCookies = response.headers['set-cookie'] as string[]
expect(arrCookies.length).toEqual(2)
expect(arrCookies[0].startsWith('session-id=')).toBeTruthy()
expect(arrCookies[1].startsWith('session-token=')).toBeTruthy()
expect(v.isString(response.headers.date)).toBeTruthy()
expect(response.headers.connection).toEqual('close')
expect(response.headers['content-length']).toEqual('49')
Expand All @@ -99,20 +115,28 @@ describe('Session', () => {
app.use(router)

await v.superRequest(app).post('/session').then((response) => {
getCookies(response)
validateSessionSuccess(response)
const { sessionId, sessionToken } = getCookies(response)
validateSessionSuccess(response, sessionId, sessionToken)
})

app.close()
})

it('throw new Error when secret key is invalid', async () => {
try {
const router = v.Router()
const session = v.Session({ secretKey: '123' })
router.post('/session',
session.create({ userId: 123, email: 'any@mail.com' }, { expiresIn: '15m' })
)

class ExampleController implements v.Controller {
public handle (request: v.Request, response: v.Response): any {
const userData = { userId: 123, email: 'any@mail.com' }
const config = { expiresIn: '15m' }
session.create(request, response, userData, config)
response.status(200).json({ session: request.session })
}
}

const router = v.Router()
router.post('/session', v.controllerAdapter(new ExampleController()))
} catch (error: any) {
expect(error.message).toEqual('vkrun-session: the secret keys must be strings of 64 characters representing 32 bytes.')
}
Expand All @@ -122,9 +146,12 @@ describe('Session', () => {
const app = v.App()
app.use(router)

let cookie = ''

await v.superRequest(app).post('/session').then((response) => {
getCookies(response)
validateSessionSuccess(response)
const { cookie: _cookie, sessionId, sessionToken } = getCookies(response)
validateSessionSuccess(response, sessionId, sessionToken)
cookie = _cookie
})

await v.superRequest(app).post('/protect', {}, {
Expand All @@ -140,9 +167,12 @@ describe('Session', () => {
const app = v.App()
app.use(router)

let sessionId = ''

await v.superRequest(app).post('/session').then((response) => {
getCookies(response)
validateSessionSuccess(response)
const { sessionId: _sessionId, sessionToken } = getCookies(response)
validateSessionSuccess(response, _sessionId, sessionToken)
sessionId = _sessionId
})

await v.superRequest(app).post('/protect', {}, {
Expand All @@ -158,9 +188,12 @@ describe('Session', () => {
const app = v.App()
app.use(router)

let sessionToken = ''

await v.superRequest(app).post('/session').then((response) => {
getCookies(response)
validateSessionSuccess(response)
const { sessionId, sessionToken: _sessionToken } = getCookies(response)
validateSessionSuccess(response, sessionId, _sessionToken)
sessionToken = _sessionToken
})

await v.superRequest(app).post('/protect', {}, {
Expand All @@ -176,9 +209,12 @@ describe('Session', () => {
const app = v.App()
app.use(router)

let sessionToken = ''

await v.superRequest(app).post('/session').then((response) => {
getCookies(response)
validateSessionSuccess(response)
const { sessionId, sessionToken: _sessionToken } = getCookies(response)
validateSessionSuccess(response, sessionId, _sessionToken)
sessionToken = _sessionToken
})

await v.superRequest(app).post('/protect', {}, {
Expand Down Expand Up @@ -207,9 +243,12 @@ describe('Session', () => {
const app = v.App()
app.use(router)

let sessionId = ''

await v.superRequest(app).post('/session').then((response) => {
getCookies(response)
validateSessionSuccess(response)
const { sessionId: _sessionId, sessionToken } = getCookies(response)
validateSessionSuccess(response, _sessionId, sessionToken)
sessionId = _sessionId
})

await v.superRequest(app).post('/protect', {}, {
Expand All @@ -223,27 +262,12 @@ describe('Session', () => {

it('return unauthorized when session token is expired', async () => {
const app = v.App()
const secretKey = generateSecretKey()
const session = v.Session({ secretKey, sanitizationEvery: '5m' })
const router = v.Router()

class ExampleController implements v.Controller {
public handle (_request: v.Request, response: v.Response): any {
response.status(200).end()
}
}

router.post('/session',
session.create({ userId: 123, email: 'any@mail.com' }, { expiresIn: 0 }),
v.controllerAdapter(new ExampleController())
)

router.post('/protect', session.protect(), v.controllerAdapter(new ExampleController()))

app.use(router)

let cookie = ''
await v.superRequest(app).post('/session').then((response) => {
getCookies(response)
const { cookie: _cookie } = getCookies(response)
cookie = _cookie
})

await v.superRequest(app).post('/protect', {}, {
Expand All @@ -261,18 +285,26 @@ describe('Session', () => {
const session = v.Session({ secretKey, sanitizationEvery: 1 })
const router = v.Router()

router.post('/session',
session.create({ userId: 123, email: 'any@mail.com' }, { expiresIn: 1 }),
v.controllerAdapter(new ExampleController())
)
class ExampleBController implements v.Controller {
public handle (request: v.Request, response: v.Response): any {
const userData = { userId: 123, email: 'any@mail.com' }
const config = { expiresIn: 1 }
session.create(request, response, userData, config)
response.status(200).json({ session: request.session })
}
}

router.post('/session', v.controllerAdapter(new ExampleBController()))
router.post('/protect', session.protect(), v.controllerAdapter(new ExampleController()))

app.use(router)

let cookie = ''

await v.superRequest(app).post('/session').then((response) => {
getCookies(response)
validateSessionSuccess(response)
const { cookie: _cookie, sessionId, sessionToken } = getCookies(response)
cookie = _cookie
validateSessionSuccess(response, sessionId, sessionToken)
})

const delay = async (ms: number): Promise<void> => await new Promise<void>((resolve) => setTimeout(resolve, ms))
Expand All @@ -289,23 +321,13 @@ describe('Session', () => {
})

it('Should be able to update session when passed session id', async () => {
const sessionId = v.randomUUID()

const app = v.App()
const secretKey = generateSecretKey()
const session = v.Session({ secretKey, sanitizationEvery: '5m' })
const router = v.Router()

router.post('/session',
session.create({ userId: 123, email: 'any@mail.com' }, { expiresIn: '15m', sessionId }),
v.controllerAdapter(new ExampleController())
)

app.use(router)

await v.superRequest(app).post('/session').then((response) => {
getCookies(response)
validateSessionSuccess(response)
const { sessionId, sessionToken } = getCookies(response)
validateSessionSuccess(response, sessionId, sessionToken)

const cookies: any = response.headers['set-cookie']
cookies.forEach((cookie: string) => {
if (cookie.startsWith('session-id=')) {
Expand All @@ -315,8 +337,9 @@ describe('Session', () => {
})

await v.superRequest(app).post('/session').then((response) => {
getCookies(response)
validateSessionSuccess(response)
const { sessionId, sessionToken } = getCookies(response)
validateSessionSuccess(response, sessionId, sessionToken)

const cookies: any = response.headers['set-cookie']
cookies.forEach((cookie: string) => {
if (cookie.startsWith('session-id=')) {
Expand All @@ -331,17 +354,19 @@ describe('Session', () => {
it('Should be able to update the session when it has the session ID and session token in the cookie', async () => {
const app = v.App()
app.use(router)
let cookie = ''

await v.superRequest(app).post('/session').then((response) => {
getCookies(response)
validateSessionSuccess(response)
const { cookie: _cookie, sessionId, sessionToken } = getCookies(response)
validateSessionSuccess(response, sessionId, sessionToken)
cookie = _cookie
})

await v.superRequest(app).post('/session', {}, {
headers: { cookie }
}).then((response) => {
getCookies(response)
validateSessionSuccess(response)
const { sessionId, sessionToken } = getCookies(response)
validateSessionSuccess(response, sessionId, sessionToken)
})

app.close()
Expand Down
Loading

0 comments on commit 14c6ca1

Please sign in to comment.