Skip to content

Commit 45a987d

Browse files
[2.x] Fix multi byte strings in history encryption + test (#2030)
* fix multi byte strings in history encryption + test * react + svelte tests for multi byte encryption
1 parent 0a5e309 commit 45a987d

File tree

6 files changed

+37
-6
lines changed

6 files changed

+37
-6
lines changed

packages/core/src/encryption.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,17 @@ const encryptData = async (iv: Uint8Array, key: CryptoKey, data: any) => {
4747

4848
const textEncoder = new TextEncoder()
4949
const str = JSON.stringify(data)
50-
const encoded = new Uint8Array(str.length)
50+
const encoded = new Uint8Array(str.length * 3)
5151

52-
textEncoder.encodeInto(str, encoded)
52+
const result = textEncoder.encodeInto(str, encoded)
5353

5454
return window.crypto.subtle.encrypt(
5555
{
5656
name: 'AES-GCM',
5757
iv,
5858
},
5959
key,
60-
encoded,
60+
encoded.subarray(0, result.written),
6161
)
6262
}
6363

packages/react/test-app/Pages/History/Page.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Link, router } from '@inertiajs/react'
22

3-
export default ({ pageNumber }) => {
3+
export default ({ pageNumber, multiByte }) => {
44
const clearHistory = () => {
55
router.clearHistory()
66
}
@@ -11,10 +11,12 @@ export default ({ pageNumber }) => {
1111
<Link href="/history/2">Page 2</Link>
1212
<Link href="/history/3">Page 3</Link>
1313
<Link href="/history/4">Page 4</Link>
14+
<Link href="/history/5">Page 5</Link>
1415

1516
<button onClick={clearHistory}>Clear History</button>
1617

1718
<div>This is page {pageNumber}.</div>
19+
<div>Multi byte character: {multiByte}</div>
1820
</>
1921
)
2022
}

packages/svelte/test-app/Pages/History/Page.svelte

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22
import { inertia, router } from '@inertiajs/svelte'
33
44
export let pageNumber
5+
export let multiByte
56
</script>
67

78
<a href="/history/1" use:inertia>Page 1</a>
89
<a href="/history/2" use:inertia>Page 2</a>
910
<a href="/history/3" use:inertia>Page 3</a>
1011
<a href="/history/4" use:inertia>Page 4</a>
12+
<a href="/history/5" use:inertia>Page 5</a>
1113

1214
<button on:click={() => router.clearHistory()}>Clear History</button>
1315

1416
<div>This is page {pageNumber}.</div>
17+
<div>Multi byte character: { multiByte }</div>
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
<script setup lang="ts">
22
import { Link, router } from '@inertiajs/vue3'
33
4-
defineProps<{ pageNumber: number }>()
4+
defineProps<{ pageNumber: number; multiByte: string }>()
55
</script>
66

77
<template>
88
<Link href="/history/1">Page 1</Link>
99
<Link href="/history/2">Page 2</Link>
1010
<Link href="/history/3">Page 3</Link>
1111
<Link href="/history/4">Page 4</Link>
12+
<Link href="/history/5">Page 5</Link>
1213

1314
<button @click="router.clearHistory()">Clear History</button>
1415

1516
<div>This is page {{ pageNumber }}.</div>
17+
<div>Multi byte character: {{ multiByte }}</div>
1618
</template>

tests/app/server.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,8 +215,9 @@ app.get('/history/:pageNumber', (req, res) => {
215215
component: 'History/Page',
216216
props: {
217217
pageNumber: req.params.pageNumber,
218+
multiByte: req.params.pageNumber === '5' ? '😃' : 'n/a',
218219
},
219-
encryptHistory: req.params.pageNumber === '3',
220+
encryptHistory: req.params.pageNumber === '3' || req.params.pageNumber === '5',
220221
clearHistory: req.params.pageNumber === '4',
221222
})
222223
})

tests/history.spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,26 @@ test('history can be cleared via props', async ({ page }) => {
109109
await page.waitForURL('/history/3')
110110
await expect(requests.requests).toHaveLength(1)
111111
})
112+
113+
test('multi byte strings can be encrypyed', async ({ page }) => {
114+
await clickAndWaitForResponse(page, 'Page 5', '/history/5')
115+
const historyState5 = await page.evaluate(() => window.history.state)
116+
// When history is encrypted, the page is an ArrayBuffer,
117+
// but Playwright doesn't transfer it as such over the wire (page.evaluate),
118+
// so if the object is "empty" and the page check below works, it's working.
119+
await expect(historyState5.page).toEqual({})
120+
await expect(historyState5.timestamp).toBeGreaterThan(0)
121+
await expect(page.getByText('Multi byte character: 😃')).toBeVisible()
122+
123+
await clickAndWaitForResponse(page, 'Page 1', '/history/1')
124+
125+
await expect(page.getByText('Multi byte character: n/a')).toBeVisible()
126+
127+
requests.listen(page)
128+
129+
await page.goBack()
130+
await page.waitForURL('/history/5')
131+
await expect(page.getByText('This is page 5')).toBeVisible()
132+
await expect(requests.requests).toHaveLength(0)
133+
await expect(page.getByText('Multi byte character: 😃')).toBeVisible()
134+
})

0 commit comments

Comments
 (0)