Skip to content

Commit 35278b0

Browse files
feat: return with the getAll method (#77)
* feat: return with the getAll method * refactor(SHAPE-10063): apply Johannes feedback * docs: update README with Alba feedback
1 parent 88773ea commit 35278b0

File tree

10 files changed

+97
-25
lines changed

10 files changed

+97
-25
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@ const sessionStore = getSessionStore(authHandlerParams)({
2525
})
2626
```
2727

28-
The `sessionStore` created by `sessionCookieStore` now has three methods: `get`, `put`, and `remove`. The `getAll` method is no longer provided. If you believe the `getAll` method is still useful for your use case, please let us know by opening a GitHub issue.
28+
The `sessionStore` created by `sessionCookieStore` now exposes four methods: `get`, `getAll`, `put`, and `remove`.
2929

30-
The `put` and `remove` methods now return a `Promise<boolean>` instead of a `Promise<void>`.
30+
- The `getAll` method returns all app sessions, regardless of the spaces that the user has open.
31+
- The `put` and `remove` methods now return a `Promise<boolean>` instead of a `Promise<void>`.
3132

3233
### `AuthHandlerParams`
3334

@@ -202,14 +203,13 @@ const href = `/my/other/page?spaceId=${spaceId}&userId=${userId}`
202203

203204
To run OAuth locally, pass the `storyblokApiBaseUrl` property to the params object when calling the `authHandler` function in the target project (i.e. the plugin or application you want to test). With this parameter, you can change the target's backend environment.
204205

205-
206206
```typescript
207207
import { AuthHandlerParams } from '@storyblok/app-extension-auth'
208208

209209
import { authHandler } from '@storyblok/app-extension-auth'
210210
const params: AuthHandlerParams = {
211211
// ...
212-
storyblokApiBaseUrl: 'http://localhost:1234'
212+
storyblokApiBaseUrl: 'http://localhost:1234',
213213
}
214214
authHandler(params)
215215
```

src/session-adapters/createCookieAdapter.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { expireCookie, getCookie, setCookie, verifyData } from '../utils'
1+
import {
2+
expireCookie,
3+
getAllCookies,
4+
getCookie,
5+
setCookie,
6+
verifyData,
7+
} from '../utils'
28
import jwt from 'jsonwebtoken'
39
import { Adapter } from './publicAdapter'
410
import { isAppSession } from '../session'
@@ -32,6 +38,20 @@ export const createCookieAdapter: CreateCookieAdapter = (params) => {
3238
return verifiedData
3339
},
3440

41+
getAllSessions: ({ req }) => {
42+
return getAllCookies(req, key)
43+
.map((cookie) => {
44+
const verifiedData = verifyData(clientSecret, cookie)
45+
46+
if (!isAppSession(verifiedData)) {
47+
return undefined
48+
}
49+
50+
return verifiedData
51+
})
52+
.filter((cookie) => cookie !== undefined)
53+
},
54+
3555
setSession: ({ res, spaceId, userId, session }) => {
3656
const expires = createExpirationDate(7)
3757

src/session-adapters/internalAdapter.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ export type InternalAdapter = {
2121
userId: string
2222
}) => MaybePromise<AppSession | undefined>
2323

24+
getAllSessions?: () => MaybePromise<AppSession[] | undefined>
25+
2426
setSession: (params: {
2527
spaceId: string
2628
userId: string
@@ -85,6 +87,23 @@ export const createInternalAdapter: CreateInternalAdapter = ({
8587
}
8688
},
8789

90+
getAllSessions: async () => {
91+
try {
92+
if (!adapter.getAllSessions) {
93+
return undefined
94+
}
95+
96+
const sessions = await adapter.getAllSessions({
97+
req,
98+
})
99+
100+
return sessions
101+
} catch (e) {
102+
console.log('Retrieving all the sessions failed: ', e)
103+
return undefined
104+
}
105+
},
106+
88107
setSession: async ({ spaceId, userId, session }) => {
89108
try {
90109
const isSessionSet = await adapter.setSession({

src/session-adapters/publicAdapter.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ import { AppSession } from '../session'
33

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

6+
// eslint-disable-next-line functional/no-mixed-types
67
export type Adapter = {
78
getSession: GetSession
9+
getAllSessions?: GetAllSessions
810
setSession: SetSession
911
removeSession: RemoveSession
1012
hasSession: HasSession
@@ -22,6 +24,10 @@ type GetSession = (
2224
params: BaseSessionParams,
2325
) => MaybePromise<AppSession | undefined>
2426

27+
type GetAllSessions = (
28+
params: Pick<BaseSessionParams, 'req'>,
29+
) => MaybePromise<AppSession[]>
30+
2531
type SetSession = (
2632
params: BaseSessionParams & {
2733
session: AppSession

src/session/sessionStore.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ export const getSessionStore: AppSessionCookieStoreFactory =
3030
})
3131
return await refreshStoredAppSession(params, adapter, session)
3232
},
33+
getAll: async () => {
34+
const sessions = await adapter.getAllSessions?.()
35+
36+
return sessions || []
37+
},
3338
put: async (session) =>
3439
await adapter.setSession({
3540
spaceId: String(session.spaceId),

src/session/types/AppSessionStore.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export type AppSessionStore = {
88
autoRefresh?: boolean
99
},
1010
) => Promise<AppSession | undefined>
11+
getAll?: () => Promise<AppSession[]>
1112
put: (session: AppSession) => Promise<boolean>
1213
remove: (keys: AppSessionQuery) => Promise<boolean>
1314
}

src/storyblok-auth-api/refreshToken.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export const refreshToken =
4040
)
4141
}
4242
return tokenSet
43-
} catch (e) {
43+
} catch {
4444
return new Error('Refresh token failed unexpectedly with an exception')
4545
}
4646
}

src/utils/cookie/getCookie/getCookie.test.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import httpMocks from 'node-mocks-http'
2-
import { getCookie } from './getCookie'
2+
import { getAllCookies, getCookie } from './getCookie'
33

44
const cookieName = 'myCookie'
55
const cookieValue = 'abc123'
@@ -42,4 +42,14 @@ describe('Getting app cookies', () => {
4242
)
4343
expect(getCookie(req, cookieName)).toBeUndefined()
4444
})
45+
it('Should get all the app cookies by name/key (ignoring its scope)', () => {
46+
const req = mockRequest(
47+
`firstCookie=firstCookieValue; 111111:222222:myCookie=sessionCookieValue1; 888888:999999:myCookie=sessionCookieValue2; lastCookie=lastCookieValue`,
48+
)
49+
50+
expect(getAllCookies(req, cookieName)).toEqual([
51+
'sessionCookieValue1',
52+
'sessionCookieValue2',
53+
])
54+
})
4555
})

src/utils/cookie/getCookie/getCookie.ts

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,42 @@ import http from 'http'
33
/**
44
* RegExp to match all characters to escape in a RegExp.
55
*/
6-
76
const REGEXP_ESCAPE_CHARS_REGEXP = /[\^$\\.*+?()[\]{}|]/g
87

98
const getPattern = (name: string) =>
109
new RegExp(
11-
'(?:^|;) *' + name.replace(REGEXP_ESCAPE_CHARS_REGEXP, '\\$&') + '=([^;]*)',
10+
'(?:^|;)*[0-9:]*' +
11+
name.replace(REGEXP_ESCAPE_CHARS_REGEXP, '\\$&') +
12+
'=([^;]*)',
1213
)
1314

1415
export const getCookie = (
1516
request: http.IncomingMessage,
1617
name: string,
1718
): string | undefined => {
18-
const header = request.headers['cookie']
19-
if (!header) {
20-
return undefined
21-
}
22-
23-
const match = header.match(getPattern(name))
24-
if (!match) {
25-
return undefined
26-
}
27-
28-
const value = match[1]
29-
if (value[0] === '"') {
30-
return value.slice(1, -1)
31-
}
32-
return value
19+
return getAllCookies(request, name)[0]
20+
}
21+
22+
export const getAllCookies = (
23+
request: http.IncomingMessage,
24+
name: string,
25+
): string[] => {
26+
const headerCookies = (request.headers['cookie'] || '').split(/;\s*/)
27+
28+
return headerCookies
29+
.map((cookie) => {
30+
const match = cookie.match(getPattern(name))
31+
if (!match) {
32+
return undefined
33+
}
34+
35+
const value = match[1]
36+
37+
if (value[0] === '"') {
38+
return value.slice(1, -1)
39+
}
40+
41+
return value
42+
})
43+
.filter((cookie) => cookie !== undefined)
3344
}

src/utils/verifyData/verifyData.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export const verifyData = <Data>(secret: string, jwtToken: string): unknown => {
1010
return undefined
1111
}
1212
return payload.data as Data
13-
} catch (e) {
13+
} catch {
1414
return undefined
1515
}
1616
}

0 commit comments

Comments
 (0)