Receive support for Sender Key

Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
This commit is contained in:
Scott Nonnenberg 2021-05-13 18:18:43 -07:00
parent e5f9c0db28
commit e6bab06510
28 changed files with 743 additions and 164 deletions

View file

@ -48,6 +48,7 @@ import {
MessageTypeUnhydrated,
PreKeyType,
SearchResultMessageType,
SenderKeyType,
ServerInterface,
SessionType,
SignedPreKeyType,
@ -134,6 +135,11 @@ const dataInterface: ClientInterface = {
removeItemById,
removeAllItems,
createOrUpdateSenderKey,
getSenderKeyById,
removeAllSenderKeys,
getAllSenderKeys,
createOrUpdateSession,
createOrUpdateSessions,
getSessionById,
@ -736,6 +742,23 @@ async function removeAllItems() {
await channels.removeAllItems();
}
// Sender Keys
async function createOrUpdateSenderKey(key: SenderKeyType): Promise<void> {
await channels.createOrUpdateSenderKey(key);
}
async function getSenderKeyById(
id: string
): Promise<SenderKeyType | undefined> {
return channels.getSenderKeyById(id);
}
async function removeAllSenderKeys(): Promise<void> {
await channels.removeAllSenderKeys();
}
async function getAllSenderKeys(): Promise<Array<SenderKeyType>> {
return channels.getAllSenderKeys();
}
// Sessions
async function createOrUpdateSession(data: SessionType) {

View file

@ -66,6 +66,16 @@ export type ClientSearchResultMessageType = MessageType & {
bodyRanges: [];
snippet: string;
};
export type SenderKeyType = {
// Primary key
id: string;
// These two are combined into one string to give us the final id
senderId: string;
distributionId: string;
// Raw data to serialize/deserialize into signal-client SenderKeyRecord
data: Buffer;
lastUpdatedDate: number;
};
export type SessionType = {
id: string;
conversationId: string;
@ -171,6 +181,11 @@ export type DataInterface = {
removeAllItems: () => Promise<void>;
getAllItems: () => Promise<Array<ItemType>>;
createOrUpdateSenderKey: (key: SenderKeyType) => Promise<void>;
getSenderKeyById: (id: string) => Promise<SenderKeyType | undefined>;
removeAllSenderKeys: () => Promise<void>;
getAllSenderKeys: () => Promise<Array<SenderKeyType>>;
createOrUpdateSession: (data: SessionType) => Promise<void>;
createOrUpdateSessions: (array: Array<SessionType>) => Promise<void>;
getSessionById: (id: string) => Promise<SessionType | undefined>;

View file

@ -49,6 +49,7 @@ import {
MessageMetricsType,
PreKeyType,
SearchResultMessageType,
SenderKeyType,
ServerInterface,
SessionType,
SignedPreKeyType,
@ -86,7 +87,7 @@ type StickerRow = Readonly<{
type EmptyQuery = [];
type ArrayQuery = Array<Array<null | number | string>>;
type Query = { [key: string]: null | number | string };
type Query = { [key: string]: null | number | string | Buffer };
// Because we can't force this module to conform to an interface, we narrow our exports
// to this one default export, which does conform to the interface.
@ -125,6 +126,11 @@ const dataInterface: ServerInterface = {
removeItemById,
removeAllItems,
createOrUpdateSenderKey,
getSenderKeyById,
removeAllSenderKeys,
getAllSenderKeys,
createOrUpdateSession,
createOrUpdateSessions,
getSessionById,
@ -1625,6 +1631,7 @@ async function updateToSchemaVersion25(currentVersion: number, db: Database) {
db.pragma('user_version = 25');
})();
console.log('updateToSchemaVersion25: success!');
}
async function updateToSchemaVersion26(currentVersion: number, db: Database) {
@ -1660,6 +1667,7 @@ async function updateToSchemaVersion26(currentVersion: number, db: Database) {
db.pragma('user_version = 26');
})();
console.log('updateToSchemaVersion26: success!');
}
async function updateToSchemaVersion27(currentVersion: number, db: Database) {
@ -1697,6 +1705,7 @@ async function updateToSchemaVersion27(currentVersion: number, db: Database) {
db.pragma('user_version = 27');
})();
console.log('updateToSchemaVersion27: success!');
}
function updateToSchemaVersion28(currentVersion: number, db: Database) {
@ -1718,6 +1727,7 @@ function updateToSchemaVersion28(currentVersion: number, db: Database) {
db.pragma('user_version = 28');
})();
console.log('updateToSchemaVersion28: success!');
}
function updateToSchemaVersion29(currentVersion: number, db: Database) {
@ -1751,6 +1761,28 @@ function updateToSchemaVersion29(currentVersion: number, db: Database) {
db.pragma('user_version = 29');
})();
console.log('updateToSchemaVersion29: success!');
}
function updateToSchemaVersion30(currentVersion: number, db: Database) {
if (currentVersion >= 30) {
return;
}
db.transaction(() => {
db.exec(`
CREATE TABLE senderKeys(
id TEXT PRIMARY KEY NOT NULL,
senderId TEXT NOT NULL,
distributionId TEXT NOT NULL,
data BLOB NOT NULL,
lastUpdatedDate NUMBER NOT NULL
);
`);
db.pragma('user_version = 30');
})();
console.log('updateToSchemaVersion30: success!');
}
const SCHEMA_VERSIONS = [
@ -1783,6 +1815,7 @@ const SCHEMA_VERSIONS = [
updateToSchemaVersion27,
updateToSchemaVersion28,
updateToSchemaVersion29,
updateToSchemaVersion30,
];
function updateSchema(db: Database): void {
@ -2087,6 +2120,49 @@ function removeAllItems(): Promise<void> {
return removeAllFromTable(ITEMS_TABLE);
}
async function createOrUpdateSenderKey(key: SenderKeyType): Promise<void> {
const db = getInstance();
prepare(
db,
`
INSERT OR REPLACE INTO senderKeys (
id,
senderId,
distributionId,
data,
lastUpdatedDate
) values (
$id,
$senderId,
$distributionId,
$data,
$lastUpdatedDate
)
`
).run(key);
}
async function getSenderKeyById(
id: string
): Promise<SenderKeyType | undefined> {
const db = getInstance();
const row = prepare(db, 'SELECT * FROM senderKeys WHERE id = $id').get({
id,
});
return row;
}
async function removeAllSenderKeys(): Promise<void> {
const db = getInstance();
prepare(db, 'DELETE FROM senderKeys').run({});
}
async function getAllSenderKeys(): Promise<Array<SenderKeyType>> {
const db = getInstance();
const rows = prepare(db, 'SELECT * FROM senderKeys').all({});
return rows;
}
const SESSIONS_TABLE = 'sessions';
async function createOrUpdateSession(data: SessionType): Promise<void> {
const db = getInstance();
@ -4635,6 +4711,7 @@ async function removeAll(): Promise<void> {
DELETE FROM items;
DELETE FROM messages;
DELETE FROM preKeys;
DELETE FROM senderKeys;
DELETE FROM sessions;
DELETE FROM signedPreKeys;
DELETE FROM unprocessed;
@ -4657,6 +4734,7 @@ async function removeAllConfiguration(): Promise<void> {
DELETE FROM identityKeys;
DELETE FROM items;
DELETE FROM preKeys;
DELETE FROM senderKeys;
DELETE FROM sessions;
DELETE FROM signedPreKeys;
DELETE FROM unprocessed;

View file

@ -37,6 +37,7 @@ type CleanedDataValue =
| boolean
| null
| undefined
| Buffer
| CleanedObject
| CleanedArray;
/* eslint-disable no-restricted-syntax */
@ -110,6 +111,10 @@ function cleanDataInner(
return undefined;
}
if (data instanceof Buffer) {
return data;
}
const dataAsRecord = data as Record<string, unknown>;
if (