Skip to content

Commit

Permalink
fix(3742): add validation to metametricsId
Browse files Browse the repository at this point in the history
  • Loading branch information
DDDDDanica committed Jan 9, 2025
1 parent 8724cc3 commit a9a7672
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ const MOCK_METRICS_IDS = {
MOBILE_MAX: 'ffffffff-ffff-4fff-bfff-ffffffffffff',
EXTENSION_MIN: `0x${'0'.repeat(64) as string}`,
EXTENSION_MAX: `0x${'f'.repeat(64) as string}`,
UUID_V3: '00000000-0000-3000-8000-000000000000',
INVALID_HEX_NO_PREFIX: '86bacb9b2bf9a7e8d2b147eadb95ac9aaa26842327cd24afc8bd4b3c1d136420',

Check failure on line 17 in packages/remote-feature-flag-controller/src/utils/user-segmentation-utils.test.ts

View workflow job for this annotation

GitHub Actions / Lint, build, and test / Lint (20.x)

Insert `⏎···`
INVALID_HEX_SHORT: '0x86bacb9b2bf9a7e8d2b147eadb95ac9aaa26842327cd24afc8bd4b3c1d13642',

Check failure on line 18 in packages/remote-feature-flag-controller/src/utils/user-segmentation-utils.test.ts

View workflow job for this annotation

GitHub Actions / Lint, build, and test / Lint (20.x)

Insert `⏎···`
INVALID_HEX_LONG: '0x86bacb9b2bf9a7e8d2b147eadb95ac9aaa26842327cd24afc8bd4b3c1d1364200',

Check failure on line 19 in packages/remote-feature-flag-controller/src/utils/user-segmentation-utils.test.ts

View workflow job for this annotation

GitHub Actions / Lint, build, and test / Lint (20.x)

Insert `⏎···`
INVALID_HEX_INVALID_CHARS: '0x86bacb9b2bf9a7e8d2b147eadb95ac9aaa26842327cd24afc8bd4b3c1d13642g',

Check failure on line 20 in packages/remote-feature-flag-controller/src/utils/user-segmentation-utils.test.ts

View workflow job for this annotation

GitHub Actions / Lint, build, and test / Lint (20.x)

Insert `⏎···`
};

const MOCK_FEATURE_FLAGS = {
Expand Down Expand Up @@ -125,6 +130,29 @@ describe('user-segmentation-utils', () => {
});
});
});

describe('MetaMetrics ID validation', () => {
it('throws an error if the MetaMetrics ID is not a valid UUIDv4', () => {
expect(() => generateDeterministicRandomNumber(MOCK_METRICS_IDS.UUID_V3)).toThrow('Invalid UUID version. Expected v4, got v3');

Check failure on line 136 in packages/remote-feature-flag-controller/src/utils/user-segmentation-utils.test.ts

View workflow job for this annotation

GitHub Actions / Lint, build, and test / Lint (20.x)

Replace `·generateDeterministicRandomNumber(MOCK_METRICS_IDS.UUID_V3)` with `⏎··········generateDeterministicRandomNumber(MOCK_METRICS_IDS.UUID_V3),⏎········`
});

it('throws an error if the MetaMetrics ID is not a valid hex string', () => {
expect(() => generateDeterministicRandomNumber(MOCK_METRICS_IDS.INVALID_HEX_NO_PREFIX)).toThrow('Hex ID must start with 0x prefix');

Check failure on line 140 in packages/remote-feature-flag-controller/src/utils/user-segmentation-utils.test.ts

View workflow job for this annotation

GitHub Actions / Lint, build, and test / Lint (20.x)

Replace `·generateDeterministicRandomNumber(MOCK_METRICS_IDS.INVALID_HEX_NO_PREFIX)` with `⏎··········generateDeterministicRandomNumber(⏎············MOCK_METRICS_IDS.INVALID_HEX_NO_PREFIX,⏎··········),⏎········`
});

it('throws an error if the MetaMetrics ID is not a valid hex string', () => {

Check failure on line 143 in packages/remote-feature-flag-controller/src/utils/user-segmentation-utils.test.ts

View workflow job for this annotation

GitHub Actions / Lint, build, and test / Lint (20.x)

Test title is used multiple times in the same describe block
expect(() => generateDeterministicRandomNumber(MOCK_METRICS_IDS.INVALID_HEX_SHORT)).toThrow('Invalid hex ID length. Expected 64 characters, got 63');

Check failure on line 144 in packages/remote-feature-flag-controller/src/utils/user-segmentation-utils.test.ts

View workflow job for this annotation

GitHub Actions / Lint, build, and test / Lint (20.x)

Replace `·generateDeterministicRandomNumber(MOCK_METRICS_IDS.INVALID_HEX_SHORT)` with `⏎··········generateDeterministicRandomNumber(MOCK_METRICS_IDS.INVALID_HEX_SHORT),⏎········`
});

it('throws an error if the MetaMetrics ID is not a valid hex string', () => {

Check failure on line 147 in packages/remote-feature-flag-controller/src/utils/user-segmentation-utils.test.ts

View workflow job for this annotation

GitHub Actions / Lint, build, and test / Lint (20.x)

Test title is used multiple times in the same describe block
expect(() => generateDeterministicRandomNumber(MOCK_METRICS_IDS.INVALID_HEX_LONG)).toThrow('Invalid hex ID length. Expected 64 characters, got 65');

Check failure on line 148 in packages/remote-feature-flag-controller/src/utils/user-segmentation-utils.test.ts

View workflow job for this annotation

GitHub Actions / Lint, build, and test / Lint (20.x)

Replace `·generateDeterministicRandomNumber(MOCK_METRICS_IDS.INVALID_HEX_LONG)` with `⏎··········generateDeterministicRandomNumber(MOCK_METRICS_IDS.INVALID_HEX_LONG),⏎········`
});

it('throws an error if the MetaMetrics ID contains invalid hex characters', () => {
expect(() => generateDeterministicRandomNumber(MOCK_METRICS_IDS.INVALID_HEX_INVALID_CHARS))
.toThrow('Hex ID contains invalid characters');
});
});
});

describe('isFeatureFlagWithScopeValue', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,43 @@ const UUID_V4_VALUE_RANGE_BIGINT =
export function generateDeterministicRandomNumber(
metaMetricsId: string,
): number {
if (!metaMetricsId) {
throw new Error('MetaMetrics ID cannot be empty');
}

let idValue: bigint;
let maxValue: bigint;

// uuidv4 format
if (uuidValidate(metaMetricsId) && uuidVersion(metaMetricsId) === 4) {
// Normalize the UUIDv4 range to start from 0 by subtracting MIN_UUID_V4_BIGINT.
// This ensures uniform distribution across the entire range, since UUIDv4
// has restricted bits for version (4) and variant (8-b) that would otherwise skew the distribution
if (uuidValidate(metaMetricsId)) {
if (uuidVersion(metaMetricsId) !== 4) {
throw new Error(`Invalid UUID version. Expected v4, got v${uuidVersion(metaMetricsId)}`);
}
idValue = uuidStringToBigInt(metaMetricsId) - MIN_UUID_V4_BIGINT;
maxValue = UUID_V4_VALUE_RANGE_BIGINT;
} else {
// hex format with 0x prefix
if (!metaMetricsId.startsWith('0x')) {
throw new Error('Hex ID must start with 0x prefix');
}

const cleanId = metaMetricsId.slice(2);
const EXPECTED_HEX_LENGTH = 64; // 32 bytes = 64 hex characters

if (cleanId.length !== EXPECTED_HEX_LENGTH) {
throw new Error(
`Invalid hex ID length. Expected ${EXPECTED_HEX_LENGTH} characters, got ${cleanId.length}`
);
}

if (!/^[0-9a-f]+$/i.test(cleanId)) {
throw new Error('Hex ID contains invalid characters');
}

idValue = BigInt(`0x${cleanId}`);
maxValue = BigInt(`0x${'f'.repeat(cleanId.length)}`);
}

// Use BigInt division first, then convert to number to maintain precision
return Number((idValue * BigInt(1_000_000)) / maxValue) / 1_000_000;
}
Expand Down

0 comments on commit a9a7672

Please sign in to comment.