diff --git a/android/app/src/main/java/com/mattermost/helpers/RandomId.kt b/android/app/src/main/java/com/mattermost/helpers/RandomId.kt index 7795d0a29..67489eff6 100644 --- a/android/app/src/main/java/com/mattermost/helpers/RandomId.kt +++ b/android/app/src/main/java/com/mattermost/helpers/RandomId.kt @@ -1,6 +1,6 @@ package com.mattermost.helpers -import kotlin.math.floor +import java.util.UUID class RandomId { companion object { @@ -9,14 +9,7 @@ class RandomId { private const val idLength = 16 fun generate(): String { - var id = "" - for (i in 1.rangeTo((idLength / 2))) { - val random = floor(Math.random() * alphabetLength * alphabetLength) - id += alphabet[floor(random / alphabetLength).toInt()] - id += alphabet[(random % alphabetLength).toInt()] - } - - return id + return UUID.randomUUID().toString() } } } diff --git a/app/components/formatted_text/index.tsx b/app/components/formatted_text/index.tsx index 2114fdaa6..fd8f335aa 100644 --- a/app/components/formatted_text/index.tsx +++ b/app/components/formatted_text/index.tsx @@ -5,6 +5,8 @@ import {createElement, isValidElement} from 'react'; import {useIntl} from 'react-intl'; import {type StyleProp, Text, type TextProps, type TextStyle} from 'react-native'; +import {generateId} from '@utils/general'; + type FormattedTextProps = TextProps & { id: string; defaultMessage?: string; @@ -24,7 +26,7 @@ const FormattedText = (props: FormattedTextProps) => { if (values && Object.keys(values).length > 0) { // Creates a token with a random UID that should not be guessable or // conflict with other parts of the `message` string. - const uid = Math.floor(Math.random() * 0x10000000000).toString(16); + const uid = generateId(); const generateToken = (() => { let counter = 0; diff --git a/app/utils/general/index.ts b/app/utils/general/index.ts index 3a42dea9d..4b9ea98af 100644 --- a/app/utils/general/index.ts +++ b/app/utils/general/index.ts @@ -2,6 +2,7 @@ // See LICENSE.txt for license information. import {applicationId} from 'expo-application'; +import {randomUUID} from 'expo-crypto'; import {createIntl} from 'react-intl'; import ReactNativeHapticFeedback, {HapticFeedbackTypes} from 'react-native-haptic-feedback'; @@ -25,22 +26,7 @@ export function emptyFunction(..._args: any[]) { // Generates a RFC-4122 version 4 compliant globally unique identifier. export const generateId = (prefix?: string): string => { - // implementation taken from http://stackoverflow.com/a/2117523 - let id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'; - id = id.replace(/[xy]/g, (c) => { - const r = Math.floor(Math.random() * 16); - let v; - - if (c === 'x') { - v = r; - } else { - // eslint-disable-next-line no-mixed-operators - v = (r & 0x3) | 0x8; - } - - return v.toString(16); - }); - + const id = randomUUID(); if (prefix) { return `${prefix}-${id}`; } diff --git a/ios/Gekidou/Sources/Gekidou/Storage/Database.swift b/ios/Gekidou/Sources/Gekidou/Storage/Database.swift index 1caf68c4a..49f30c930 100644 --- a/ios/Gekidou/Sources/Gekidou/Storage/Database.swift +++ b/ios/Gekidou/Sources/Gekidou/Storage/Database.swift @@ -87,20 +87,7 @@ public class Database: NSObject { } public func generateId() -> String { - let alphabet = Array("0123456789abcdefghijklmnopqrstuvwxyz") - let alphabetLenght = alphabet.count - let idLenght = 16 - var id = "" - - for _ in 1...(idLenght / 2) { - let random = floor(Double.random(in: 0..<1) * Double(alphabetLenght) * Double(alphabetLenght)) - let firstIndex = Int(floor(random / Double(alphabetLenght))) - let lastIndex = Int(random) % alphabetLenght - id += String(alphabet[firstIndex]) - id += String(alphabet[lastIndex]) - } - - return id + return UUID().uuidString.lowercased() } public func getOnlyServerUrl() throws -> String { diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 6b3190003..e564e2462 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -11,6 +11,8 @@ PODS: - ExpoModulesCore - Expo (51.0.14): - ExpoModulesCore + - ExpoCrypto (13.0.2): + - ExpoModulesCore - ExpoDevice (6.0.2): - ExpoModulesCore - ExpoFileSystem (17.0.1): @@ -1645,6 +1647,7 @@ DEPENDENCIES: - EXApplication (from `../node_modules/expo-application/ios`) - EXConstants (from `../node_modules/expo-constants/ios`) - Expo (from `../node_modules/expo`) + - ExpoCrypto (from `../node_modules/expo-crypto/ios`) - ExpoDevice (from `../node_modules/expo-device/ios`) - ExpoFileSystem (from `../node_modules/expo-file-system/ios`) - ExpoImage (from `../node_modules/expo-image/ios`) @@ -1775,6 +1778,8 @@ EXTERNAL SOURCES: :path: "../node_modules/expo-constants/ios" Expo: :path: "../node_modules/expo" + ExpoCrypto: + :path: "../node_modules/expo-crypto/ios" ExpoDevice: :path: "../node_modules/expo-device/ios" ExpoFileSystem: @@ -1981,6 +1986,7 @@ SPEC CHECKSUMS: EXApplication: c08200c34daca7af7fd76ac4b9d606077410e8ad EXConstants: 409690fbfd5afea964e5e9d6c4eb2c2b59222c59 Expo: 9c87c876b45a6934894ba5e9353ee94fdba48125 + ExpoCrypto: 156078f266bf28f80ecf5e2a9c3a0d6ffce07a1c ExpoDevice: fc94f0e42ecdfd897e7590f2874fc64dfa7e9b1c ExpoFileSystem: 80bfe850b1f9922c16905822ecbf97acd711dc51 ExpoImage: 2ccccff1219ebc765e344f3338f2430af2df4824 @@ -1992,7 +1998,7 @@ SPEC CHECKSUMS: FBLazyVector: 4bc164e5b5e6cfc288d2b5ff28643ea15fa1a589 fmt: 4c2741a687cc09f0634a2e2c72a838b99f1ff120 glog: fdfdfe5479092de0c4bdbebedd9056951f092c4f - hermes-engine: 49d04e119f7241031cb4718f6bdea0a536c0ddd9 + hermes-engine: 01d3e052018c2a13937aca1860fbedbccd4a41b7 HMSegmentedControl: 34c1f54d822d8308e7b24f5d901ec674dfa31352 JitsiWebRTC: 37fb2fb70d42cac58c06948527a5f9e1b3f50812 libavif: 84bbb62fb232c3018d6f1bab79beea87e35de7b7 diff --git a/package-lock.json b/package-lock.json index c8a9e7162..23aef6ae4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,6 +49,7 @@ "emoji-regex": "10.3.0", "expo": "51.0.14", "expo-application": "5.9.1", + "expo-crypto": "~13.0.2", "expo-device": "6.0.2", "expo-image": "1.12.12", "expo-linear-gradient": "13.0.2", @@ -13914,6 +13915,17 @@ "expo": "*" } }, + "node_modules/expo-crypto": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/expo-crypto/-/expo-crypto-13.0.2.tgz", + "integrity": "sha512-7f/IMPYJZkBM21LNEMXGrNo/0uXSVfZTwufUdpNKedJR0fm5fH4DCSN79ZddlV26nF90PuXjK2inIbI6lb0qRA==", + "dependencies": { + "base64-js": "^1.3.0" + }, + "peerDependencies": { + "expo": "*" + } + }, "node_modules/expo-device": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/expo-device/-/expo-device-6.0.2.tgz", diff --git a/package.json b/package.json index 35bf7804d..dbfb7f422 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "emoji-regex": "10.3.0", "expo": "51.0.14", "expo-application": "5.9.1", + "expo-crypto": "13.0.2", "expo-device": "6.0.2", "expo-image": "1.12.12", "expo-linear-gradient": "13.0.2", diff --git a/test/test_helper.ts b/test/test_helper.ts index 0439a1177..e39a4e587 100644 --- a/test/test_helper.ts +++ b/test/test_helper.ts @@ -15,7 +15,6 @@ import {SYSTEM_IDENTIFIERS} from '@constants/database'; import {PUSH_PROXY_STATUS_VERIFIED} from '@constants/push_proxy'; import DatabaseManager from '@database/manager'; import {prepareCommonSystemValues} from '@queries/servers/system'; -import {generateId} from '@utils/general'; import type {APIClientInterface} from '@mattermost/react-native-network-client'; @@ -134,7 +133,23 @@ class TestHelper { }; generateId = () => { - return generateId(); + // implementation taken from http://stackoverflow.com/a/2117523 + let id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'; + id = id.replace(/[xy]/g, (c) => { + const r = Math.floor(Math.random() * 16); + let v; + + if (c === 'x') { + v = r; + } else { + // eslint-disable-next-line no-mixed-operators + v = (r & 0x3) | 0x8; + } + + return v.toString(16); + }); + + return id; }; createClient = () => {