Skip to content

Commit

Permalink
Fix bootstrap validator missing cases (#246)
Browse files Browse the repository at this point in the history
* Fix bootstrap validator missing cases

* feedback

* cleanup typing
  • Loading branch information
tore-statsig authored Mar 20, 2023
1 parent dd38c56 commit 6c6791f
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 40 deletions.
99 changes: 60 additions & 39 deletions src/utils/BootstrapValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,55 +10,76 @@ export default abstract class BootstrapValidator {
if (!evaluatedKeys || typeof evaluatedKeys !== 'object') {
return true;
}

const keys = this.copyObject(evaluatedKeys ?? {});
const customIDs: Record<string, unknown> = this.copyObject({
...user?.customIDs,
const evaluatedKeysRecord = evaluatedKeys as Record<string, unknown>;
const keys = BootstrapValidator.copyObject({
userID: evaluatedKeysRecord?.userID,
customIDs: evaluatedKeysRecord?.customIDs,
});

for (let [key, value] of Object.entries(keys)) {
switch (key) {
case 'userID':
if (value !== user?.userID) {
return false;
}
break;

case 'customIDs':
if (typeof value !== 'object' || typeof customIDs !== 'object') {
return false;
}

if (value?.['stableID'] || customIDs?.['stableID']) {
var a = 1;
}
const userToCompare = user == null ? null : BootstrapValidator.copyObject(
{
userID: user?.userID,
customIDs: user?.customIDs,
}
);

// StableID may be present, but should not be compared
delete value?.['stableID'];
delete customIDs?.['stableID'];
return BootstrapValidator.validate(keys, userToCompare) && BootstrapValidator.validate(userToCompare, keys);
} catch (error) {
// This is best-effort. If we fail, return true.
}

const actualKeys = Object.keys(value);
const expectedKeys = Object.keys(customIDs);
if (actualKeys.length !== expectedKeys.length) {
return false;
}
return true;
}

for (let [customID, customIDValue] of Object.entries(value)) {
if (customIDs[customID] !== customIDValue) {
return false;
}
}
break;
private static validate(
one: Record<string, unknown> | null,
two: Record<string, unknown> | null
): boolean {
if (one == null) {
return two == null;
} else if (two == null) {
return false;
}
for (let [key, value] of Object.entries(one)) {
if (key === 'stableID') {
continue;
}
if (typeof value !== typeof two[key]) {
return false;
}
if (typeof value === 'string') {
if (value !== two[key]) {
return false;
}
} else if (typeof value === 'object') {
return this.validate(
value as Record<string, unknown>,
two[key] as Record<string, unknown>
);
} else {
// unexpected
return false;
}
} catch (error) {
// This is best-effort. If we fail, return true.
}

return true;
}

private static copyObject<T>(obj: T): T {
return JSON.parse(JSON.stringify(obj));
private static copyObject<T>(obj: T | null): T | null {
if (obj == null) {
return null;
}
const copy = JSON.parse(JSON.stringify(obj));
delete copy.stableID;
if (copy.customIDs) {
delete copy.customIDs['stableID'];
if (Object.keys(copy.customIDs).length === 0) {
delete copy.customIDs;
}
}

if (Object.keys(copy).length === 0) {
return null;
}
return copy;
}
}
59 changes: 58 additions & 1 deletion src/utils/__tests__/BootstrapValidator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,63 @@ describe('BootstrapValidator', () => {
expect(result).toBe(true);
});

it('returns false when userid doesnt match empty evaluted_keys', () => {
const result = BootstrapValidator.isValid(
{ userID: 'a-user-id'},
{
evaluated_keys: {},
},
);

expect(result).toBe(false);
});

it('returns false when customid doesnt match empty evaluted_keys', () => {
const result = BootstrapValidator.isValid(
{ customIDs: {workID: 'a-work-id'}},
{
evaluated_keys: {},
},
);

expect(result).toBe(false);
});

it('returns false when userid doesnt match empty evaluted_keys', () => {
const result = BootstrapValidator.isValid(
{ userID: 'a-user-id'},
{
evaluated_keys: {},
},
);

expect(result).toBe(false);
});

it('returns false when customid doesnt match empty user', () => {
const result = BootstrapValidator.isValid(
{},
{
evaluated_keys: {
customIDs: {workID: 'a-work-id'},
}
},
);

expect(result).toBe(false);
});

it('returns false when userid doesnt match empty user', () => {
const result = BootstrapValidator.isValid(
{},
{
evaluated_keys: {userID: 'a-user-id'},
},
);

expect(false).toBe(result);
});

it('returns false when userID does not match', () => {
const result = BootstrapValidator.isValid(
{ userID: 'a-user-id', customIDs: { workID: 'a-work-id' } },
Expand All @@ -60,8 +117,8 @@ describe('BootstrapValidator', () => {
{
evaluated_keys: {
userID: 'a-user-id',
stableID: 'an-invalid-stable-id',
customIDs: {
stableID: 'an-invalid-stable-id',
workID: 'a-work-id',
},
},
Expand Down

0 comments on commit 6c6791f

Please sign in to comment.