feat: Initial clean release of CHM
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled

这个提交包含在:
chen
2026-11-04 11:29:39 +08:00
当前提交 301194963b
共有 8663 个文件被更改,包括 1962691 次插入 和 0 次删除

查看文件

@@ -0,0 +1,49 @@
import { NoteEntity } from '../database/types';
import NoteLockService from './NoteLockService';
import type { DecryptedNoteLockKey } from './NoteLockKey';
// The marker a gated load stamps on a note. Not a database column, so it cannot live on the
// generated NoteEntity type.
export type NoteLockNoteEntity = NoteEntity & { isDecrypted?: boolean };
export default class NoteLockNote {
public static isLocked(note: NoteEntity): boolean {
if (!note) return false;
return !!note.is_locked;
}
public static isLocking(note: NoteEntity, oldNote: NoteEntity): boolean {
if (!oldNote) return false;
return this.isLocked(note) && !oldNote.is_locked;
}
public static async decryptBody(note: NoteEntity, key: DecryptedNoteLockKey = null): Promise<NoteLockNoteEntity> {
if (!note) throw new Error('Gated note lock load is missing note');
if (note.is_locked === undefined) throw new Error('Gated note lock load is missing lock state');
const isLocked = this.isLocked(note);
// The marker means the note was loaded with the gate, locked or not.
const result = { ...note, isDecrypted: true };
if (isLocked) {
// A missing body here means the gated load did not request enough fields, so pass an empty string and let decryption fail explicitly.
result.body = await NoteLockService.withDecryptedKey(scoped => scoped.decryptString(note.body ?? ''), key);
}
return result;
}
public static async prepareForSave(note: NoteLockNoteEntity, linkedItemIds: (body: string)=> string[], serializeResourceIds: (resourceIds: string[])=> string, isNew: boolean, useNoteLock: boolean, key: DecryptedNoteLockKey = null) {
if (!note) throw new Error('Gated note lock save is missing note');
if (!('body' in note)) throw new Error('Gated note lock save is missing body');
const isLocked = this.isLocked(note);
// The marker proves the data came from a gated load, so a cipher body is never encrypted
// a second time and a missed gated load fails during development, locked note or not.
if (useNoteLock && !isNew && !note.isDecrypted) throw new Error('Gated note lock save is missing decrypted state');
if (!isLocked) note.extracted_resource_ids = '';
const plainTextBody = note.body ?? '';
if (isLocked) {
note.extracted_resource_ids = serializeResourceIds(linkedItemIds(plainTextBody));
note.body = await NoteLockService.withDecryptedKey(scoped => scoped.encryptString(plainTextBody), key);
}
}
}