Add timestamp utilities with helpful names

This commit is contained in:
Fedor Indutny 2021-03-22 14:08:52 -07:00 committed by GitHub
parent 9fa3359477
commit a75402d290
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 71 additions and 17 deletions

View file

@ -5,6 +5,7 @@
import { fromEncodedBinaryToArrayBuffer, constantTimeEqual } from './Crypto';
import { isNotNil } from './util/isNotNil';
import { isMoreRecentThan } from './util/timestamp';
const TIMESTAMP_THRESHOLD = 5 * 1000; // 5 seconds
const Direction = {
@ -839,7 +840,7 @@ export class SignalProtocolStore extends EventsMixin {
isNonBlockingApprovalRequired(identityRecord: IdentityKeyType): boolean {
return (
!identityRecord.firstUse &&
Date.now() - identityRecord.timestamp < TIMESTAMP_THRESHOLD &&
isMoreRecentThan(identityRecord.timestamp, TIMESTAMP_THRESHOLD) &&
!identityRecord.nonblockingApproval
);
}
@ -1138,7 +1139,7 @@ export class SignalProtocolStore extends EventsMixin {
}
if (
Date.now() - identityRecord.timestamp < TIMESTAMP_THRESHOLD &&
isMoreRecentThan(identityRecord.timestamp, TIMESTAMP_THRESHOLD) &&
!identityRecord.nonblockingApproval &&
!identityRecord.firstUse
) {

View file

@ -8,6 +8,9 @@ import { getTitleBarVisibility, TitleBarVisibility } from './types/Settings';
import { isWindowDragElement } from './util/isWindowDragElement';
import { assert } from './util/assert';
import { routineProfileRefresh } from './routineProfileRefresh';
import { isMoreRecentThan, isOlderThan } from './util/timestamp';
const MAX_ATTACHMENT_DOWNLOAD_AGE = 3600 * 72 * 1000;
export async function startApp(): Promise<void> {
window.startupProcessingQueue = new window.Signal.Util.StartupQueue();
@ -555,12 +558,11 @@ export async function startApp(): Promise<void> {
};
// How long since we were last running?
const now = Date.now();
const lastHeartbeat = window.storage.get('lastHeartbeat');
await window.storage.put('lastStartup', Date.now());
const THIRTY_DAYS = 30 * 24 * 60 * 60 * 1000;
if (lastHeartbeat > 0 && now - lastHeartbeat > THIRTY_DAYS) {
if (lastHeartbeat > 0 && isOlderThan(lastHeartbeat, THIRTY_DAYS)) {
await unlinkAndDisconnect();
}
@ -2097,12 +2099,14 @@ export async function startApp(): Promise<void> {
// once we stop processing the queue.
window.attachmentDownloadQueue = undefined;
const THREE_DAYS_AGO = Date.now() - 3600 * 72 * 1000;
const MAX_ATTACHMENT_MSGS_TO_DOWNLOAD = 250;
const attachmentsToDownload = attachmentDownloadQueue.filter(
(message, index) =>
index <= MAX_ATTACHMENT_MSGS_TO_DOWNLOAD ||
message.getReceivedAt() > THREE_DAYS_AGO ||
isMoreRecentThan(
message.getReceivedAt(),
MAX_ATTACHMENT_DOWNLOAD_AGE
) ||
// Stickers and long text attachments has to be downloaded for UI
// to display the message properly.
message.hasRequiredAttachmentDownloads()

View file

@ -8,12 +8,14 @@ import { assert } from './util/assert';
import { missingCaseError } from './util/missingCaseError';
import { isNormalNumber } from './util/isNormalNumber';
import { map, take } from './util/iterables';
import { isOlderThan } from './util/timestamp';
import { ConversationModel } from './models/conversations';
const STORAGE_KEY = 'lastAttemptedToRefreshProfilesAt';
const MAX_AGE_TO_BE_CONSIDERED_ACTIVE = 30 * 24 * 60 * 60 * 1000;
const MAX_AGE_TO_BE_CONSIDERED_RECENTLY_REFRESHED = 1 * 24 * 60 * 60 * 1000;
const MAX_CONVERSATIONS_TO_REFRESH = 50;
const MIN_ELAPSED_DURATION_TO_REFRESH_AGAIN = 12 * 3600 * 1000;
// This type is a little stricter than what's on `window.storage`, and only requires what
// we need for easier testing.
@ -81,8 +83,7 @@ function hasEnoughTimeElapsedSinceLastRefresh(storage: StorageType): boolean {
}
if (isNormalNumber(storedValue)) {
const twelveHoursAgo = Date.now() - 43200000;
return storedValue < twelveHoursAgo;
return isOlderThan(storedValue, MIN_ELAPSED_DURATION_TO_REFRESH_AGAIN);
}
assert(

View file

@ -0,0 +1,37 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import { isOlderThan, isMoreRecentThan } from '../../util/timestamp';
const ONE_HOUR = 3600 * 1000;
const ONE_DAY = 24 * ONE_HOUR;
describe('timestamp', () => {
describe('isOlderThan', () => {
it('returns false on recent and future timestamps', () => {
assert.isFalse(isOlderThan(Date.now(), ONE_DAY));
assert.isFalse(isOlderThan(Date.now() + ONE_DAY, ONE_DAY));
});
it('returns true on old enough timestamps', () => {
assert.isFalse(isOlderThan(Date.now() - ONE_DAY + ONE_HOUR, ONE_DAY));
assert.isTrue(isOlderThan(Date.now() - ONE_DAY - ONE_HOUR, ONE_DAY));
});
});
describe('isMoreRecentThan', () => {
it('returns true on recent and future timestamps', () => {
assert.isTrue(isMoreRecentThan(Date.now(), ONE_DAY));
assert.isTrue(isMoreRecentThan(Date.now() + ONE_DAY, ONE_DAY));
});
it('returns false on old enough timestamps', () => {
assert.isTrue(isMoreRecentThan(Date.now() - ONE_DAY + ONE_HOUR, ONE_DAY));
assert.isFalse(
isMoreRecentThan(Date.now() - ONE_DAY - ONE_HOUR, ONE_DAY)
);
});
});
});

View file

@ -17,8 +17,10 @@ import ProvisioningCipher from './ProvisioningCipher';
import WebSocketResource, {
IncomingWebSocketRequest,
} from './WebsocketResources';
import { isMoreRecentThan, isOlderThan } from '../util/timestamp';
const ARCHIVE_AGE = 30 * 24 * 60 * 60 * 1000;
const PREKEY_ROTATION_AGE = 24 * 60 * 60 * 1000;
function getIdentifier(id: string) {
if (!id || !id.length) {
@ -321,10 +323,9 @@ export default class AccountManager extends EventTarget {
existingKeys.sort((a, b) => (b.created_at || 0) - (a.created_at || 0));
const confirmedKeys = existingKeys.filter(key => key.confirmed);
const ONE_DAY_AGO = Date.now() - 24 * 60 * 60 * 1000;
if (
confirmedKeys.length >= 3 &&
confirmedKeys[0].created_at > ONE_DAY_AGO
isMoreRecentThan(confirmedKeys[0].created_at, PREKEY_ROTATION_AGE)
) {
window.log.warn(
'rotateSignedPreKey: 3+ confirmed keys, most recent is less than a day old. Cancelling rotation.'
@ -437,9 +438,8 @@ export default class AccountManager extends EventTarget {
return;
}
const createdAt = key.created_at || 0;
const age = Date.now() - createdAt;
if (age > ARCHIVE_AGE) {
if (isOlderThan(createdAt, ARCHIVE_AGE)) {
window.log.info(
'Removing confirmed signed prekey:',
key.keyId,
@ -463,8 +463,7 @@ export default class AccountManager extends EventTarget {
}
const createdAt = key.created_at || 0;
const age = Date.now() - createdAt;
if (age > ARCHIVE_AGE) {
if (isOlderThan(createdAt, ARCHIVE_AGE)) {
window.log.info(
'Removing unconfirmed signed prekey:',
key.keyId,

View file

@ -1,6 +1,8 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { isMoreRecentThan } from './timestamp';
const SIX_HOURS = 1000 * 60 * 60 * 6;
export function isConversationUnregistered({
@ -8,6 +10,6 @@ export function isConversationUnregistered({
}: Readonly<{ discoveredUnregisteredAt?: number }>): boolean {
return Boolean(
discoveredUnregisteredAt &&
discoveredUnregisteredAt > Date.now() - SIX_HOURS
isMoreRecentThan(discoveredUnregisteredAt, SIX_HOURS)
);
}

View file

@ -14026,7 +14026,7 @@
"rule": "jQuery-load(",
"path": "ts/LibSignalStore.js",
"line": " await window.ConversationController.load();",
"lineNumber": 810,
"lineNumber": 811,
"reasonCategory": "falseMatch",
"updated": "2021-02-27T00:48:49.313Z"
},
@ -14034,7 +14034,7 @@
"rule": "jQuery-load(",
"path": "ts/LibSignalStore.ts",
"line": " await window.ConversationController.load();",
"lineNumber": 1221,
"lineNumber": 1222,
"reasonCategory": "falseMatch",
"updated": "2021-02-27T00:48:49.313Z"
},

10
ts/util/timestamp.ts Normal file
View file

@ -0,0 +1,10 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
export function isMoreRecentThan(timestamp: number, delta: number): boolean {
return timestamp > Date.now() - delta;
}
export function isOlderThan(timestamp: number, delta: number): boolean {
return timestamp <= Date.now() - delta;
}