Skip to content

Commit 5dc25f4

Browse files
authored
chore: adjust precomputed assignments export for node environment (#190)
* Change getPrecomputedAssignments obfuscated default because the precomputed client is hard coded to expect an obfuscated input * Import crypto for node environment * v4.8.0-alpha.1 * Add react-native-get-random-values
1 parent 65986fe commit 5dc25f4

File tree

9 files changed

+61
-10
lines changed

9 files changed

+61
-10
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@eppo/js-client-sdk-common",
3-
"version": "4.8.0-alpha.0",
3+
"version": "4.8.0-alpha.1",
44
"description": "Common library for Eppo JavaScript SDKs (web, react native, and node)",
55
"main": "dist/index.js",
66
"files": [
@@ -73,6 +73,7 @@
7373
"buffer": "npm:@eppo/[email protected]",
7474
"js-base64": "^3.7.7",
7575
"pino": "^9.5.0",
76+
"react-native-get-random-values": "^1.11.0",
7677
"semver": "^7.5.4",
7778
"spark-md5": "^3.0.2",
7879
"uuid": "^8.3.2"

src/client/eppo-client.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ describe('EppoClient E2E test', () => {
214214
});
215215

216216
it('skips disabled flags', () => {
217-
const encodedPrecomputedWire = client.getPrecomputedAssignments('subject', {});
217+
const encodedPrecomputedWire = client.getPrecomputedAssignments('subject', {}, false);
218218
const { precomputed } = JSON.parse(encodedPrecomputedWire) as IConfigurationWire;
219219
if (!precomputed) {
220220
fail('Precomputed data not in Configuration response');
@@ -229,7 +229,7 @@ describe('EppoClient E2E test', () => {
229229
});
230230

231231
it('evaluates and returns assignments', () => {
232-
const encodedPrecomputedWire = client.getPrecomputedAssignments('subject', {});
232+
const encodedPrecomputedWire = client.getPrecomputedAssignments('subject', {}, false);
233233
const { precomputed } = JSON.parse(encodedPrecomputedWire) as IConfigurationWire;
234234
if (!precomputed) {
235235
fail('Precomputed data not in Configuration response');
@@ -248,7 +248,7 @@ describe('EppoClient E2E test', () => {
248248
// Use a known salt to produce deterministic hashes
249249
setSaltOverrideForTests(new Uint8Array([7, 53, 17, 78]));
250250

251-
const encodedPrecomputedWire = client.getPrecomputedAssignments('subject', {}, true);
251+
const encodedPrecomputedWire = client.getPrecomputedAssignments('subject', {});
252252
const { precomputed } = JSON.parse(encodedPrecomputedWire) as IConfigurationWire;
253253
if (!precomputed) {
254254
fail('Precomputed data not in Configuration response');

src/client/eppo-client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -871,7 +871,7 @@ export default class EppoClient {
871871
getPrecomputedAssignments(
872872
subjectKey: string,
873873
subjectAttributes: Attributes | ContextAttributes = {},
874-
obfuscated = false,
874+
obfuscated = true,
875875
): string {
876876
const configDetails = this.getConfigDetails();
877877

src/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
import { HybridConfigurationStore } from './configuration-store/hybrid.store';
3535
import { MemoryStore, MemoryOnlyConfigurationStore } from './configuration-store/memory.store';
3636
import * as constants from './constants';
37+
import { decodePrecomputedFlag } from './decoding';
3738
import BatchEventProcessor from './events/batch-event-processor';
3839
import { BoundedEventQueue } from './events/bounded-event-queue';
3940
import DefaultEventDispatcher, {
@@ -47,6 +48,7 @@ import NamedEventQueue from './events/named-event-queue';
4748
import NetworkStatusListener from './events/network-status-listener';
4849
import HttpClient from './http-client';
4950
import { PrecomputedFlag, Flag, ObfuscatedFlag, VariationType, FormatEnum } from './interfaces';
51+
import { setSaltOverrideForTests } from './obfuscation';
5052
import {
5153
AttributeType,
5254
Attributes,
@@ -125,4 +127,8 @@ export {
125127
IConfigurationWire,
126128
IPrecomputedConfigurationResponse,
127129
PrecomputedFlag,
130+
131+
// Test helpers
132+
setSaltOverrideForTests,
133+
decodePrecomputedFlag,
128134
};

src/obfuscation.ts

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,33 @@
11
import base64 = require('js-base64');
22
import * as SparkMD5 from 'spark-md5';
33

4+
import { logger } from './application-logger';
45
import { PrecomputedFlag } from './interfaces';
56

7+
// Import randomBytes according to the environment
8+
let getRandomValues: (length: number) => Uint8Array;
9+
if (typeof window !== 'undefined' && window.crypto) {
10+
// Browser environment
11+
getRandomValues = (length: number) => window.crypto.getRandomValues(new Uint8Array(length));
12+
} else if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {
13+
// React Native environment
14+
require('react-native-get-random-values');
15+
getRandomValues = (length: number) => {
16+
const array = new Uint8Array(length);
17+
return window.crypto.getRandomValues(array);
18+
};
19+
} else {
20+
// Node.js environment
21+
import('crypto')
22+
.then((crypto) => {
23+
getRandomValues = (length: number) => new Uint8Array(crypto.randomBytes(length));
24+
return;
25+
})
26+
.catch((error) => {
27+
logger.error('[Eppo SDK] Failed to load crypto module:', error);
28+
});
29+
}
30+
631
export function getMD5Hash(input: string, salt = ''): string {
732
return new SparkMD5().append(salt).append(input).end();
833
}
@@ -49,7 +74,5 @@ export function setSaltOverrideForTests(salt: Uint8Array | null) {
4974
}
5075

5176
export function generateSalt(length = 16): string {
52-
return base64.fromUint8Array(
53-
saltOverrideBytes ? saltOverrideBytes : crypto.getRandomValues(new Uint8Array(length)),
54-
);
77+
return base64.fromUint8Array(saltOverrideBytes ? saltOverrideBytes : getRandomValues(length));
5578
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
declare module 'react-native-get-random-values';

tsconfig.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
"outDir": "dist",
1010
"noImplicitAny": true,
1111
"strict": true,
12-
"strictPropertyInitialization": true
12+
"strictPropertyInitialization": true,
1313
},
14-
"include": ["src/**/*.ts"],
14+
"include": [
15+
"src/**/*.ts"
16+
],
1517
"exclude": [
1618
"node_modules",
1719
"dist",

webpack.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ module.exports = {
1919
},
2020
resolve: {
2121
extensions: ['.tsx', '.ts', '.js'],
22+
fallback: {
23+
crypto: false, // Exclude crypto module in the browser bundle
24+
},
25+
alias: {
26+
'react-native-get-random-values': false, // Ignore this module in non-React Native environments
27+
},
2228
},
2329
output: {
2430
filename: 'eppo-sdk.js',

yarn.lock

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2194,6 +2194,11 @@ expect@^29.0.0, expect@^29.7.0:
21942194
jest-message-util "^29.7.0"
21952195
jest-util "^29.7.0"
21962196

2197+
fast-base64-decode@^1.0.0:
2198+
version "1.0.0"
2199+
resolved "https://registry.yarnpkg.com/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz#b434a0dd7d92b12b43f26819300d2dafb83ee418"
2200+
integrity sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==
2201+
21972202
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
21982203
version "3.1.3"
21992204
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
@@ -3931,6 +3936,13 @@ react-is@^18.0.0:
39313936
resolved "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz"
39323937
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
39333938

3939+
react-native-get-random-values@^1.11.0:
3940+
version "1.11.0"
3941+
resolved "https://registry.yarnpkg.com/react-native-get-random-values/-/react-native-get-random-values-1.11.0.tgz#1ca70d1271f4b08af92958803b89dccbda78728d"
3942+
integrity sha512-4BTbDbRmS7iPdhYLRcz3PGFIpFJBwNZg9g42iwa2P6FOv9vZj/xJc678RZXnLNZzd0qd7Q3CCF6Yd+CU2eoXKQ==
3943+
dependencies:
3944+
fast-base64-decode "^1.0.0"
3945+
39343946
real-require@^0.2.0:
39353947
version "0.2.0"
39363948
resolved "https://registry.yarnpkg.com/real-require/-/real-require-0.2.0.tgz#209632dea1810be2ae063a6ac084fee7e33fba78"

0 commit comments

Comments
 (0)