Skip to content

Commit 917783c

Browse files
authored
Merge pull request #3043 from opencloud-eu/renovate/dev-dependencies
chore(deps): update devdependencies (non-major) to v3.5.41
2 parents 1dbeae9 + f9c4055 commit 917783c

9 files changed

Lines changed: 810 additions & 779 deletions

File tree

packages/web-app-rclone-crypt/tests/unit/unlock.spec.ts

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,46 @@
11
import { mock } from 'vitest-mock-extended'
22
import { Resource, SpaceResource } from '@opencloud-eu/web-client'
33
import { WebDAV } from '@opencloud-eu/web-client/webdav'
4-
import { streamToArrayBuffer } from '@opencloud-eu/web-pkg'
4+
import { FolderVaultEngine, streamToArrayBuffer } from '@opencloud-eu/web-pkg'
55
import { probeVaultNeedsSetup, unlockVault, VaultTarget } from '../../src/unlock'
66
import { createEngine } from '../../src/crypto/engine'
77
import { INTEGRITY_ID_PROP } from '../../src/integrity'
88

9+
// Every unlock derives a real scrypt key (N=2^14), which takes long enough on a
10+
// loaded CI runner to blow the 5s default.
11+
vi.setConfig({ testTimeout: 15_000 })
12+
913
const vaultRoot = '/my.vault'
1014
const passphrase = 'foobar'
1115
// "report.txt" encrypted with the passphrase above - the sample `verifySegment`
1216
// decrypts when a vault carries no integrity token.
1317
const encryptedChildName = 'unq54c7b9fj4lam8t82q1hofdo'
1418

19+
// One engine - and therefore one scrypt derivation - per passphrase for the
20+
// whole file. Engines hold no per-test state, and the derivation is the single
21+
// most expensive thing these tests do.
22+
const engines = new Map<string, FolderVaultEngine>()
23+
function engineFor(password: string): FolderVaultEngine {
24+
if (!engines.has(password)) {
25+
engines.set(password, createEngine(vaultRoot, password))
26+
}
27+
return engines.get(password)
28+
}
29+
1530
function tokenFor(password: string): Promise<string> {
16-
return createEngine(vaultRoot, password).createIntegrityToken()
31+
return engineFor(password).createIntegrityToken()
1732
}
1833

1934
/** Real rclone-crypt ciphertext for `content`, as the server would hold it. */
2035
function encryptedFile(password: string, content: string): Promise<ArrayBuffer> {
21-
const engine = createEngine(vaultRoot, password)
22-
return streamToArrayBuffer(engine.encryptContent(new Blob([content]).stream()))
36+
return streamToArrayBuffer(engineFor(password).encryptContent(new Blob([content]).stream()))
37+
}
38+
39+
/** The ciphertext a sampled file returns by default, computed once. */
40+
let sampleFileContent: Promise<ArrayBuffer> | undefined
41+
function encryptedSampleFile(): Promise<ArrayBuffer> {
42+
sampleFileContent ??= encryptedFile(passphrase, 'hello vault')
43+
return sampleFileContent
2344
}
2445

2546
type Child = { name: string; isFolder?: boolean; size?: number }
@@ -61,7 +82,7 @@ async function createTarget({
6182
)
6283
})
6384
webdav.getFileContents.mockResolvedValue({
64-
body: fileContent ?? (await encryptedFile(passphrase, 'hello vault'))
85+
body: fileContent ?? (await encryptedSampleFile())
6586
} as never)
6687
webdav.setProperties.mockResolvedValue(undefined as never)
6788

@@ -76,6 +97,12 @@ function writtenToken(webdav: WebDAV): string {
7697
return (properties as Record<string, string>)[INTEGRITY_ID_PROP]
7798
}
7899

100+
// `clearMocks` only clears calls, so a console spy would stay in place for every
101+
// test that follows it.
102+
afterEach(() => {
103+
vi.restoreAllMocks()
104+
})
105+
79106
describe('unlockVault', () => {
80107
describe('a vault carrying an integrity token', () => {
81108
it('unlocks with the right passphrase and writes nothing', async () => {
@@ -113,7 +140,7 @@ describe('unlockVault', () => {
113140
const result = await unlockVault(target, passphrase)
114141

115142
expect(result.status).toBe('unlocked')
116-
const engine = createEngine(vaultRoot, passphrase)
143+
const engine = engineFor(passphrase)
117144
expect(await engine.verifyIntegrityToken(writtenToken(webdav))).toBe(true)
118145
})
119146

@@ -175,7 +202,7 @@ describe('unlockVault', () => {
175202
{ extraProps: [INTEGRITY_ID_PROP] }
176203
)
177204
// The backfilled token has to verify under the passphrase we just used.
178-
const engine = createEngine(vaultRoot, passphrase)
205+
const engine = engineFor(passphrase)
179206
expect(await engine.verifyIntegrityToken(writtenToken(webdav))).toBe(true)
180207
})
181208

@@ -194,7 +221,7 @@ describe('unlockVault', () => {
194221
// catches it - without that, we would write a token for the wrong passphrase
195222
// and lock the real one out permanently.
196223
const { target, webdav } = await createTarget({ children: [{ name: encryptedChildName }] })
197-
const engine = createEngine(vaultRoot, 'definitely-wrong')
224+
const engine = engineFor('definitely-wrong')
198225
expect(await engine.verifySegment(encryptedChildName)).toBe(true)
199226

200227
const result = await unlockVault(target, 'definitely-wrong')
@@ -285,6 +312,7 @@ describe('unlockVault', () => {
285312
it('still unlocks when the backfill is rejected', async () => {
286313
// A viewer on a shared vault or a public-link visitor cannot write
287314
// properties. The passphrase is verified by then, so keep them in.
315+
vi.spyOn(console, 'warn').mockImplementation(() => undefined)
288316
const { target, webdav } = await createTarget({ children: [{ name: encryptedChildName }] })
289317
webdav.setProperties.mockRejectedValue(new Error('403'))
290318

@@ -301,7 +329,7 @@ describe('unlockVault', () => {
301329
const result = await unlockVault(target, passphrase)
302330

303331
expect(result.status).toBe('unlocked')
304-
const engine = createEngine(vaultRoot, passphrase)
332+
const engine = engineFor(passphrase)
305333
expect(await engine.verifyIntegrityToken(writtenToken(webdav))).toBe(true)
306334
})
307335

packages/web-app-rclone-crypt/tests/unit/views/UnlockVault.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ describe('UnlockVault', () => {
136136
})
137137

138138
it('offers a retry when unlocking fails for any other reason', async () => {
139+
vi.spyOn(console, 'error').mockImplementation(() => undefined)
139140
const { wrapper, mocks, vaultStore } = await mountProbed()
140141
vi.mocked(unlockVault).mockRejectedValue(new Error('network'))
141142
await submit(wrapper)

0 commit comments

Comments
 (0)