Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/__tests__/database.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it } from 'vitest'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import initSqlJs from 'sql.js'
import { AppDatabase, type Book, type Chapter, type ImageAsset } from '@/lib/database'

Expand Down Expand Up @@ -49,9 +49,17 @@ function chapter(overrides: Partial<Chapter> = {}): Chapter {
let db: AppDatabase

beforeEach(async () => {
// Row ids are built from Date.now(); make it strictly increasing so records
// created within the same millisecond (e.g. two wiki pages) get unique ids.
let tick = 1_800_000_000_000
vi.spyOn(Date, 'now').mockImplementation(() => (tick += 1))
db = await makeDb()
})

afterEach(() => {
vi.restoreAllMocks()
})

describe('books', () => {
it('saves and reads books back', async () => {
await db.saveBook(book())
Expand Down
16 changes: 11 additions & 5 deletions src/__tests__/encryption.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,17 @@ describe('Encryption (legacy CryptoJS fallback)', () => {
expect(decode(decrypted)).toBe('legacy backup text')
})

it('throws when a legacy backup is decrypted with the wrong password', async () => {
it('never returns the original plaintext for a legacy backup with the wrong password', async () => {
const legacy = CryptoJS.AES.encrypt('legacy backup text', 'pw').toString()
// A wrong password yields garbage bytes; CryptoJS may surface this either as
// the source's own "wrong password" error or as an internal "Malformed UTF-8
// data" throw, depending on the bytes. Either way it must reject.
await expect(Encryption.decrypt(legacy, 'nope')).rejects.toThrow()
// A wrong password usually throws (bad padding / malformed UTF-8), but can
// occasionally decode to non-empty garbage. The deterministic invariant is
// that it must never yield the original plaintext.
let recovered: string | null = null
try {
recovered = decode(await Encryption.decrypt(legacy, 'nope'))
} catch {
// Throwing is the common, acceptable outcome.
}
expect(recovered).not.toBe('legacy backup text')
})
})
Loading