• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

cameri / nostream / 27746379779

18 Jun 2026 08:19AM UTC coverage: 67.421% (+0.4%) from 66.995%
27746379779

Pull #641

github

web-flow
Merge efcea03f7 into faf55f1de
Pull Request #641: feat: add admin backend foundation (login, session, health)

1980 of 3297 branches covered (60.05%)

Branch coverage included in aggregate %.

190 of 226 new or added lines in 17 files covered. (84.07%)

4543 of 6378 relevant lines covered (71.23%)

21.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.19
/src/utils/admin-session.ts
1
import { timingSafeEqual } from 'crypto'
2✔
2
import { IncomingMessage } from 'http'
3

4
import { Settings } from '../@types/settings'
5
import { getPublicPathPrefix, isSecureRequest, joinPathPrefix } from './http'
2✔
6
import { deriveFromSecret, hmacSha256 } from './secret'
2✔
7

8
export const DEFAULT_ADMIN_SESSION_TTL_SECONDS = 86400
2✔
9

10
export const resolveAdminSessionTtlSeconds = (
2✔
11
  sessionTtlSeconds: number | undefined,
12
  defaultTtlSeconds = DEFAULT_ADMIN_SESSION_TTL_SECONDS,
8✔
13
): number => {
14
  if (typeof sessionTtlSeconds === 'number' && Number.isFinite(sessionTtlSeconds) && sessionTtlSeconds > 0) {
8✔
15
    return Math.floor(sessionTtlSeconds)
3✔
16
  }
17

18
  return defaultTtlSeconds
5✔
19
}
20

21
export const buildAdminSessionCookieHeader = (
2✔
22
  request: IncomingMessage,
23
  settings: Settings,
24
  token: string,
25
  maxAgeSeconds: number,
26
): string => {
27
  const cookiePath = joinPathPrefix(getPublicPathPrefix(request, settings), '/admin')
4✔
28
  const secure = isSecureRequest(request, settings) ? '; Secure' : ''
4✔
29

30
  return `admin_session=${token}; Path=${cookiePath}; HttpOnly; SameSite=Strict; Max-Age=${maxAgeSeconds}${secure}`
4✔
31
}
32

33
export const createAdminSessionToken = (expiresAt: number): string => {
2✔
34
  const signature = hmacSha256(deriveFromSecret('admin-session'), `${expiresAt}`).toString('hex')
4✔
35
  return `${expiresAt}.${signature}`
3✔
36
}
37

38
export const parseAdminSessionToken = (token: string): { expiresAt: number } | undefined => {
2✔
39
  const separatorIndex = token.indexOf('.')
2✔
40
  if (separatorIndex <= 0) {
2!
NEW
41
    return undefined
×
42
  }
43

44
  const expiresAt = Number(token.slice(0, separatorIndex))
2✔
45
  if (!Number.isFinite(expiresAt)) {
2!
NEW
46
    return undefined
×
47
  }
48

49
  return { expiresAt }
2✔
50
}
51

52
export const isValidAdminSessionToken = (token: string, nowSeconds = Math.floor(Date.now() / 1000)): boolean => {
2✔
53
  const separatorIndex = token.indexOf('.')
6✔
54
  if (separatorIndex <= 0) {
6!
NEW
55
    return false
×
56
  }
57

58
  const expiresAt = Number(token.slice(0, separatorIndex))
6✔
59
  const signature = token.slice(separatorIndex + 1)
6✔
60

61
  if (!Number.isFinite(expiresAt) || expiresAt <= nowSeconds || !/^[0-9a-f]+$/.test(signature)) {
6!
NEW
62
    return false
×
63
  }
64

65
  const expected = hmacSha256(deriveFromSecret('admin-session'), `${expiresAt}`).toString('hex')
6✔
66
  const expectedBuf = Buffer.from(expected, 'utf8')
5✔
67
  const actualBuf = Buffer.from(signature, 'utf8')
5✔
68

69
  if (expectedBuf.length !== actualBuf.length) {
5✔
70
    return false
1✔
71
  }
72

73
  return timingSafeEqual(expectedBuf, actualBuf)
4✔
74
}
75

76
export const getAdminSessionTokenFromRequest = (authorizationHeader?: string, cookieHeader?: string): string | undefined => {
2✔
77
  if (authorizationHeader?.startsWith('Bearer ')) {
10✔
78
    const token = authorizationHeader.slice('Bearer '.length).trim()
3✔
79
    return token.length > 0 ? token : undefined
3!
80
  }
81

82
  if (!cookieHeader) {
7✔
83
    return undefined
2✔
84
  }
85

86
  for (const part of cookieHeader.split(';')) {
5✔
87
    const [name, ...valueParts] = part.trim().split('=')
5✔
88
    if (name === 'admin_session') {
5!
89
      const value = valueParts.join('=').trim()
5✔
90
      return value.length > 0 ? value : undefined
5!
91
    }
92
  }
93

NEW
94
  return undefined
×
95
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc