Fix timestamp capping for storage service
Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
This commit is contained in:
		
					parent
					
						
							
								5fc53ee435
							
						
					
				
			
			
				commit
				
					
						f15d5049f8
					
				
			
		
					 5 changed files with 141 additions and 7 deletions
				
			
		|  | @ -888,7 +888,10 @@ export async function mergeGroupV1Record( | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   conversation.setMuteExpiration( |   conversation.setMuteExpiration( | ||||||
|     getTimestampFromLong(groupV1Record.mutedUntilTimestamp), |     getTimestampFromLong( | ||||||
|  |       groupV1Record.mutedUntilTimestamp, | ||||||
|  |       Number.MAX_SAFE_INTEGER | ||||||
|  |     ), | ||||||
|     { |     { | ||||||
|       viaStorageServiceSync: true, |       viaStorageServiceSync: true, | ||||||
|     } |     } | ||||||
|  | @ -1025,7 +1028,10 @@ export async function mergeGroupV2Record( | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   conversation.setMuteExpiration( |   conversation.setMuteExpiration( | ||||||
|     getTimestampFromLong(groupV2Record.mutedUntilTimestamp), |     getTimestampFromLong( | ||||||
|  |       groupV2Record.mutedUntilTimestamp, | ||||||
|  |       Number.MAX_SAFE_INTEGER | ||||||
|  |     ), | ||||||
|     { |     { | ||||||
|       viaStorageServiceSync: true, |       viaStorageServiceSync: true, | ||||||
|     } |     } | ||||||
|  | @ -1265,7 +1271,10 @@ export async function mergeContactRecord( | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   conversation.setMuteExpiration( |   conversation.setMuteExpiration( | ||||||
|     getTimestampFromLong(contactRecord.mutedUntilTimestamp), |     getTimestampFromLong( | ||||||
|  |       contactRecord.mutedUntilTimestamp, | ||||||
|  |       Number.MAX_SAFE_INTEGER | ||||||
|  |     ), | ||||||
|     { |     { | ||||||
|       viaStorageServiceSync: true, |       viaStorageServiceSync: true, | ||||||
|     } |     } | ||||||
|  |  | ||||||
							
								
								
									
										40
									
								
								ts/sql/migrations/1310-muted-fixup.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								ts/sql/migrations/1310-muted-fixup.ts
									
										
									
									
									
										Normal 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!'); | ||||||
|  | } | ||||||
|  | @ -106,10 +106,11 @@ import { updateToSchemaVersion1260 } from './1260-sync-tasks-rowid'; | ||||||
| import { updateToSchemaVersion1270 } from './1270-normalize-messages'; | import { updateToSchemaVersion1270 } from './1270-normalize-messages'; | ||||||
| import { updateToSchemaVersion1280 } from './1280-blob-unprocessed'; | import { updateToSchemaVersion1280 } from './1280-blob-unprocessed'; | ||||||
| import { updateToSchemaVersion1290 } from './1290-int-unprocessed-source-device'; | import { updateToSchemaVersion1290 } from './1290-int-unprocessed-source-device'; | ||||||
|  | import { updateToSchemaVersion1300 } from './1300-sticker-pack-refs'; | ||||||
| import { | import { | ||||||
|   updateToSchemaVersion1300, |   updateToSchemaVersion1310, | ||||||
|   version as MAX_VERSION, |   version as MAX_VERSION, | ||||||
| } from './1300-sticker-pack-refs'; | } from './1310-muted-fixup'; | ||||||
| import { DataWriter } from '../Server'; | import { DataWriter } from '../Server'; | ||||||
| 
 | 
 | ||||||
| function updateToSchemaVersion1( | function updateToSchemaVersion1( | ||||||
|  | @ -2087,6 +2088,7 @@ export const SCHEMA_VERSIONS = [ | ||||||
|   updateToSchemaVersion1290, |   updateToSchemaVersion1290, | ||||||
| 
 | 
 | ||||||
|   updateToSchemaVersion1300, |   updateToSchemaVersion1300, | ||||||
|  |   updateToSchemaVersion1310, | ||||||
| ]; | ]; | ||||||
| 
 | 
 | ||||||
| export class DBVersionFromFutureError extends Error { | export class DBVersionFromFutureError extends Error { | ||||||
|  |  | ||||||
							
								
								
									
										80
									
								
								ts/test-node/sql/migration_1310_test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								ts/test-node/sql/migration_1310_test.ts
									
										
									
									
									
										Normal 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, | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |     ]); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
|  | @ -19,7 +19,10 @@ export function getSafeLongFromTimestamp( | ||||||
|   return Long.fromNumber(timestamp); |   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()) { |   if (!value || value.isNegative()) { | ||||||
|     return 0; |     return 0; | ||||||
|   } |   } | ||||||
|  | @ -27,7 +30,7 @@ export function getTimestampFromLong(value?: Long | null): number { | ||||||
|   const num = value.toNumber(); |   const num = value.toNumber(); | ||||||
| 
 | 
 | ||||||
|   if (num > MAX_SAFE_DATE) { |   if (num > MAX_SAFE_DATE) { | ||||||
|     return MAX_SAFE_DATE; |     return maxValue; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   return num; |   return num; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 automated-signal
				automated-signal