Skip to content

Commit 9474cff

Browse files
refactor: apply fallback sanitization during settings validation
1 parent 501174d commit 9474cff

File tree

4 files changed

+53
-57
lines changed

4 files changed

+53
-57
lines changed
Lines changed: 47 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Treatment, TreatmentWithConfig } from '../../../../types/splitio';
1+
import { FallbackTreatmentConfiguration, Treatment, TreatmentWithConfig } from '../../../../types/splitio';
22
import { ILogger } from '../../../logger/types';
33
import { isObject, isString } from '../../../utils/lang';
44

@@ -7,59 +7,62 @@ enum FallbackDiscardReason {
77
Treatment = 'Invalid treatment (max 100 chars and must match pattern)',
88
}
99

10-
export class FallbacksSanitizer {
10+
const TREATMENT_PATTERN = /^[0-9]+[.a-zA-Z0-9_-]*$|^[a-zA-Z]+[a-zA-Z0-9_-]*$/;
1111

12-
private static readonly pattern = /^[0-9]+[.a-zA-Z0-9_-]*$|^[a-zA-Z]+[a-zA-Z0-9_-]*$/;
13-
14-
private static isValidFlagName(name: string): boolean {
15-
return name.length <= 100 && !name.includes(' ');
16-
}
12+
function isValidFlagName(name: string): boolean {
13+
return name.length <= 100 && !name.includes(' ');
14+
}
1715

18-
private static isValidTreatment(t?: Treatment | TreatmentWithConfig): boolean {
19-
const treatment = isObject(t) ? (t as TreatmentWithConfig).treatment : t;
16+
function isValidTreatment(t?: Treatment | TreatmentWithConfig): boolean {
17+
const treatment = isObject(t) ? (t as TreatmentWithConfig).treatment : t;
2018

21-
if (!isString(treatment) || treatment.length > 100) {
22-
return false;
23-
}
24-
return FallbacksSanitizer.pattern.test(treatment);
19+
if (!isString(treatment) || treatment.length > 100) {
20+
return false;
2521
}
22+
return TREATMENT_PATTERN.test(treatment);
23+
}
2624

27-
static sanitizeGlobal(logger: ILogger, treatment?: Treatment | TreatmentWithConfig): Treatment | TreatmentWithConfig | undefined {
28-
if (!this.isValidTreatment(treatment)) {
29-
logger.error(
30-
`Fallback treatments - Discarded fallback: ${FallbackDiscardReason.Treatment}`
31-
);
32-
return undefined;
33-
}
34-
return treatment;
25+
function sanitizeGlobal(logger: ILogger, treatment?: Treatment | TreatmentWithConfig): Treatment | TreatmentWithConfig | undefined {
26+
if (!isValidTreatment(treatment)) {
27+
logger.error(`Fallback treatments - Discarded fallback: ${FallbackDiscardReason.Treatment}`);
28+
return undefined;
3529
}
30+
return treatment;
31+
}
32+
33+
function sanitizeByFlag(
34+
logger: ILogger,
35+
byFlagFallbacks: Record<string, Treatment | TreatmentWithConfig> = {}
36+
): Record<string, Treatment | TreatmentWithConfig> {
37+
const sanitizedByFlag: Record<string, Treatment | TreatmentWithConfig> = {};
3638

37-
static sanitizeByFlag(
38-
logger: ILogger,
39-
byFlagFallbacks: Record<string, Treatment | TreatmentWithConfig>
40-
): Record<string, Treatment | TreatmentWithConfig> {
41-
const sanitizedByFlag: Record<string, Treatment | TreatmentWithConfig> = {};
39+
const entries = Object.keys(byFlagFallbacks);
40+
entries.forEach((flag) => {
41+
const t = byFlagFallbacks[flag];
42+
if (!isValidFlagName(flag)) {
43+
logger.error(`Fallback treatments - Discarded flag '${flag}': ${FallbackDiscardReason.FlagName}`);
44+
return;
45+
}
4246

43-
const entries = Object.keys(byFlagFallbacks);
44-
entries.forEach((flag) => {
45-
const t = byFlagFallbacks[flag];
46-
if (!this.isValidFlagName(flag)) {
47-
logger.error(
48-
`Fallback treatments - Discarded flag '${flag}': ${FallbackDiscardReason.FlagName}`
49-
);
50-
return;
51-
}
47+
if (!isValidTreatment(t)) {
48+
logger.error(`Fallback treatments - Discarded treatment for flag '${flag}': ${FallbackDiscardReason.Treatment}`);
49+
return;
50+
}
5251

53-
if (!this.isValidTreatment(t)) {
54-
logger.error(
55-
`Fallback treatments - Discarded treatment for flag '${flag}': ${FallbackDiscardReason.Treatment}`
56-
);
57-
return;
58-
}
52+
sanitizedByFlag[flag] = t;
53+
});
5954

60-
sanitizedByFlag[flag] = t;
61-
});
55+
return sanitizedByFlag;
56+
}
6257

63-
return sanitizedByFlag;
58+
export function sanitizeFallbacks(logger: ILogger, fallbacks: unknown): FallbackTreatmentConfiguration | undefined {
59+
if (!isObject(fallbacks)) {
60+
logger.error('Fallback treatments - Discarded fallback: Invalid fallback configuration');
61+
return;
6462
}
63+
64+
return {
65+
global: sanitizeGlobal(logger, (fallbacks as FallbackTreatmentConfiguration).global),
66+
byFlag: sanitizeByFlag(logger, (fallbacks as FallbackTreatmentConfiguration).byFlag)
67+
};
6568
}

src/evaluator/fallbackTreatmentsCalculator/index.ts

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import { FallbackTreatmentConfiguration, Treatment, TreatmentWithConfig } from '../../../types/splitio';
2-
import { FallbacksSanitizer } from './fallbackSanitizer';
32
import { CONTROL } from '../../utils/constants';
43
import { isString } from '../../utils/lang';
5-
import { ILogger } from '../../logger/types';
64

75
export type IFallbackTreatmentsCalculator = {
86
resolve(flagName: string, label: string): TreatmentWithConfig & { label: string };
@@ -11,16 +9,7 @@ export type IFallbackTreatmentsCalculator = {
119
export const FALLBACK_PREFIX = 'fallback - ';
1210

1311
export class FallbackTreatmentsCalculator implements IFallbackTreatmentsCalculator {
14-
private readonly fallbacks: FallbackTreatmentConfiguration;
15-
16-
constructor(logger: ILogger, fallbacks?: FallbackTreatmentConfiguration) {
17-
const sanitizedGlobal = fallbacks?.global ? FallbacksSanitizer.sanitizeGlobal(logger, fallbacks.global) : undefined;
18-
const sanitizedByFlag = fallbacks?.byFlag ? FallbacksSanitizer.sanitizeByFlag(logger, fallbacks.byFlag) : {};
19-
this.fallbacks = {
20-
global: sanitizedGlobal,
21-
byFlag: sanitizedByFlag
22-
};
23-
}
12+
constructor(private readonly fallbacks: FallbackTreatmentConfiguration = {}) {}
2413

2514
resolve(flagName: string, label: string): TreatmentWithConfig & { label: string } {
2615
const treatment = this.fallbacks.byFlag?.[flagName];

src/sdkFactory/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ISDK | SplitIO.IA
6161
}
6262
});
6363

64-
const fallbackTreatmentsCalculator = new FallbackTreatmentsCalculator(settings.log, settings.fallbackTreatments);
64+
const fallbackTreatmentsCalculator = new FallbackTreatmentsCalculator(settings.fallbackTreatments);
6565

6666
if (initialRolloutPlan) {
6767
setRolloutPlan(log, initialRolloutPlan, storage as IStorageSync, key && getMatching(key));

src/utils/settingsValidation/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { ISettings } from '../../types';
88
import { validateKey } from '../inputValidation/key';
99
import { ERROR_MIN_CONFIG_PARAM, LOG_PREFIX_CLIENT_INSTANTIATION } from '../../logger/constants';
1010
import { validateRolloutPlan } from '../../storages/setRolloutPlan';
11+
import { sanitizeFallbacks } from '../../evaluator/fallbackTreatmentsCalculator/fallbackSanitizer';
1112

1213
// Exported for telemetry
1314
export const base = {
@@ -207,5 +208,8 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV
207208
// @ts-ignore, modify readonly prop
208209
withDefaults.userConsent = consent ? consent(withDefaults) : undefined;
209210

211+
// @ts-ignore, modify readonly prop
212+
withDefaults.fallbackTreatments = withDefaults.fallbackTreatments ? sanitizeFallbacks(log, withDefaults.fallbackTreatments) : undefined;
213+
210214
return withDefaults;
211215
}

0 commit comments

Comments
 (0)