Skip to content

Commit

Permalink
feat: moving cookie related logic to cookieAdapter.ts (#42)
Browse files Browse the repository at this point in the history
* feat: moving cookie related logic to cookieAdapter.ts

* feat: forcing appSession type upon adapter

* feat: add error handling in case public adapter does not handle errors

* feat: typo fixes

* feat: add PR change request

* feat: remove comment

* feat: remove yarn

* feat: auto install peers

* feat: splitting types

* feat: fix inferSessionQuery

* feat: better test cases

* feat: fix expires

* feat: change cookieAdapter const to createCookieAdapter function to be able to pass custom sessionKey

- minor function extraction for better readability

* feat: reorder private functions

* bump version

---------

Co-authored-by: Eunjae Lee <[email protected]>
  • Loading branch information
BibiSebi and eunjae-lee authored Jul 15, 2024
1 parent a2aced7 commit 2e0885b
Show file tree
Hide file tree
Showing 16 changed files with 3,034 additions and 4,429 deletions.
801 changes: 0 additions & 801 deletions .yarn/releases/yarn-3.2.4.cjs

This file was deleted.

2 changes: 0 additions & 2 deletions .yarnrc

This file was deleted.

5 changes: 0 additions & 5 deletions .yarnrc.yml

This file was deleted.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@storyblok/app-extension-auth",
"description": "A typed JavaScript library for handling authentication with Storyblok apps.",
"version": "2.0.0-beta.1",
"version": "2.0.0-beta.2",
"author": {
"name": "Johannes Lindgren",
"email": "[email protected]"
Expand Down
6,255 changes: 2,787 additions & 3,468 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

59 changes: 0 additions & 59 deletions src/session-adapters/cookieAdapter.ts

This file was deleted.

81 changes: 81 additions & 0 deletions src/session-adapters/createCookieAdapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { expireCookie, getCookie, setCookie, verifyData } from '../utils'
import jwt from 'jsonwebtoken'
import { Adapter } from './publicAdapter'
import { isAppSession } from '../session'

const clientSecret = process.env['CLIENT_SECRET'] || ''
const defaultSessionKey = 'sb.auth'

type CreateCookieAdapter = (params?: {
sessionKey?: string | undefined
}) => Adapter

export const createCookieAdapter: CreateCookieAdapter = (params) => {
const key = params?.sessionKey ?? defaultSessionKey

const adapter: Adapter = {
getSession: ({ req, spaceId, userId }) => {
const cookie = getCookie(req, createScopedKey({ spaceId, userId, key }))

if (!cookie) {
return undefined
}

const verifiedData = verifyData(clientSecret, cookie)

if (!isAppSession(verifiedData)) {
return undefined
}

return verifiedData
},

setSession: ({ res, spaceId, userId, session }) => {
const expires = createExpirationDate(7)

const signedData = jwt.sign({ data: session }, clientSecret)

setCookie(
res,
createScopedKey({ spaceId, userId, key }),
signedData,
expires,
)
return true
},

hasSession: (params) => {
const session = adapter.getSession(params)
return session !== undefined
},

removeSession: ({ res, spaceId, userId }) => {
expireCookie(res, createScopedKey({ spaceId, userId, key }))
return true
},
}

return adapter
}

// We do not use `clientId` in cookie adapter,
// because different plugins will have different domain names,
// and it's enough to differentiate these cookie values.
const createScopedKey = ({
spaceId,
userId,
key,
}: {
spaceId: string
userId: string
key: string
}) => {
return `${spaceId}:${userId}:${key}`
}

//TODO: extract to util
const createExpirationDate = (days: number): Date => {
const expires = new Date()
expires.setDate(expires.getDate() + days)
return expires
}
2 changes: 1 addition & 1 deletion src/session-adapters/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from './cookieAdapter'
export * from './createCookieAdapter'
export * from './publicAdapter'
export * from './internalAdapter'
80 changes: 45 additions & 35 deletions src/session-adapters/internalAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
} from '../utils'
import { AppSession } from '../session/types'
import { AuthHandlerParams } from '../storyblok-auth-api'
import { sessionIdentifier } from '../session/sessionIdentifier'

export type InternalAdapter = {
// session
Expand Down Expand Up @@ -52,7 +51,7 @@ type CreateInternalAdapter = ({
res,
adapter,
}: {
params: Pick<AuthHandlerParams, 'clientId' | 'clientSecret' | 'sessionKey'>
params: Pick<AuthHandlerParams, 'clientId' | 'clientSecret'>
req: http.IncomingMessage
res: http.ServerResponse
adapter: Adapter
Expand All @@ -64,65 +63,76 @@ export const createInternalAdapter: CreateInternalAdapter = ({
res,
adapter,
}) => {
const sessionKey = sessionIdentifier(params.sessionKey)

return {
getSession: async ({ spaceId, userId }) => {
const session = await adapter.getItem({
req,
res,
clientId: params.clientId,
spaceId,
userId,
key: sessionKey,
})
if (!session) {
return undefined
}
try {
return JSON.parse(session) as AppSession
} catch (err) {
const session = await adapter.getSession({
req,
res,
clientId: params.clientId,
spaceId,
userId,
})

if (!session) {
return undefined
}

return session
} catch (e) {
console.log('Retrieving the session failed: ', e)
return undefined
}
},

setSession: async ({ spaceId, userId, session }) => {
try {
return await adapter.setItem({
const isSessionSet = await adapter.setSession({
req,
res,
clientId: params.clientId,
spaceId,
userId,
key: sessionKey,
value: JSON.stringify(session),
session,
})
} catch (err) {

return isSessionSet
} catch (e) {
console.log('Setting the session failed: ', e)
return false
}
},

hasSession: ({ spaceId, userId }) =>
adapter.hasItem({
req,
res,
clientId: params.clientId,
spaceId,
userId,
key: sessionKey,
}),
hasSession: async ({ spaceId, userId }) => {
try {
const hasSession = await adapter.hasSession({
req,
res,
clientId: params.clientId,
spaceId,
userId,
})

return hasSession
} catch (e) {
console.log('Session could not be found: ', e)
return false
}
},

removeSession: async ({ spaceId, userId }) => {
try {
return await adapter.removeItem({
const sessionRemoved = await adapter.removeSession({
req,
res,
clientId: params.clientId,
spaceId,
userId,
key: sessionKey,
})
} catch (err) {

return sessionRemoved
} catch (e) {
console.log('Removing the session failed: ', e)
return false
}
},
Expand All @@ -133,15 +143,15 @@ export const createInternalAdapter: CreateInternalAdapter = ({
return true
},

getCallbackData() {
getCallbackData: () => {
const cookie = getCookie(req, callbackCookieName)
const data = verifyData(params.clientSecret, cookie || '') as
| CallbackCookieData
| undefined
return data
},

removeCallbackData() {
removeCallbackData: () => {
expireCookie(res, callbackCookieName)
return true
},
Expand Down
59 changes: 25 additions & 34 deletions src/session-adapters/publicAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,33 @@
import { IncomingMessage, ServerResponse } from 'node:http'
import { AppSession } from '../session'

export type MaybePromise<T> = T | Promise<T>

export type Adapter = {
getItem: (params: {
req: IncomingMessage
res: ServerResponse
clientId: string
spaceId: string
userId: string
key: string
}) => MaybePromise<string | undefined>
getSession: GetSession
setSession: SetSession
removeSession: RemoveSession
hasSession: HasSession
}

setItem: (params: {
req: IncomingMessage
res: ServerResponse
clientId: string
spaceId: string
userId: string
key: string
value: string
}) => MaybePromise<boolean>
type BaseSessionParams = {
req: IncomingMessage
res: ServerResponse
clientId: string
spaceId: string
userId: string
}

removeItem: (params: {
req: IncomingMessage
res: ServerResponse
clientId: string
spaceId: string
userId: string
key: string
}) => MaybePromise<boolean>
type GetSession = (
params: BaseSessionParams,
) => MaybePromise<AppSession | undefined>

hasItem: (params: {
req: IncomingMessage
res: ServerResponse
clientId: string
spaceId: string
userId: string
key: string
}) => MaybePromise<boolean>
}
type SetSession = (
params: BaseSessionParams & {
session: AppSession
},
) => MaybePromise<boolean>

type RemoveSession = (params: BaseSessionParams) => MaybePromise<boolean>

type HasSession = (params: BaseSessionParams) => MaybePromise<boolean>
Loading

0 comments on commit 2e0885b

Please sign in to comment.