-
Notifications
You must be signed in to change notification settings - Fork 929
Use crypo RNG for auto ID generation to reduce conflicts. #2764
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 1 commit
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 |
---|---|---|
|
@@ -43,6 +43,12 @@ export interface Platform { | |
/** Converts a binary string to a Base64 encoded string. */ | ||
btoa(raw: string): string; | ||
|
||
/** | ||
* Generates a random byte `b` with `0 <= b <= max`. If `max` is negative, | ||
* it is the same as setting it to byte max (255). | ||
*/ | ||
randomByte(max: number): number; | ||
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. The platforms both provide ways to get an array of random bytes. It's better to keep this interface structured in terms of exposing common platform primitives and than we can implement any derived concerns (like limiting to a max value just once). Concretely, I think this should 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. |
||
|
||
/** The Platform's 'window' implementation or null if not available. */ | ||
readonly window: Window | null; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,20 +16,26 @@ | |
*/ | ||
|
||
import { assert } from './assert'; | ||
import { Platform } from '../platform/platform'; | ||
|
||
export type EventHandler<E> = (value: E) => void; | ||
export interface Indexable { | ||
[k: string]: unknown; | ||
} | ||
|
||
export class AutoId { | ||
static newId(): string { | ||
static newId(platform: Platform): string { | ||
// Alphanumeric characters | ||
const chars = | ||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; | ||
let autoId = ''; | ||
for (let i = 0; i < 20; i++) { | ||
autoId += chars.charAt(Math.floor(Math.random() * chars.length)); | ||
// Length of `chars` is 62. We generate random values between 0 and 247. | ||
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. Mark this explicitly inclusive. Usually "between" implies one or both end points are excluded from the set. That is, use "Random values between 0 and 247 (inclusive)." 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. |
||
// Each value maps to an 4-element interval of `chars`, for example: | ||
// 0..3 -> 0, 4..7 -> 1, etc. This ensures a uniform distribution of | ||
// probability for all candidates. | ||
const v = platform.randomByte(247); | ||
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. A possible improvement here is to request 20-40 random bytes at a time from 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. |
||
autoId += chars.charAt(Math.floor(v / 4)); | ||
} | ||
assert(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.
AutoId.newId
should just callPlatformSupport.getPlatform()
for itself. If you need a version of this that takes the platform as an argument for testing, it's fine to haveAutoId.newId()
delegate to that version. We shouldn't have to update all callers to fix this.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.
Done.