Fix admin PKI validation (#766)
Admin PKI fields were falsely flagged as unchanged. Co-authored-by: philon- <philon-@users.noreply.github.com>
This commit is contained in:
co-authored by
philon-
parent
a7f56c0bd5
commit
27ed4e58bd
@@ -197,14 +197,12 @@ export const Security = ({ onFormInit }: SecurityConfigProps) => {
|
|||||||
description: t("security.primaryAdminKey.description"),
|
description: t("security.primaryAdminKey.description"),
|
||||||
bits,
|
bits,
|
||||||
devicePSKBitCount: 32,
|
devicePSKBitCount: 32,
|
||||||
hide: true,
|
|
||||||
actionButtons: [],
|
actionButtons: [],
|
||||||
disabledBy: [
|
disabledBy: [
|
||||||
{ fieldName: "adminChannelEnabled", invert: true },
|
{ fieldName: "adminChannelEnabled", invert: true },
|
||||||
],
|
],
|
||||||
properties: {
|
properties: {
|
||||||
showCopyButton: true,
|
showCopyButton: true,
|
||||||
showPasswordToggle: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -215,14 +213,12 @@ export const Security = ({ onFormInit }: SecurityConfigProps) => {
|
|||||||
description: t("security.secondaryAdminKey.description"),
|
description: t("security.secondaryAdminKey.description"),
|
||||||
bits,
|
bits,
|
||||||
devicePSKBitCount: 32,
|
devicePSKBitCount: 32,
|
||||||
hide: true,
|
|
||||||
actionButtons: [],
|
actionButtons: [],
|
||||||
disabledBy: [
|
disabledBy: [
|
||||||
{ fieldName: "adminChannelEnabled", invert: true },
|
{ fieldName: "adminChannelEnabled", invert: true },
|
||||||
],
|
],
|
||||||
properties: {
|
properties: {
|
||||||
showCopyButton: true,
|
showCopyButton: true,
|
||||||
showPasswordToggle: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -233,14 +229,12 @@ export const Security = ({ onFormInit }: SecurityConfigProps) => {
|
|||||||
description: t("security.tertiaryAdminKey.description"),
|
description: t("security.tertiaryAdminKey.description"),
|
||||||
bits,
|
bits,
|
||||||
devicePSKBitCount: 32,
|
devicePSKBitCount: 32,
|
||||||
hide: true,
|
|
||||||
actionButtons: [],
|
actionButtons: [],
|
||||||
disabledBy: [
|
disabledBy: [
|
||||||
{ fieldName: "adminChannelEnabled", invert: true },
|
{ fieldName: "adminChannelEnabled", invert: true },
|
||||||
],
|
],
|
||||||
properties: {
|
properties: {
|
||||||
showCopyButton: true,
|
showCopyButton: true,
|
||||||
showPasswordToggle: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -57,4 +57,49 @@ describe("deepCompareConfig", () => {
|
|||||||
expect(deepCompareConfig([1, 2, 3, 4], [1, 2], true)).toBe(true);
|
expect(deepCompareConfig([1, 2, 3, 4], [1, 2], true)).toBe(true);
|
||||||
expect(deepCompareConfig([1, 2, 3, 4], [1, 2], false)).toBe(false);
|
expect(deepCompareConfig([1, 2, 3, 4], [1, 2], false)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("compares Uint8Array strictly: equal bytes -> true", () => {
|
||||||
|
const a = new Uint8Array([1, 2, 3]);
|
||||||
|
const b = new Uint8Array([1, 2, 3]);
|
||||||
|
expect(deepCompareConfig(a, b)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("compares Uint8Array strictly: different bytes -> false", () => {
|
||||||
|
const a = new Uint8Array([1, 2, 3]);
|
||||||
|
const b = new Uint8Array([1, 2, 4]);
|
||||||
|
expect(deepCompareConfig(a, b)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Uint8Array vs undefined is false even when allowUndefined is true", () => {
|
||||||
|
const a = new Uint8Array([1, 2, 3]);
|
||||||
|
expect(deepCompareConfig(a, undefined, true)).toBe(false);
|
||||||
|
expect(deepCompareConfig(undefined, a, true)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("nested Uint8Array fields must match exactly", () => {
|
||||||
|
const existing = { data: new Uint8Array([9, 8, 7]) };
|
||||||
|
const workingEqual = { data: new Uint8Array([9, 8, 7]) };
|
||||||
|
const workingDiff = { data: new Uint8Array([9, 8, 6]) };
|
||||||
|
const workingUndef = { data: undefined as unknown };
|
||||||
|
|
||||||
|
expect(deepCompareConfig(existing, workingEqual)).toBe(true);
|
||||||
|
expect(deepCompareConfig(existing, workingDiff)).toBe(false);
|
||||||
|
// still false even with allowUndefined
|
||||||
|
expect(deepCompareConfig(existing, workingUndef, true)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("arrays containing Uint8Array: element must match exactly", () => {
|
||||||
|
const a = [new Uint8Array([1, 2]), new Uint8Array([3, 4])];
|
||||||
|
const b = [new Uint8Array([1, 2]), new Uint8Array([3, 4])];
|
||||||
|
const c = [new Uint8Array([1, 2]), new Uint8Array([3, 9])];
|
||||||
|
|
||||||
|
expect(deepCompareConfig(a, b)).toBe(true);
|
||||||
|
expect(deepCompareConfig(a, c)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shorter working array with missing Uint8Array element -> false even with allowUndefined", () => {
|
||||||
|
const existing = [new Uint8Array([1, 2]), new Uint8Array([3, 4])];
|
||||||
|
const workingShort = [new Uint8Array([1, 2])]; // missing the second byte array
|
||||||
|
expect(deepCompareConfig(existing, workingShort, true)).toBe(false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,6 +2,22 @@ function isObject(value: unknown): value is Record<string, unknown> {
|
|||||||
return typeof value === "object" && value !== null && !Array.isArray(value);
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isUint8Array(v: unknown): v is Uint8Array {
|
||||||
|
return v instanceof Uint8Array;
|
||||||
|
}
|
||||||
|
|
||||||
|
function bytesEqual(a: Uint8Array, b: Uint8Array): boolean {
|
||||||
|
if (a.byteLength !== b.byteLength) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < a.byteLength; i++) {
|
||||||
|
if (a[i] !== b[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
export function deepCompareConfig(
|
export function deepCompareConfig(
|
||||||
a: unknown,
|
a: unknown,
|
||||||
b: unknown,
|
b: unknown,
|
||||||
@@ -11,7 +27,10 @@ export function deepCompareConfig(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If allowUndefined is true, and one is undefined, they are considered equal. // This check is placed early to simplify subsequent logic.
|
if (isUint8Array(a) || isUint8Array(b)) {
|
||||||
|
return isUint8Array(a) && isUint8Array(b) && bytesEqual(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
if (allowUndefined && (a === undefined || b === undefined)) {
|
if (allowUndefined && (a === undefined || b === undefined)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user