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

cameri / nostream / 27743281618

18 Jun 2026 07:17AM UTC coverage: 67.377% (+0.4%) from 66.995%
27743281618

Pull #641

github

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

1979 of 3297 branches covered (60.02%)

Branch coverage included in aggregate %.

185 of 221 new or added lines in 17 files covered. (83.71%)

4535 of 6371 relevant lines covered (71.18%)

18.91 hits per line

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

86.36
/src/admin/password-admin-auth-provider.ts
1
import { Request, Response } from 'express'
2

3
import { IAdminAuthProvider } from '../@types/admin'
4
import { Settings } from '../@types/settings'
5
import { adminLoginBodySchema } from '../schemas/admin-login-schema'
2✔
6
import { verifyAdminPasswordHash, verifyPlaintextPassword } from '../utils/admin-password'
2✔
7
import {
2✔
8
  buildAdminSessionCookieHeader,
9
  createAdminSessionToken,
10
  getAdminSessionTokenFromRequest,
11
  isValidAdminSessionToken,
12
  parseAdminSessionToken,
13
  resolveAdminSessionTtlSeconds,
14
} from '../utils/admin-session'
15
import { validateSchema } from '../utils/validation'
2✔
16

17
export class PasswordAdminAuthProvider implements IAdminAuthProvider {
2✔
18
  public constructor(private readonly settings: () => Settings) {}
10✔
19

20
  public async handleLogin(request: Request, response: Response): Promise<void> {
21
    const validation = validateSchema(adminLoginBodySchema)(request.body)
3✔
22
    if (validation.error) {
3!
NEW
23
      response.status(400).setHeader('content-type', 'application/json').send({ error: 'Invalid request' })
×
NEW
24
      return
×
25
    }
26

27
    if (!this.verifyPassword(validation.value.password)) {
3✔
28
      response.status(401).setHeader('content-type', 'application/json').send({ error: 'Unauthorized' })
1✔
29
      return
1✔
30
    }
31

32
    const currentSettings = this.settings()
2✔
33
    const sessionTtlSeconds = resolveAdminSessionTtlSeconds(currentSettings.admin?.sessionTtlSeconds)
2✔
34
    const expiresAt = Math.floor(Date.now() / 1000) + sessionTtlSeconds
2✔
35
    const token = createAdminSessionToken(expiresAt)
2✔
36

37
    response
2✔
38
      .status(200)
39
      .setHeader('content-type', 'application/json')
40
      .setHeader('Set-Cookie', buildAdminSessionCookieHeader(request, currentSettings, token, sessionTtlSeconds))
41
      .send({ authenticated: true, expiresAt })
42
  }
43

44
  public isRequestAuthenticated(request: Request): boolean {
45
    const token = this.getToken(request)
5✔
46
    return token ? isValidAdminSessionToken(token) : false
5✔
47
  }
48

49
  public getSessionExpiresAt(request: Request): number | undefined {
50
    const token = this.getToken(request)
2✔
51
    return token ? parseAdminSessionToken(token)?.expiresAt : undefined
2!
52
  }
53

54
  private getToken(request: Request): string | undefined {
55
    return getAdminSessionTokenFromRequest(request.headers.authorization, request.headers.cookie)
7✔
56
  }
57

58
  private verifyPassword(password: string): boolean {
59
    const envPassword = process.env.ADMIN_PASSWORD
3✔
60
    if (typeof envPassword === 'string' && envPassword.length > 0) {
3✔
61
      return verifyPlaintextPassword(password, envPassword)
2✔
62
    }
63

64
    const passwordHash = this.settings().admin?.passwordHash
1✔
65
    if (!passwordHash) {
1!
NEW
66
      return false
×
67
    }
68

69
    return verifyAdminPasswordHash(password, passwordHash)
1✔
70
  }
71
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc