Improving Win95 styling
This commit is contained in:
@@ -0,0 +1,200 @@
|
||||
import express from 'express'
|
||||
import cookieParser from 'cookie-parser'
|
||||
import jwt from 'jsonwebtoken'
|
||||
import request from 'supertest'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { requireLabAccess } from '../src/labAuth.js'
|
||||
|
||||
const secret = 'test-lab-secret'
|
||||
|
||||
function testApp(config: Parameters<typeof requireLabAccess>[0]) {
|
||||
const app = express()
|
||||
app.use(cookieParser())
|
||||
app.use(requireLabAccess(config))
|
||||
app.get('/admin', (_request, response) => response.send('ok'))
|
||||
app.get('/api/ca/decks', (_request, response) => response.json([{ id: 'deck' }]))
|
||||
return app
|
||||
}
|
||||
|
||||
function authCookie(claims: object = {}) {
|
||||
return `auth_token=${jwt.sign({ sub: '42', email: 'student@glitch.university', ...claims }, secret)}`
|
||||
}
|
||||
|
||||
describe('lab auth middleware', () => {
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks()
|
||||
})
|
||||
|
||||
it('allows requests when lab auth is disabled', async () => {
|
||||
const app = testApp({
|
||||
enabled: false,
|
||||
gnommowebUrl: 'https://glitch.university',
|
||||
jwtSecret: '',
|
||||
keycardMeritSlug: 'lab-keycard',
|
||||
keycardRequired: true,
|
||||
signInUrl: 'https://glitch.university/auth/google',
|
||||
userProfileUrl: 'https://glitch.university/api/user/profile'
|
||||
})
|
||||
|
||||
await request(app).get('/admin').expect(200, 'ok')
|
||||
})
|
||||
|
||||
it('redirects browser requests without a shared auth cookie', async () => {
|
||||
const app = testApp({
|
||||
enabled: true,
|
||||
gnommowebUrl: 'https://glitch.university',
|
||||
jwtSecret: secret,
|
||||
keycardMeritSlug: 'lab-keycard',
|
||||
keycardRequired: true,
|
||||
signInUrl: 'https://glitch.university/auth/google?returnTo={returnTo}',
|
||||
userProfileUrl: 'https://glitch.university/api/user/profile'
|
||||
})
|
||||
|
||||
const response = await request(app)
|
||||
.get('/admin')
|
||||
.set('accept', 'text/html')
|
||||
.set('host', 'lab.glitch.university')
|
||||
.set('x-forwarded-proto', 'https')
|
||||
.expect(302)
|
||||
|
||||
expect(response.headers.location).toContain('https://glitch.university/auth/google?returnTo=')
|
||||
expect(decodeURIComponent(response.headers.location)).toContain('https://lab.glitch.university/admin')
|
||||
})
|
||||
|
||||
it('rejects API requests with an invalid shared auth cookie', async () => {
|
||||
const app = testApp({
|
||||
enabled: true,
|
||||
gnommowebUrl: 'https://glitch.university',
|
||||
jwtSecret: secret,
|
||||
keycardMeritSlug: 'lab-keycard',
|
||||
keycardRequired: true,
|
||||
signInUrl: 'https://glitch.university/auth/google',
|
||||
userProfileUrl: 'https://glitch.university/api/user/profile'
|
||||
})
|
||||
|
||||
await request(app)
|
||||
.get('/api/ca/decks')
|
||||
.set('cookie', 'auth_token=not-a-real-jwt')
|
||||
.set('accept', 'application/json')
|
||||
.expect(401)
|
||||
.expect((response) => {
|
||||
expect(response.body.error).toBe('Invalid or expired token')
|
||||
})
|
||||
})
|
||||
|
||||
it('allows valid JWTs when keycard checks are disabled', async () => {
|
||||
const app = testApp({
|
||||
enabled: true,
|
||||
gnommowebUrl: 'https://glitch.university',
|
||||
jwtSecret: secret,
|
||||
keycardMeritSlug: 'lab-keycard',
|
||||
keycardRequired: false,
|
||||
signInUrl: 'https://glitch.university/auth/google',
|
||||
userProfileUrl: 'https://glitch.university/api/user/profile'
|
||||
})
|
||||
|
||||
await request(app).get('/api/ca/decks').set('cookie', authCookie()).expect(200)
|
||||
})
|
||||
|
||||
it('allows valid JWTs that include a lab keycard claim', async () => {
|
||||
const fetchSpy = vi.fn()
|
||||
vi.stubGlobal('fetch', fetchSpy)
|
||||
|
||||
const app = testApp({
|
||||
enabled: true,
|
||||
gnommowebUrl: 'https://glitch.university',
|
||||
jwtSecret: secret,
|
||||
keycardMeritSlug: 'lab-keycard',
|
||||
keycardRequired: true,
|
||||
signInUrl: 'https://glitch.university/auth/google',
|
||||
userProfileUrl: 'https://glitch.university/api/user/profile'
|
||||
})
|
||||
|
||||
await request(app)
|
||||
.get('/api/ca/decks')
|
||||
.set('cookie', authCookie({ merit_slug: 'lab-keycard' }))
|
||||
.expect(200)
|
||||
|
||||
expect(fetchSpy).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('allows valid JWTs when the gnommoweb user profile includes the merit slug', async () => {
|
||||
vi.stubGlobal('fetch', vi.fn(async () => new Response(JSON.stringify({
|
||||
merits: [{ slug: 'lab-keycard' }]
|
||||
}), {
|
||||
headers: { 'content-type': 'application/json' },
|
||||
status: 200
|
||||
})))
|
||||
|
||||
const app = testApp({
|
||||
enabled: true,
|
||||
gnommowebUrl: 'https://glitch.university',
|
||||
jwtSecret: secret,
|
||||
keycardMeritSlug: 'lab-keycard',
|
||||
keycardRequired: true,
|
||||
signInUrl: 'https://glitch.university/auth/google',
|
||||
userProfileUrl: 'https://glitch.university/api/user/profile'
|
||||
})
|
||||
|
||||
await request(app)
|
||||
.get('/api/ca/decks')
|
||||
.set('cookie', authCookie())
|
||||
.set('accept', 'application/json')
|
||||
.expect(200)
|
||||
})
|
||||
|
||||
it('returns a locked response when the gnommoweb user profile lacks the merit slug', async () => {
|
||||
vi.stubGlobal('fetch', vi.fn(async () => new Response(JSON.stringify({
|
||||
merits: [{ slug: 'other_merit' }]
|
||||
}), {
|
||||
headers: { 'content-type': 'application/json' },
|
||||
status: 200
|
||||
})))
|
||||
|
||||
const app = testApp({
|
||||
enabled: true,
|
||||
gnommowebUrl: 'https://glitch.university',
|
||||
jwtSecret: secret,
|
||||
keycardMeritSlug: 'lab-keycard',
|
||||
keycardRequired: true,
|
||||
signInUrl: 'https://glitch.university/auth/google',
|
||||
userProfileUrl: 'https://glitch.university/api/user/profile'
|
||||
})
|
||||
|
||||
await request(app)
|
||||
.get('/admin')
|
||||
.set('cookie', authCookie())
|
||||
.set('accept', 'text/html')
|
||||
.expect(403)
|
||||
.expect((response) => {
|
||||
expect(response.text).toContain('Lab keycard required')
|
||||
expect(response.text).toContain('does not have the CA Lab Keycard yet')
|
||||
})
|
||||
})
|
||||
|
||||
it('reports a missing gnommoweb user profile endpoint clearly', async () => {
|
||||
vi.stubGlobal('fetch', vi.fn(async () => new Response(JSON.stringify({ error: 'Not found' }), {
|
||||
headers: { 'content-type': 'application/json' },
|
||||
status: 404
|
||||
})))
|
||||
|
||||
const app = testApp({
|
||||
enabled: true,
|
||||
gnommowebUrl: 'https://glitch.university',
|
||||
jwtSecret: secret,
|
||||
keycardMeritSlug: 'lab-keycard',
|
||||
keycardRequired: true,
|
||||
signInUrl: 'https://glitch.university/auth/google',
|
||||
userProfileUrl: 'https://glitch.university/api/user/profile'
|
||||
})
|
||||
|
||||
await request(app)
|
||||
.get('/api/ca/decks')
|
||||
.set('cookie', authCookie())
|
||||
.set('accept', 'application/json')
|
||||
.expect(403)
|
||||
.expect((response) => {
|
||||
expect(response.body.reason).toContain('HTTP 404')
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user