|
16 | 16 | */ |
17 | 17 |
|
18 | 18 | import '../test/setup'; |
19 | | -import { writeTokenToStorage, readTokenFromStorage } from './storage'; |
| 19 | +import { |
| 20 | + writeTokenToStorage, |
| 21 | + readTokenFromStorage, |
| 22 | + readOrCreateDebugTokenFromStorage |
| 23 | +} from './storage'; |
20 | 24 | import * as indexeddbOperations from './indexeddb'; |
21 | 25 | import { getFakeApp } from '../test/util'; |
22 | 26 | import * as util from '@firebase/util'; |
23 | 27 | import { logger } from './logger'; |
24 | 28 | import { expect } from 'chai'; |
25 | | -import { stub } from 'sinon'; |
| 29 | +import { spy, stub } from 'sinon'; |
| 30 | +import { assert } from 'console'; |
26 | 31 |
|
27 | 32 | describe('Storage', () => { |
28 | 33 | const app = getFakeApp(); |
@@ -67,4 +72,55 @@ describe('Storage', () => { |
67 | 72 | expect(warnStub.args[0][0]).to.include('something went wrong!'); |
68 | 73 | warnStub.restore(); |
69 | 74 | }); |
| 75 | + |
| 76 | + describe('readOrCreateDebugTokenFromStorage', () => { |
| 77 | + it('returns the existing token when it exists in IndexedDB', async () => { |
| 78 | + stub(indexeddbOperations, 'readDebugTokenFromIndexedDB').resolves( |
| 79 | + 'existing-token' |
| 80 | + ); |
| 81 | + stub(indexeddbOperations, 'writeDebugTokenToIndexedDB').resolves(); |
| 82 | + const mathRandomSpy = spy(Math, 'random'); |
| 83 | + const randomUUIDSpy = spy(self.crypto, 'randomUUID'); |
| 84 | + |
| 85 | + const token = await readOrCreateDebugTokenFromStorage(); |
| 86 | + expect(token).to.equal('existing-token'); |
| 87 | + |
| 88 | + expect(randomUUIDSpy).to.not.have.been.called; |
| 89 | + expect(mathRandomSpy).to.not.have.been.called; |
| 90 | + }); |
| 91 | + |
| 92 | + it('does not fall back to Math.random when crypto.randomUUID exists', async () => { |
| 93 | + stub(indexeddbOperations, 'readDebugTokenFromIndexedDB').resolves( |
| 94 | + undefined |
| 95 | + ); |
| 96 | + stub(indexeddbOperations, 'writeDebugTokenToIndexedDB').resolves(); |
| 97 | + const mathRandomSpy = spy(Math, 'random'); |
| 98 | + const randomUUIDSpy = spy(self.crypto, 'randomUUID'); |
| 99 | + |
| 100 | + assert(typeof crypto.randomUUID !== 'undefined'); |
| 101 | + |
| 102 | + await readOrCreateDebugTokenFromStorage(); |
| 103 | + |
| 104 | + // Verify the correct generator was used and the fallback was not |
| 105 | + expect(randomUUIDSpy).to.have.been.called; |
| 106 | + expect(mathRandomSpy).to.not.have.been.called; |
| 107 | + }); |
| 108 | + |
| 109 | + it('falls back to non-cryptographically secure UUID generator if crypto.randomUUID() is undefined', async () => { |
| 110 | + stub(indexeddbOperations, 'readDebugTokenFromIndexedDB').resolves( |
| 111 | + undefined |
| 112 | + ); |
| 113 | + stub(indexeddbOperations, 'writeDebugTokenToIndexedDB').resolves(); |
| 114 | + stub(self.crypto, 'randomUUID').value(undefined); |
| 115 | + const mathRandomSpy = spy(Math, 'random'); |
| 116 | + const logSpy = spy(logger, 'warn'); |
| 117 | + |
| 118 | + await readOrCreateDebugTokenFromStorage(); |
| 119 | + |
| 120 | + expect(mathRandomSpy.called).to.be.true; |
| 121 | + expect(logSpy).to.have.been.calledWith( |
| 122 | + `crypto.randomUUID() was undefined. This happens in non secure contexts. Falling back to non-cryptographically secure UUID generator.` |
| 123 | + ); |
| 124 | + }); |
| 125 | + }); |
70 | 126 | }); |
0 commit comments