Skip to content

Commit e35a0fb

Browse files
chore: revert recent breaking IE11 changes (#1648)
1 parent 870faf0 commit e35a0fb

9 files changed

Lines changed: 250 additions & 8 deletions

File tree

.github/workflows/shared-ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
strategy:
2323
fail-fast: false
2424
matrix:
25-
node-version: ['22.x', '24.x', 'latest']
25+
node-version: ['18.x', '20.x', '22.x', '24.x', 'latest']
2626
test-type: ['node', 'browser']
2727
# Determine test categories based on whether testing published packages or source code:
2828
# - Testing published packages: only run vector tests (don't have build artifacts to test coverage or compliance)

modules/web-crypto-backend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
},
2020
"license": "Apache-2.0",
2121
"dependencies": {
22+
"@aws-crypto/ie11-detection": "4.0.0",
2223
"@aws-crypto/supports-web-crypto": "5.2.0",
2324
"@aws-sdk/util-locate-window": "3.310.0",
2425
"tslib": "^2.2.0"

modules/web-crypto-backend/src/backend-factory.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4+
import { isMsWindow } from '@aws-crypto/ie11-detection'
45
import {
56
supportsWebCrypto,
67
supportsSubtleCrypto,
78
supportsZeroByteGCM,
89
} from '@aws-crypto/supports-web-crypto'
910
import { generateSynchronousRandomValues } from './synchronous_random_values'
11+
import promisifyMsSubtleCrypto from './promisify-ms-crypto'
1012

1113
type MaybeSubtleCrypto = SubtleCrypto | false
1214
export type WebCryptoBackend =
@@ -138,6 +140,7 @@ export function pluckSubtleCrypto(window: Window): MaybeSubtleCrypto {
138140
// if needed webkitSubtle check should be added here
139141
// see: https://webkit.org/blog/7790/update-on-web-cryptography/
140142
if (supportsWebCrypto(window)) return window.crypto.subtle
143+
if (isMsWindow(window)) return promisifyMsSubtleCrypto(window.msCrypto.subtle)
141144
return false
142145
}
143146

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { MsSubtleCrypto } from '@aws-crypto/ie11-detection'
5+
6+
type MsSubtleFunctions = keyof MsSubtleCrypto
7+
8+
export default function promisifyMsSubtleCrypto(backend: MsSubtleCrypto) {
9+
const usages: MsSubtleFunctions[] = [
10+
'decrypt',
11+
'digest',
12+
'encrypt',
13+
'exportKey',
14+
'generateKey',
15+
'importKey',
16+
'sign',
17+
'verify',
18+
]
19+
const decorateUsage = (fakeBackend: any, usage: MsSubtleFunctions) =>
20+
decorate(backend, fakeBackend, usage)
21+
return usages.reduce(decorateUsage, {}) as SubtleCrypto
22+
}
23+
24+
function decorate(
25+
subtle: MsSubtleCrypto,
26+
fakeBackend: any,
27+
name: MsSubtleFunctions
28+
) {
29+
fakeBackend[name] = async (...args: any[]) => {
30+
return new Promise((resolve, reject) => {
31+
// @ts-ignore
32+
const operation = subtle[name](...args)
33+
operation.oncomplete = () => resolve(operation.result)
34+
operation.onerror = reject
35+
})
36+
}
37+
return fakeBackend
38+
}

modules/web-crypto-backend/src/synchronous_random_values.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4+
import { isMsWindow } from '@aws-crypto/ie11-detection'
45
import { supportsSecureRandom } from '@aws-crypto/supports-web-crypto'
56
import { locateWindow } from '@aws-sdk/util-locate-window'
67

@@ -18,6 +19,10 @@ export function generateSynchronousRandomValues(
1819
return function synchronousRandomValues(byteLength: number): Uint8Array {
1920
if (supportsSecureRandom(globalScope)) {
2021
return globalScope.crypto.getRandomValues(new Uint8Array(byteLength))
22+
} else if (isMsWindow(globalScope)) {
23+
const values = new Uint8Array(byteLength)
24+
globalScope.msCrypto.getRandomValues(values)
25+
return values
2126
}
2227

2328
throw new Error(`Unable to locate a secure random source.`)

modules/web-crypto-backend/test/fixtures.ts

Lines changed: 143 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,7 @@
33

44
export const fakeWindowWebCryptoSupportsZeroByteGCM: Window = {
55
crypto: {
6-
getRandomValues: (array: Uint8Array) => {
7-
for (let i = 0; i < array.length; i++) {
8-
array[i] = Math.floor(Math.random() * 256)
9-
}
10-
return array
11-
},
6+
getRandomValues: () => {},
127
subtle: {
138
async decrypt() {
149
return {} as any
@@ -147,3 +142,145 @@ export const subtleFallbackZeroByteEncryptFail = {
147142
} as any
148143

149144
export const subtleFallbackNoWebCrypto = {} as any
145+
146+
export const fakeWindowIE11OnComplete = {
147+
msCrypto: {
148+
getRandomValues: (values: Uint8Array) => {
149+
return values.fill(1)
150+
},
151+
subtle: {
152+
decrypt() {
153+
const obj = {} as any
154+
setTimeout(() => {
155+
obj.result = true
156+
obj.oncomplete()
157+
})
158+
return obj
159+
},
160+
digest() {
161+
const obj = {} as any
162+
setTimeout(() => {
163+
obj.result = true
164+
obj.oncomplete()
165+
})
166+
return obj
167+
},
168+
encrypt() {
169+
const obj = {} as any
170+
setTimeout(() => {
171+
obj.result = true
172+
obj.oncomplete()
173+
})
174+
return obj
175+
},
176+
exportKey() {
177+
const obj = {} as any
178+
setTimeout(() => {
179+
obj.result = true
180+
obj.oncomplete()
181+
})
182+
return obj
183+
},
184+
generateKey() {
185+
const obj = {} as any
186+
setTimeout(() => {
187+
obj.result = true
188+
obj.oncomplete()
189+
})
190+
return obj
191+
},
192+
importKey() {
193+
const obj = {} as any
194+
setTimeout(() => {
195+
obj.result = true
196+
obj.oncomplete()
197+
})
198+
return obj
199+
},
200+
sign() {
201+
const obj = {} as any
202+
setTimeout(() => {
203+
obj.result = true
204+
obj.oncomplete()
205+
})
206+
return obj
207+
},
208+
verify() {
209+
const obj = {} as any
210+
setTimeout(() => {
211+
obj.result = true
212+
obj.oncomplete()
213+
})
214+
return obj
215+
},
216+
},
217+
},
218+
MSInputMethodContext: {} as any,
219+
} as any
220+
221+
export const fakeWindowIE11OnError = {
222+
msCrypto: {
223+
getRandomValues: (values: Uint8Array) => {
224+
return values.fill(1)
225+
},
226+
subtle: {
227+
decrypt() {
228+
const obj = {} as any
229+
setTimeout(() => {
230+
obj.onerror(new Error('stub error'))
231+
})
232+
return obj
233+
},
234+
digest() {
235+
const obj = {} as any
236+
setTimeout(() => {
237+
obj.onerror(new Error('stub error'))
238+
})
239+
return obj
240+
},
241+
encrypt() {
242+
const obj = {} as any
243+
setTimeout(() => {
244+
obj.onerror(new Error('stub error'))
245+
})
246+
return obj
247+
},
248+
exportKey() {
249+
const obj = {} as any
250+
setTimeout(() => {
251+
obj.onerror(new Error('stub error'))
252+
})
253+
return obj
254+
},
255+
generateKey() {
256+
const obj = {} as any
257+
setTimeout(() => {
258+
obj.onerror(new Error('stub error'))
259+
})
260+
return obj
261+
},
262+
importKey() {
263+
const obj = {} as any
264+
setTimeout(() => {
265+
obj.onerror(new Error('stub error'))
266+
})
267+
return obj
268+
},
269+
sign() {
270+
const obj = {} as any
271+
setTimeout(() => {
272+
obj.onerror(new Error('stub error'))
273+
})
274+
return obj
275+
},
276+
verify() {
277+
const obj = {} as any
278+
setTimeout(() => {
279+
obj.onerror(new Error('stub error'))
280+
})
281+
return obj
282+
},
283+
},
284+
},
285+
MSInputMethodContext: {} as any,
286+
} as any
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
/* eslint-env mocha */
5+
6+
import * as chai from 'chai'
7+
import chaiAsPromised from 'chai-as-promised'
8+
import promisifyMsSubtleCrypto from '../src/promisify-ms-crypto'
9+
import * as fixtures from './fixtures'
10+
11+
chai.use(chaiAsPromised)
12+
const { expect } = chai
13+
14+
/* These tests are very simple
15+
* I am not testing every subtle function
16+
* because the promisify code is all the same.
17+
*/
18+
describe('promisifyMsSubtleCrypto', () => {
19+
const backendComplete = promisifyMsSubtleCrypto(
20+
fixtures.fakeWindowIE11OnComplete.msCrypto.subtle
21+
)
22+
const backendError = promisifyMsSubtleCrypto(
23+
fixtures.fakeWindowIE11OnError.msCrypto.subtle
24+
)
25+
26+
it('backendComplete:decrypt', async () => {
27+
// @ts-ignore These methods are stubs, ignore ts errors
28+
const test = await backendComplete.decrypt()
29+
expect(test).to.equal(true)
30+
})
31+
32+
it('backendError:decrypt', async () => {
33+
// @ts-ignore These methods are stubs, ignore ts errors
34+
await expect(backendError.decrypt()).to.rejectedWith(Error)
35+
})
36+
})

modules/web-crypto-backend/test/synchronous_random_values.test.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,25 @@
55

66
import { expect } from 'chai'
77
import { generateSynchronousRandomValues } from '../src/synchronous_random_values'
8+
import { synchronousRandomValues } from '../src/index'
89
import * as fixtures from './fixtures'
910

1011
describe('synchronousRandomValues', () => {
1112
it('should return random values', () => {
13+
const test = synchronousRandomValues(5)
14+
expect(test).to.be.instanceOf(Uint8Array)
15+
expect(test).lengthOf(5)
16+
})
17+
18+
it('should return msCrypto random values', () => {
1219
const synchronousRandomValues = generateSynchronousRandomValues(
13-
fixtures.fakeWindowWebCryptoSupportsZeroByteGCM
20+
fixtures.fakeWindowIE11OnComplete
1421
)
22+
1523
const test = synchronousRandomValues(5)
1624
expect(test).to.be.instanceOf(Uint8Array)
1725
expect(test).lengthOf(5)
26+
// The random is a stub, so I know the value
27+
expect(test).to.deep.equal(new Uint8Array(5).fill(1))
1828
})
1929
})

package-lock.json

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)