Fix timestamp capping for storage service

Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
This commit is contained in:
automated-signal 2025-01-30 13:15:44 -06:00 committed by GitHub
parent 5fc53ee435
commit f15d5049f8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 141 additions and 7 deletions

View file

@ -888,7 +888,10 @@ export async function mergeGroupV1Record(
});
conversation.setMuteExpiration(
getTimestampFromLong(groupV1Record.mutedUntilTimestamp),
getTimestampFromLong(
groupV1Record.mutedUntilTimestamp,
Number.MAX_SAFE_INTEGER
),
{
viaStorageServiceSync: true,
}
@ -1025,7 +1028,10 @@ export async function mergeGroupV2Record(
});
conversation.setMuteExpiration(
getTimestampFromLong(groupV2Record.mutedUntilTimestamp),
getTimestampFromLong(
groupV2Record.mutedUntilTimestamp,
Number.MAX_SAFE_INTEGER
),
{
viaStorageServiceSync: true,
}
@ -1265,7 +1271,10 @@ export async function mergeContactRecord(
}
conversation.setMuteExpiration(
getTimestampFromLong(contactRecord.mutedUntilTimestamp),
getTimestampFromLong(
contactRecord.mutedUntilTimestamp,
Number.MAX_SAFE_INTEGER
),
{
viaStorageServiceSync: true,
}

View file

@ -0,0 +1,40 @@
// Copyright 2025 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { LoggerType } from '../../types/Logging';
import { sql } from '../util';
import type { WritableDB } from '../Interface';
export const version = 1310;
// Value from ts/util/timestamp.ts at the time of creation of this migration
const MAX_SAFE_DATE = 8640000000000000;
export function updateToSchemaVersion1310(
currentVersion: number,
db: WritableDB,
logger: LoggerType
): void {
if (currentVersion >= 1310) {
return;
}
db.transaction(() => {
const [query, params] = sql`
UPDATE conversations
SET json = json_replace(
json,
'$.muteExpiresAt',
9007199254740991 -- max safe integer
)
WHERE json ->> '$.muteExpiresAt' IS ${MAX_SAFE_DATE};
`;
const { changes } = db.prepare(query).run(params);
if (changes !== 0) {
logger.warn(`updateToSchemaVersion1310: fixed ${changes} conversations`);
}
db.pragma('user_version = 1310');
})();
logger.info('updateToSchemaVersion1310: success!');
}

View file

@ -106,10 +106,11 @@ import { updateToSchemaVersion1260 } from './1260-sync-tasks-rowid';
import { updateToSchemaVersion1270 } from './1270-normalize-messages';
import { updateToSchemaVersion1280 } from './1280-blob-unprocessed';
import { updateToSchemaVersion1290 } from './1290-int-unprocessed-source-device';
import { updateToSchemaVersion1300 } from './1300-sticker-pack-refs';
import {
updateToSchemaVersion1300,
updateToSchemaVersion1310,
version as MAX_VERSION,
} from './1300-sticker-pack-refs';
} from './1310-muted-fixup';
import { DataWriter } from '../Server';
function updateToSchemaVersion1(
@ -2087,6 +2088,7 @@ export const SCHEMA_VERSIONS = [
updateToSchemaVersion1290,
updateToSchemaVersion1300,
updateToSchemaVersion1310,
];
export class DBVersionFromFutureError extends Error {

View file

@ -0,0 +1,80 @@
// Copyright 2025 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import { type WritableDB } from '../../sql/Interface';
import { createDB, updateToVersion, insertData, getTableData } from './helpers';
describe('SQL/updateToSchemaVersion1310', () => {
let db: WritableDB;
afterEach(() => {
db.close();
});
beforeEach(() => {
db = createDB();
updateToVersion(db, 1300);
});
it('leaves absent muteExpiresAt untouched', () => {
const convos = [
{
id: 'convo',
expireTimerVersion: 1,
json: {},
},
];
insertData(db, 'conversations', convos);
updateToVersion(db, 1310);
assert.deepStrictEqual(getTableData(db, 'conversations'), convos);
});
it('leaves regular muteExpiresAt untouched', () => {
const convos = [
{
id: 'convo',
expireTimerVersion: 1,
json: {
muteExpiresAt: 123,
},
},
{
id: 'convo-2',
expireTimerVersion: 1,
json: {
muteExpiresAt: 8640000000000000 - 1,
},
},
];
insertData(db, 'conversations', convos);
updateToVersion(db, 1310);
assert.deepStrictEqual(getTableData(db, 'conversations'), convos);
});
it('promotes MAX_SAFE_DATE to MAX_SAFE_INTEGER', () => {
insertData(db, 'conversations', [
{
id: 'convo',
expireTimerVersion: 1,
json: {
muteExpiresAt: 8640000000000000,
},
},
]);
updateToVersion(db, 1310);
assert.deepStrictEqual(getTableData(db, 'conversations'), [
{
id: 'convo',
expireTimerVersion: 1,
json: {
muteExpiresAt: Number.MAX_SAFE_INTEGER,
},
},
]);
});
});

View file

@ -19,7 +19,10 @@ export function getSafeLongFromTimestamp(
return Long.fromNumber(timestamp);
}
export function getTimestampFromLong(value?: Long | null): number {
export function getTimestampFromLong(
value?: Long | null,
maxValue = MAX_SAFE_DATE
): number {
if (!value || value.isNegative()) {
return 0;
}
@ -27,7 +30,7 @@ export function getTimestampFromLong(value?: Long | null): number {
const num = value.toNumber();
if (num > MAX_SAFE_DATE) {
return MAX_SAFE_DATE;
return maxValue;
}
return num;