fix(startup): restore keychain consent barrier

This commit is contained in:
NimBold
2026-07-15 21:09:45 +03:30
parent 6e6ae51395
commit d2479f52be
7 changed files with 67 additions and 20 deletions
+15 -2
View File
@@ -14,10 +14,23 @@ describe('download progress size display', () => {
totalIsEstimate: true,
fallbackSize: 'Unknown'
})).toEqual({
downloaded: '1.20 GB',
total: '2.40 GB',
downloaded: '1.20',
total: '2.40',
unit: 'GB',
totalIsEstimate: true,
fallback: 'Unknown'
});
});
it('converts downloaded bytes into the total size unit', () => {
expect(resolveDownloadSizeDisplay({
downloadedBytes: 512 * 1024 ** 2,
totalBytes: 2 * 1024 ** 3,
fallbackSize: '2 GB'
})).toMatchObject({
downloaded: '0.50',
total: '2.00',
unit: 'GB'
});
});
});
+27 -9
View File
@@ -1,26 +1,37 @@
export interface DownloadSizeDisplay {
downloaded: string | null;
total: string | null;
unit: string | null;
totalIsEstimate: boolean;
fallback: string;
}
const BYTE_UNITS = ['B', 'KB', 'MB', 'GB', 'TB'] as const;
const isUsableByteCount = (value: number | null | undefined): value is number =>
typeof value === 'number' && Number.isFinite(value) && value >= 0;
export const formatDownloadBytes = (bytes: number): string => {
if (bytes < 1024) return `${Math.round(bytes)} B`;
const units = ['KB', 'MB', 'GB', 'TB'];
const byteUnitIndex = (bytes: number): number => {
let value = bytes;
let unitIndex = -1;
while (value >= 1024 && unitIndex < units.length - 1) {
let unitIndex = 0;
while (value >= 1024 && unitIndex < BYTE_UNITS.length - 1) {
value /= 1024;
unitIndex += 1;
}
return unitIndex;
};
const formatDownloadBytesInUnit = (bytes: number, unitIndex: number): string => {
const value = bytes / 1024 ** unitIndex;
const precision = value >= 100 ? 0 : value >= 10 ? 1 : 2;
return `${value.toFixed(precision)} ${units[unitIndex]}`;
return value < 1024 && unitIndex === 0
? `${Math.round(value)}`
: value.toFixed(precision);
};
export const formatDownloadBytes = (bytes: number): string => {
const unitIndex = byteUnitIndex(bytes);
return `${formatDownloadBytesInUnit(bytes, unitIndex)} ${BYTE_UNITS[unitIndex]}`;
};
export const resolveDownloadSizeDisplay = ({
@@ -34,8 +45,15 @@ export const resolveDownloadSizeDisplay = ({
totalIsEstimate?: boolean;
fallbackSize?: string | null;
}): DownloadSizeDisplay => ({
downloaded: isUsableByteCount(downloadedBytes) ? formatDownloadBytes(downloadedBytes) : null,
total: isUsableByteCount(totalBytes) && totalBytes > 0 ? formatDownloadBytes(totalBytes) : null,
downloaded: isUsableByteCount(downloadedBytes) && isUsableByteCount(totalBytes) && totalBytes > 0
? formatDownloadBytesInUnit(downloadedBytes, byteUnitIndex(totalBytes))
: null,
total: isUsableByteCount(totalBytes) && totalBytes > 0
? formatDownloadBytesInUnit(totalBytes, byteUnitIndex(totalBytes))
: null,
unit: isUsableByteCount(totalBytes) && totalBytes > 0
? BYTE_UNITS[byteUnitIndex(totalBytes)]
: null,
totalIsEstimate: Boolean(totalIsEstimate && isUsableByteCount(totalBytes) && totalBytes > 0),
fallback: fallbackSize && fallbackSize !== '-' ? fallbackSize : 'Unknown'
});
+13
View File
@@ -80,6 +80,19 @@ describe('getKeychainStartupDecision', () => {
});
});
it('keeps persistent access deferred without prompting when the version API is unavailable', () => {
expect(getKeychainStartupDecision({
portable: false,
appVersion: '',
approvedVersion: '1.0.5',
accessGranted: true,
promptDismissed: false
})).toEqual({
deferKeychainHydration: true,
showKeychainPrompt: false
});
});
it('never gates portable pairing on credential-store access', () => {
expect(getKeychainStartupDecision({
portable: true,
+4 -2
View File
@@ -25,9 +25,11 @@ export const getKeychainStartupDecision = ({
};
}
const versionChanged = Boolean(appVersion) && approvedVersion !== appVersion;
const versionKnown = Boolean(appVersion.trim());
const versionChanged = versionKnown && approvedVersion !== appVersion;
const mustDeferAccess = !accessGranted || !versionKnown || versionChanged;
return {
deferKeychainHydration: !accessGranted || versionChanged,
deferKeychainHydration: mustDeferAccess,
showKeychainPrompt: versionChanged || (!accessGranted && !promptDismissed)
};
};