82 lines
3.7 KiB
JavaScript
82 lines
3.7 KiB
JavaScript
import { test, after } from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import { startAppwriteMock } from './support/appwriteMock.js'
|
|
import { startFakeStripe } from './support/fakeStripe.js'
|
|
import { useTestEnv } from './support/testEnv.js'
|
|
|
|
// Mitarbeiter-2FA per E-Mail-Code: Appwrite-Sitzung aus dem Login und offene Code-Anmeldungen
|
|
const aw = await startAppwriteMock()
|
|
const st = await startFakeStripe()
|
|
useTestEnv({ appwriteUrl: aw.url, stripeUrl: st.url })
|
|
const { loginWithAppwrite, appwriteSessionFetch } = await import('../server/services/appwriteClient.js')
|
|
after(() => Promise.all([aw.close(), st.close()]))
|
|
|
|
aw.addUser({ $id: 'u_staff', email: 'kenso@webklar.com', password: 'geheim-geheim', mfa: true, emailVerification: true })
|
|
|
|
test('loginWithAppwrite liefert die Appwrite-Sitzung', async () => {
|
|
const user = await loginWithAppwrite('kenso@webklar.com', 'geheim-geheim')
|
|
assert.equal(user.$id, 'u_staff')
|
|
assert.equal(user.sessionCookie, 'sess-u_staff')
|
|
})
|
|
|
|
test('appwriteSessionFetch schickt Sitzung und Sprache', async () => {
|
|
const before = aw.mailsSent('u_staff')
|
|
const challenge = await appwriteSessionFetch('/account/mfa/challenges', {
|
|
method: 'POST',
|
|
body: { factor: 'email' },
|
|
sessionCookie: 'sess-u_staff',
|
|
})
|
|
assert.match(challenge.$id, /^ch/)
|
|
assert.equal(aw.mailsSent('u_staff'), before + 1)
|
|
assert.equal(aw.lastLocale(), 'de')
|
|
await assert.rejects(
|
|
appwriteSessionFetch('/account/mfa/challenges', { method: 'PUT', body: { challengeId: challenge.$id, otp: '000000' }, sessionCookie: 'sess-u_staff' }),
|
|
(err) => err.status === 401 && err.type === 'user_invalid_token'
|
|
)
|
|
})
|
|
|
|
const { maskEmail, startStaffMfa, verifyStaffMfa, resendStaffMfa } = await import('../server/services/staffMfa.js')
|
|
|
|
async function start() {
|
|
const { sessionCookie } = await loginWithAppwrite('kenso@webklar.com', 'geheim-geheim')
|
|
return startStaffMfa({ userId: 'u_staff', email: 'kenso@webklar.com', sessionCookie })
|
|
}
|
|
|
|
test('maskEmail: erstes Zeichen, Rest der Adresse ausgeblendet', () => {
|
|
assert.equal(maskEmail('kenso@webklar.com'), 'k…@webklar.com')
|
|
assert.equal(maskEmail('a@b.de'), 'a…@b.de')
|
|
assert.equal(maskEmail(''), '')
|
|
})
|
|
|
|
test('Richtiger Code meldet an, danach ist die Anmeldung verbraucht', async () => {
|
|
const { key, maskedEmail } = await start()
|
|
assert.equal(maskedEmail, 'k…@webklar.com')
|
|
assert.deepEqual(await verifyStaffMfa(key, aw.lastOtp('u_staff')), { ok: true, userId: 'u_staff', email: 'kenso@webklar.com' })
|
|
assert.deepEqual(await verifyStaffMfa(key, aw.lastOtp('u_staff')), { ok: false, reason: 'gone' })
|
|
})
|
|
|
|
test('Falscher Code: nach 5 Fehlversuchen ist die Anmeldung weg', async () => {
|
|
const { key } = await start()
|
|
for (let i = 0; i < 5; i++) assert.deepEqual(await verifyStaffMfa(key, '000000'), { ok: false, reason: 'invalid' })
|
|
assert.deepEqual(await verifyStaffMfa(key, aw.lastOtp('u_staff')), { ok: false, reason: 'gone' })
|
|
})
|
|
|
|
test('Nach 10 Minuten ist die Anmeldung abgelaufen', async (t) => {
|
|
const { key } = await start()
|
|
const now = Date.now()
|
|
t.mock.method(Date, 'now', () => now + 11 * 60 * 1000)
|
|
assert.deepEqual(await verifyStaffMfa(key, aw.lastOtp('u_staff')), { ok: false, reason: 'gone' })
|
|
})
|
|
|
|
test('Code erneut senden: neue Mail, nur der neue Code gilt', async () => {
|
|
const { key } = await start()
|
|
const oldOtp = aw.lastOtp('u_staff')
|
|
const before = aw.mailsSent('u_staff')
|
|
assert.equal(await resendStaffMfa(key), true)
|
|
assert.equal(aw.mailsSent('u_staff'), before + 1)
|
|
const newOtp = aw.lastOtp('u_staff')
|
|
if (oldOtp !== newOtp) assert.deepEqual(await verifyStaffMfa(key, oldOtp), { ok: false, reason: 'invalid' })
|
|
assert.equal((await verifyStaffMfa(key, newOtp)).ok, true)
|
|
assert.equal(await resendStaffMfa(key), false)
|
|
})
|