fix: split up migration of initial user config dumps into two

This commit is contained in:
Audric Ackermann 2023-05-01 14:31:18 +10:00
parent 7bb0e52dce
commit 6fe6544d6c
6 changed files with 91 additions and 24 deletions

View File

@ -9,7 +9,8 @@ const updateLocalConfig = () => {
var hash = '';
try {
// TODO make sure that this works well on windows and macOS builds
// this was tested on windows, linux and macOS builds through the CI and works fine, but might require to make git available in the PATH when building unofficial builds.
// this is used to udpate the hash of the commit in the UI at the bottom of the settings screen, and in the about view
var stdout = execSync('git rev-parse HEAD').toString();
console.info('"git rev-parse HEAD" result: ', stdout && stdout.trim());

View File

@ -14,5 +14,5 @@ mv $PWD/_locales/zh-TW $PWD/_locales/zh_TW
echo 'Updated locales from crowdin to session-desktop folder'
python2 $PWD/tools/updateI18nKeysType.py
python3 $PWD/tools/updateI18nKeysType.py

View File

@ -229,15 +229,22 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
}
/**
* Returns true if this conversation is active
* i.e. the conversation is visibie on the left pane. (Either we or another user created this convo).
* This is useful because we do not want bumpTyping on the first message typing to a new convo to
* send a message.
* Returns true if this conversation is active.
* i.e. the conversation is visible on the left pane. (Either we or another user created this convo).
* An active conversation is a user/group we interacted with directly, or they did, at some point.
* For instance, all of the conversations created when receiving a community are not active, until we start directly talking with them (or they do).
*/
public isActive() {
return Boolean(this.get('active_at'));
}
/**
*
* @returns true if this conversation is private and hidden.
* A non-private conversation cannot be hidden currently.
* - a community is removed straight away when we leave it and not marked hidden
* - a legacy group is kept visible if we leave it, until we explicitely delete it. At that time, it is removed completely and not marked hidden
*/
public isHidden() {
const priority = this.get('priority') || CONVERSATION_PRIORITIES.default;
return this.isPrivate() && priority === CONVERSATION_PRIORITIES.hidden;

View File

@ -97,6 +97,7 @@ const LOKI_SCHEMA_VERSIONS = [
updateToSessionSchemaVersion28,
updateToSessionSchemaVersion29,
updateToSessionSchemaVersion30,
updateToSessionSchemaVersion31,
];
function updateToSessionSchemaVersion1(currentVersion: number, db: BetterSqlite3.Database) {
@ -1452,7 +1453,11 @@ function updateToSessionSchemaVersion30(currentVersion: number, db: BetterSqlite
console.log(`updateToSessionSchemaVersion${targetVersion}: starting...`);
/**
* Create a table to store our sharedConfigMessage dumps
* Make all the changes required to the database structure to handle the user configs, in the next migration.
* I made two migrations because it was easier to separate
* - the part needed a user to be logged in (creating the user dumps needs a private ed25519 key)
* - from the part not requiring a change of user, but which absolutely needed to be happening nevertheless (database structure changes)
*
*/
db.transaction(() => {
// drop unused readCapability & uploadCapability columns. Also move `writeCapability` to memory only value.
@ -1472,23 +1477,30 @@ function updateToSessionSchemaVersion30(currentVersion: number, db: BetterSqlite
ALTER TABLE unprocessed DROP COLUMN serverTimestamp;
`);
// for manually flagging conversations as unread"
db.exec(`ALTER TABLE ${CONVERSATIONS_TABLE} ADD COLUMN markedAsUnread BOOLEAN;`);
// after the rename of isPinned to priority, we also need to hide any private conversation that is not active at all.
// as they might be contacts, we did delete from the app already.
// The release of message requests from other platforms (17 april 2022) created a bunch of active, but not "real contacts" conversation.
// This `UPDATE` command makes sure to make any private conversation which have was inactive since the 1st may 2022 as inactive
db.prepare(
`UPDATE ${CONVERSATIONS_TABLE} SET
active_at = 0
WHERE type = 'private' AND active_at > 0 AND active_at < ${1000 * 1651363200};` // 1st may 2022 GMT
).run({});
db.prepare(
`UPDATE ${CONVERSATIONS_TABLE} SET
priority = ${CONVERSATION_PRIORITIES.hidden}
WHERE type = 'private' AND active_at IS NULL;`
WHERE type = 'private' AND (active_at IS NULL OR active_at = 0 );`
).run({});
db.exec(`CREATE TABLE ${CONFIG_DUMP_TABLE}(
variant TEXT NOT NULL,
publicKey TEXT NOT NULL,
data BLOB,
PRIMARY KEY (publicKey, variant)
);
`);
/**
* Remove the `publicChat` prefix from the communities, instead keep the full url+room in it, with the corresponding http or https prefix.
* This is easier to handle with the libsession wrappers
**/
const allOpengroupsConvo = db
.prepare(
`SELECT id FROM ${CONVERSATIONS_TABLE} WHERE
@ -1535,6 +1547,31 @@ function updateToSessionSchemaVersion30(currentVersion: number, db: BetterSqlite
).run({ newId });
});
// create the table which is going to handle the wrappers, without any content in this migration.
db.exec(`CREATE TABLE ${CONFIG_DUMP_TABLE}(
variant TEXT NOT NULL,
publicKey TEXT NOT NULL,
data BLOB,
PRIMARY KEY (publicKey, variant)
);
`);
writeSessionSchemaVersion(targetVersion, db);
})();
console.log(`updateToSessionSchemaVersion${targetVersion}: success!`);
}
function updateToSessionSchemaVersion31(currentVersion: number, db: BetterSqlite3.Database) {
const targetVersion = 31;
if (currentVersion >= targetVersion) {
return;
}
console.log(`updateToSessionSchemaVersion${targetVersion}: starting...`);
db.transaction(() => {
// In the migration 30, we made all the changes which didn't require the user to be logged in yet.
// in this one, we check if a user is logged in, and if yes we build and save the config dumps for the current state of the database.
try {
const keys = getIdentityKeys(db);
@ -1611,7 +1648,7 @@ function updateToSessionSchemaVersion30(currentVersion: number, db: BetterSqlite
// this filter is based on the `isContactToStoreInWrapper` function. Note, blocked contacts won't be added to the wrapper at first, but will on the first start
const contactsToWriteInWrapper = db
.prepare(
`SELECT * FROM ${CONVERSATIONS_TABLE} WHERE type = 'private' AND active_at > 0 AND NOT hidden AND (didApproveMe OR isApproved) AND id <> '$us' AND id NOT LIKE '15%' ;`
`SELECT * FROM ${CONVERSATIONS_TABLE} WHERE type = 'private' AND active_at > 0 AND priority <> ${CONVERSATION_PRIORITIES.hidden} AND (didApproveMe OR isApproved) AND id <> '$us' AND id NOT LIKE '15%' ;`
)
.all({
us: publicKeyHex,
@ -1762,17 +1799,18 @@ function updateToSessionSchemaVersion30(currentVersion: number, db: BetterSqlite
// we've just created the initial dumps. A ConfSyncJob is run when the app starts after 20 seconds
} catch (e) {
console.error(`failed to create initial wrapper: `, e.stack);
console.error(
`failed to create initial wrapper. Might just not have a logged in user yet? `,
e.message,
e.stack,
e
);
// if we get an exception here, most likely no users are logged in yet. We can just continue the transaction and the wrappers will be created when a user creates a new account.
}
// for manually flagging conversations as :unread"
db.exec(`ALTER TABLE ${CONVERSATIONS_TABLE} ADD COLUMN markedAsUnread BOOLEAN;`);
// still, we update the schema version
writeSessionSchemaVersion(targetVersion, db);
})();
console.log(`updateToSessionSchemaVersion${targetVersion}: success!`);
});
}
export function printTableColumns(table: string, db: BetterSqlite3.Database) {

View File

@ -79,6 +79,14 @@ async function initializeLibSessionUtilWrappers() {
`initializeLibSessionUtilWrappers: missingRequiredVariants "${missingVariant}"`
);
await GenericWrapperActions.init(missingVariant, privateKeyEd25519, null);
// save the newly created dump to the database even if it is empty, just so we do not need to recreate one next run
const dump = await GenericWrapperActions.dump(missingVariant);
await ConfigDumpData.saveConfigDump({
data: dump,
publicKey: UserUtils.getOurPubKeyStrFromCache(),
variant: missingVariant,
});
window.log.debug(
`initializeLibSessionUtilWrappers: missingRequiredVariants "${missingVariant}" created`
);

View File

@ -77,6 +77,19 @@ describe('libsession_contacts', () => {
).to.be.eq(false);
});
it('excludes hidden but not active', () => {
expect(
SessionUtilContact.isContactToStoreInWrapper(
new ConversationModel({
...validArgs,
type: ConversationTypeEnum.PRIVATE,
priority: CONVERSATION_PRIORITIES.hidden,
active_at: 0,
} as any)
)
).to.be.eq(false);
});
it('excludes non approved by us nor did approveme and not active', () => {
expect(
SessionUtilContact.isContactToStoreInWrapper(