Skip to content

Commit a9a9d9e

Browse files
hongj-srcmeta-codesync[bot]
authored andcommitted
Extract AppendixProvider to a separate file
Summary: Separate AppendixProvider to file. Detach the appendix function from base ParamBuilder main function Differential Revision: D84870237 Privacy Context Container: L1276675 fbshipit-source-id: c247aeaa97c145b14efbe821094ec7f1407801c3
1 parent 76a0969 commit a9a9d9e

4 files changed

Lines changed: 133 additions & 26 deletions

File tree

nodejs/capi-param-builder/src/ParamBuilder.js

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ const FbcParamConfig = require('./model/FbcParamConfig');
99
const CookieSettings = require('./model/CookieSettings');
1010
const Constants = require('./model/Constants');
1111
const net = require('net');
12-
const { version } = require('../package.json');
1312
const { getNormalizedAndHashedPII } = require('./piiUtil/PIIUtil');
13+
const { getAppendixInfo } = require('./utils/AppendixProvider');
1414

1515
class ParamBuilder {
1616
constructor(input_params) {
@@ -40,22 +40,8 @@ class ParamBuilder {
4040
this.cookies_to_set = [];
4141
this.cookies_to_set_dict = {};
4242
// language token
43-
this.appendix_new = this._getAppendixInfo(true, version);
44-
this.appendix_normal = this._getAppendixInfo(false, version);
45-
}
46-
47-
_getAppendixInfo(is_new, sdk_version) {
48-
try {
49-
const [major, minor, patch] = sdk_version.split('.').map(Number);
50-
const is_new_byte = is_new === true ? 0x01 : 0x00;
51-
const bytes = [Constants.DEFAULT_FORMAT, Constants.LANGUAGE_TOKEN_INDEX, is_new_byte, major.toString(16), minor.toString(16), patch.toString(16)];
52-
const buf = Buffer.from(bytes);
53-
const base64urlSafe = buf.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
54-
return base64urlSafe;
55-
} catch (error) {
56-
console.error("Exception when parsing appendix version number:" + error);
57-
return Constants.LANGUAGE_TOKEN;
58-
}
43+
this.appendix_new = getAppendixInfo(true);
44+
this.appendix_normal = getAppendixInfo(false);
5945
}
6046

6147
_preprocessCookie(cookies, cookie_name) {
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
const { version } = require('../../package.json');
10+
const { LANGUAGE_TOKEN , LANGUAGE_TOKEN_INDEX , DEFAULT_FORMAT } = require('../model/Constants');
11+
12+
function getAppendixInfo(is_new) {
13+
try {
14+
// Validate version format: must be exactly 3 numeric parts separated by dots
15+
if (!/^\d+(\.\d+){2}$/.test(version)) {
16+
return LANGUAGE_TOKEN;
17+
}
18+
19+
const [major, minor, patch] = version.split('.').map(Number);
20+
21+
// Validate byte range (0-255) - regex doesn't check this
22+
if (major > 255 || minor > 255 || patch > 255) {
23+
return LANGUAGE_TOKEN;
24+
}
25+
26+
const is_new_byte = is_new === true ? 0x01 : 0x00;
27+
const bytes = [DEFAULT_FORMAT, LANGUAGE_TOKEN_INDEX, is_new_byte, major, minor, patch];
28+
const buf = Buffer.from(bytes);
29+
const base64urlSafe = buf.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
30+
return base64urlSafe;
31+
} catch (error) {
32+
console.error("Exception when parsing appendix version number:" + error);
33+
return LANGUAGE_TOKEN;
34+
}
35+
}
36+
37+
module.exports = {
38+
getAppendixInfo
39+
};
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
const { getAppendixInfo } = require('../src/utils/AppendixProvider');
9+
10+
jest.mock('../package.json', () => ({version: '1.0.1'}));
11+
12+
describe('AppendixProvider - getAppendixInfo', () => {
13+
beforeEach(() => {
14+
jest.spyOn(console, 'error').mockImplementation(() => {});
15+
});
16+
17+
afterEach(() => {
18+
console.error.mockRestore();
19+
jest.resetModules();
20+
jest.resetAllMocks();
21+
});
22+
23+
test('test cases on valid input', () => {
24+
expect(getAppendixInfo(true)).toBe('AQQBAQAB'); // 1.0.1
25+
expect(getAppendixInfo(false)).toBe('AQQAAQAB'); // 1.0.1
26+
});
27+
28+
test('test cases on invalid input', () => {
29+
const resultFalse = getAppendixInfo(false);
30+
expect(getAppendixInfo(1)).toBe(resultFalse);
31+
expect(getAppendixInfo('true')).toBe(resultFalse);
32+
expect(getAppendixInfo({})).toBe(resultFalse);
33+
expect(getAppendixInfo([])).toBe(resultFalse);
34+
expect(getAppendixInfo(0)).toBe(resultFalse);
35+
expect(getAppendixInfo('')).toBe(resultFalse);
36+
expect(getAppendixInfo(null)).toBe(resultFalse);
37+
expect(getAppendixInfo(undefined)).toBe(resultFalse);
38+
});
39+
40+
test('should handle version 1.15.24', () => {
41+
jest.doMock('../package.json', () => ({version: '1.15.24'}));
42+
const { getAppendixInfo } = require('../src/utils/AppendixProvider');
43+
expect(getAppendixInfo(true)).toBe('AQQBAQ8Y');
44+
expect(getAppendixInfo(false)).toBe('AQQAAQ8Y');
45+
});
46+
47+
test('should return LANGUAGE_TOKEN when version is invalid format', () => {
48+
mockPackageVersion('invalid-version');
49+
const { getAppendixInfo } = require('../src/utils/AppendixProvider');
50+
const result = getAppendixInfo(true);
51+
expect(result).toBe('BA');
52+
});
53+
54+
test('should return LANGUAGE_TOKEN when version is missing', () => {
55+
mockPackageVersion({});
56+
const { getAppendixInfo } = require('../src/utils/AppendixProvider');
57+
const result = getAppendixInfo(true);
58+
expect(result).toBe('BA');
59+
});
60+
61+
test('should return LANGUAGE_TOKEN when version has only 2 parts', () => {
62+
mockPackageVersion('1.0');
63+
const { getAppendixInfo } = require('../src/utils/AppendixProvider');
64+
const result = getAppendixInfo(true);
65+
expect(result).toBe('BA');
66+
});
67+
68+
test('should return LANGUAGE_TOKEN when version has too many parts', () => {
69+
mockPackageVersion('1.0.0.1');
70+
const { getAppendixInfo } = require('../src/utils/AppendixProvider');
71+
const result = getAppendixInfo(true);
72+
expect(result).toBe('BA');
73+
});
74+
75+
test('should return LANGUAGE_TOKEN when version contains non-numeric values', () => {
76+
mockPackageVersion('a.b.c');
77+
const { getAppendixInfo } = require('../src/utils/AppendixProvider');
78+
const result = getAppendixInfo(true);
79+
expect(result).toBe('BA');
80+
});
81+
82+
function mockPackageVersion(version) {
83+
jest.resetModules();
84+
jest.doMock('../package.json', () => ({version: version}));
85+
jest.doMock('../src/model/Constants', () => ({
86+
LANGUAGE_TOKEN: 'BA',
87+
LANGUAGE_TOKEN_INDEX: 0x04,
88+
DEFAULT_FORMAT: 0x01,
89+
}));
90+
}
91+
});

nodejs/capi-param-builder/tests/ParamBuilder.test.js

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -426,13 +426,4 @@ describe('ParamBuilder base unit test', () => {
426426
expect(builder.getFbc()).toEqual("fb.2." + DUMMY_TIMESTAMP + ".test123_test_balabala." + DUMMY_APPENDIX_NEW);
427427
expect(builder.getFbp()).toEqual("fb.2."+ DUMMY_TIMESTAMP + "." + DUMMY_FBP_PAYLOAD + "." + DUMMY_APPENDIX_NEW);
428428
});
429-
430-
test('testProcessRequestWithInvalidVersionNumber', () => {
431-
const builder = new ParamBuilder();
432-
const appendix_new = builder._getAppendixInfo(true); // null version
433-
const appendix_normal = builder._getAppendixInfo(false, ""); // empty version
434-
// Fallback
435-
expect(appendix_new).toEqual(Constants.LANGUAGE_TOKEN);
436-
expect(appendix_normal).toEqual(Constants.LANGUAGE_TOKEN);
437-
});
438429
});

0 commit comments

Comments
 (0)