-
Notifications
You must be signed in to change notification settings - Fork 929
Reland "Use crypo RNG for auto ID generation to reduce conflicts (#2764)" #3012
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
867417c
a2b89c2
02592ec
17b6bc5
ea4967a
434e650
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,7 @@ import { Platform } from '../platform/platform'; | |
import { Connection } from '../remote/connection'; | ||
import { JsonProtoSerializer } from '../remote/serializer'; | ||
import { ConnectivityMonitor } from './../remote/connectivity_monitor'; | ||
|
||
import { NoopConnectivityMonitor } from '../remote/connectivity_monitor_noop'; | ||
import { BrowserConnectivityMonitor } from './browser_connectivity_monitor'; | ||
import { WebChannelConnection } from './webchannel_connection'; | ||
|
@@ -72,4 +73,27 @@ export class BrowserPlatform implements Platform { | |
btoa(raw: string): string { | ||
return btoa(raw); | ||
} | ||
|
||
randomBytes(nBytes: number): Uint8Array { | ||
if (nBytes <= 0) { | ||
return new Uint8Array(); | ||
} | ||
|
||
// Polyfill for IE and WebWorker | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you improve this comment to explain how it affects the reader? Is the polyfill being done by the code block that follows? Or is it instructing the reader to perform some polyfilling? Consider re-writing this comment as a sentence that would be either clearly informative or clearly actionable by the reader. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
// eslint-disable-next-line no-restricted-globals | ||
const crypto = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We might also consider adding support for this shim on ReactNative: https://stackoverflow.com/questions/45301900/howto-patch-shim-crypto-getrandomvalues-for-react-native While the fallback will make sure these environments don't break, we can possibly extend our support for Edit: I missed that you added There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So we don't need it, right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am ok with not adding support for ReactNative until the ReactNative Firebase wrapper bundles "crypto", but note that without getting "crypto" from globals, we will always fall back to Math.random() for RN. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, I am filing a ticket to get crypto added for react native firestore. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. react-native-firebase participant here, just cross-linking invertase/react-native-firebase#3618 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just thought I'd quickly summerize; React Native Firebase doesn't use the JS SDK, we're a thin JS wrapper around the native Android & iOS SDKs so this change has no direct affect on us. However our JS wrapper does use an identical random id generator - so I think we may need to port this change across in some form - we'll pick this up separately, thanks! |
||
(this.window && | ||
(this.window.crypto || (this.window as any)['msCrypto'])) || | ||
(self && self.crypto); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. According to https://developer.mozilla.org/en-US/docs/Web/API/Window/self, you can just write:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
const v = new Uint8Array(nBytes); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: Consider a more meaningful name than There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
if (!!crypto) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this double exclamation mark intentional? If not, you may want to add a unit test that would fail if Math.random() is used unintentionally. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can probably just be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
crypto.getRandomValues(v); | ||
} else { | ||
// Falls back to Math.random | ||
for (let i = 0; i < nBytes; i++) { | ||
v[i] = Math.floor(Math.random() * 256); | ||
} | ||
} | ||
return v; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,7 @@ | |
*/ | ||
|
||
import { debugAssert } from './assert'; | ||
import { PlatformSupport } from '../platform/platform'; | ||
|
||
export type EventHandler<E> = (value: E) => void; | ||
export interface Indexable { | ||
|
@@ -28,8 +29,17 @@ export class AutoId { | |
const chars = | ||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; | ||
let autoId = ''; | ||
for (let i = 0; i < 20; i++) { | ||
autoId += chars.charAt(Math.floor(Math.random() * chars.length)); | ||
while (autoId.length < 20) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider re-writing this loop as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rewrote the section to reduce hardcoding numbers. |
||
const bytes = PlatformSupport.getPlatform().randomBytes(40); | ||
for (const b of Array.from(bytes)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: You can save one copy here if you do a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
// Length of `chars` is 62. We only take bytes between 0 and 62*4-1 | ||
// (both inclusive). The value is then evenly mapped to indices of `char` | ||
// via a modulo operation. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm assuming this logic is used to ensure an even distribution between all of the characters in |
||
const maxValue = 62 * 4 - 1; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider moving the calculation of maxValue to immediately follow the declaration of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hardcoding const chars = '...';
const maxValue = chars.length * 4 - 1;
debugAssert(maxValue < 256); Then the hardcoded value of |
||
if (autoId.length < 20 && b <= maxValue) { | ||
autoId += chars.charAt(b % 62); | ||
} | ||
} | ||
} | ||
debugAssert(autoId.length === 20, 'Invalid auto ID: ' + autoId); | ||
return autoId; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the rationale for accepting negative numbers? This seems like it may be hiding bugs in the calling code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed it to validate input, and reject anything <=0.