1import { toByteArray } from 'base64-js'; 2import { UnavailabilityError } from 'expo-modules-core'; 3 4import ExpoRandom from './ExpoRandom'; 5 6const warnIsDeprecated = (functionName: string) => 7 console.warn( 8 `expo-random is deprecated in favor of expo-crypto: use ExpoCrypto.${functionName}()instead. https://docs.expo.dev/versions/latest/sdk/crypto/` 9 ); 10 11function assertByteCount(value: any, methodName: string): void { 12 warnIsDeprecated('assertByteCount'); 13 14 if ( 15 typeof value !== 'number' || 16 isNaN(value) || 17 Math.floor(value) < 0 || 18 Math.floor(value) > 1024 19 ) { 20 throw new TypeError( 21 `expo-random: ${methodName}(${value}) expected a valid number from range 0...1024` 22 ); 23 } 24} 25 26// @needsAudit 27/** 28 * Generates completely random bytes using native implementations. The `byteCount` property 29 * is a `number` indicating the number of bytes to generate in the form of a `Uint8Array`. 30 * Falls back to `Math.random` during development to prevent issues with React Native Debugger. 31 * @param byteCount - A number within the range from `0` to `1024`. Anything else will throw a `TypeError`. 32 * @return An array of random bytes with the same length as the `byteCount`. 33 */ 34export function getRandomBytes(byteCount: number): Uint8Array { 35 warnIsDeprecated('getRandomBytes'); 36 assertByteCount(byteCount, 'getRandomBytes'); 37 const validByteCount = Math.floor(byteCount); 38 if (__DEV__) { 39 if (!global.nativeCallSyncHook || global.__REMOTEDEV__) { 40 // remote javascript debugging is enabled 41 const array = new Uint8Array(validByteCount); 42 for (let i = 0; i < validByteCount; i++) { 43 array[i] = Math.floor(Math.random() * 256); 44 } 45 return array; 46 } 47 } 48 if (ExpoRandom.getRandomBytes) { 49 return ExpoRandom.getRandomBytes(validByteCount); 50 } else if (ExpoRandom.getRandomBase64String) { 51 const base64 = ExpoRandom.getRandomBase64String(validByteCount); 52 return toByteArray(base64); 53 } else { 54 throw new UnavailabilityError('expo-random', 'getRandomBytes'); 55 } 56} 57 58// @needsAudit 59/** 60 * Generates completely random bytes using native implementations. The `byteCount` property 61 * is a `number` indicating the number of bytes to generate in the form of a `Uint8Array`. 62 * @param byteCount - A number within the range from `0` to `1024`. Anything else will throw a `TypeError`. 63 * @return A promise that fulfills with an array of random bytes with the same length as the `byteCount`. 64 */ 65export async function getRandomBytesAsync(byteCount: number): Promise<Uint8Array> { 66 warnIsDeprecated('getRandomBytesAsync'); 67 assertByteCount(byteCount, 'getRandomBytesAsync'); 68 const validByteCount = Math.floor(byteCount); 69 if (ExpoRandom.getRandomBytesAsync) { 70 return await ExpoRandom.getRandomBytesAsync(validByteCount); 71 } else if (ExpoRandom.getRandomBase64StringAsync) { 72 const base64 = await ExpoRandom.getRandomBase64StringAsync(validByteCount); 73 return toByteArray(base64); 74 } else { 75 throw new UnavailabilityError('expo-random', 'getRandomBytesAsync'); 76 } 77} 78