88 lines
2.5 KiB
TypeScript
88 lines
2.5 KiB
TypeScript
// Copyright 2023 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
import { createSelector } from 'reselect';
|
|
|
|
import { Environment, getEnvironment } from '../../environment';
|
|
import { isInPast } from '../../util/timestamp';
|
|
import { DAY } from '../../util/durations';
|
|
import * as log from '../../logging/log';
|
|
import type { StateType } from '../reducer';
|
|
import type { ExpirationStateType } from '../ducks/expiration';
|
|
import { getRemoteBuildExpiration, getAutoDownloadUpdate } from './items';
|
|
|
|
const NINETY_ONE_DAYS = 91 * DAY;
|
|
const THIRTY_ONE_DAYS = 31 * DAY;
|
|
const SIXTY_DAYS = 60 * DAY;
|
|
|
|
export const getExpiration = (state: StateType): ExpirationStateType =>
|
|
state.expiration;
|
|
|
|
const getPackagedBuildExpiration = createSelector(
|
|
getExpiration,
|
|
({ buildExpiration }) => buildExpiration
|
|
);
|
|
|
|
export const getExpirationTimestamp = createSelector(
|
|
getPackagedBuildExpiration,
|
|
getRemoteBuildExpiration,
|
|
getAutoDownloadUpdate,
|
|
(
|
|
buildExpiration: number,
|
|
remoteBuildExpiration: number | undefined,
|
|
autoDownloadUpdate: boolean
|
|
): number => {
|
|
const localBuildExpiration = autoDownloadUpdate
|
|
? buildExpiration
|
|
: buildExpiration - SIXTY_DAYS;
|
|
|
|
// Log the expiration date in this selector because it invalidates only
|
|
// if one of the arguments changes.
|
|
let result: number;
|
|
let type: string;
|
|
if (remoteBuildExpiration && remoteBuildExpiration < localBuildExpiration) {
|
|
type = 'remote';
|
|
result = remoteBuildExpiration;
|
|
} else {
|
|
type = 'local';
|
|
result = localBuildExpiration;
|
|
}
|
|
log.info(`Build expires (${type}): ${new Date(result).toISOString()}`);
|
|
return result;
|
|
}
|
|
);
|
|
|
|
export type HasExpiredOptionsType = Readonly<{
|
|
now?: number;
|
|
}>;
|
|
|
|
export const hasExpired = createSelector(
|
|
getExpirationTimestamp,
|
|
getAutoDownloadUpdate,
|
|
(_: StateType, { now = Date.now() }: HasExpiredOptionsType = {}) => now,
|
|
(buildExpiration: number, autoDownloadUpdate: boolean, now: number) => {
|
|
if (getEnvironment() !== Environment.Production && buildExpiration === 0) {
|
|
return false;
|
|
}
|
|
|
|
if (isInPast(buildExpiration)) {
|
|
return true;
|
|
}
|
|
|
|
const safeExpirationMs = autoDownloadUpdate
|
|
? NINETY_ONE_DAYS
|
|
: THIRTY_ONE_DAYS;
|
|
|
|
const buildExpirationDuration = buildExpiration - now;
|
|
const tooFarIntoFuture = buildExpirationDuration > safeExpirationMs;
|
|
|
|
if (tooFarIntoFuture) {
|
|
log.error(
|
|
'Build expiration is set too far into the future',
|
|
buildExpiration
|
|
);
|
|
}
|
|
|
|
return tooFarIntoFuture || isInPast(buildExpiration);
|
|
}
|
|
);
|