feat(journals): extract decryption logic to helper and improve Quick Add behavior

- Extracted journal entry decryption workflow to 'ae_journals_decryption.ts' to decouple it from Svelte reactivity and address loop issues.
- Updated 'ae_comp__journal_entry_obj_id_view.svelte' to use the new decryption helper.
- Refactored 'Quick Add' to use the first line as the title and remove it from the content before saving.
This commit is contained in:
Scott Idem
2026-01-14 15:52:02 -05:00
parent 8c9788bd41
commit 6562d4ba04
4 changed files with 151 additions and 19 deletions

View File

@@ -0,0 +1,90 @@
import { ae_util } from '$lib/ae_utils/ae_utils';
import type { ae_JournalEntry, ae_Journal } from '$lib/types/ae_types';
/**
* Result structure for decryption operations.
*/
export interface DecryptionResult {
success: boolean;
content?: string;
history?: string;
error?: string;
}
/**
* Decrypts a journal entry's content and history using the provided or stored passcode.
*
* @param entry The journal entry object to decrypt.
* @param journal The parent journal object (provides base passcode and private_passcode).
* @param typed_passcode Optional: A user-entered passcode override.
* @returns A Promise resolving to a DecryptionResult.
*/
export async function decrypt_journal_entry(
entry: ae_JournalEntry,
journal: ae_Journal,
typed_passcode?: string
): Promise<DecryptionResult> {
// Safety check: if not encrypted, return as-is
if (!entry.content_encrypted) {
return {
success: true,
content: entry.content ?? '',
history: entry.history ?? ''
};
}
// Determine which key to use
let journal_key = typed_passcode;
// If no override, try the private passcode stored on the journal object
if (!journal_key?.length) {
journal_key = journal.private_passcode;
}
if (!journal_key) {
return {
success: false,
error: 'No passcode provided or available for decryption.'
};
}
// Aether standard: combine the journal's public passcode with the private key
const decrypt_key = `${journal.passcode ?? ''}:${journal_key}`;
try {
// Decrypt Primary Content
const result = await ae_util.decrypt_wrapper(entry.content_encrypted, decrypt_key);
if (result === false) {
return {
success: false,
error: 'Decryption failed. Incorrect passcode or corrupted data.'
};
}
const decrypted_text = typeof result === 'string' ? result : '';
let decrypted_history = '';
// Decrypt History (if it exists)
if (entry.history_encrypted) {
const h_res = await ae_util.decrypt_wrapper(entry.history_encrypted, decrypt_key);
if (h_res !== false) {
decrypted_history = typeof h_res === 'string' ? h_res : '';
}
}
return {
success: true,
content: decrypted_text,
history: decrypted_history
};
} catch (err: any) {
console.error('decrypt_journal_entry error:', err);
return {
success: false,
error: `System error during decryption: ${err.message}`
};
}
}

View File

@@ -18,6 +18,7 @@
import { ae_loc, ae_api } from '$lib/stores/ae_stores';
import { journals_loc, journals_sess, journals_slct } from '$lib/ae_journals/ae_journals_stores';
import { journals_func } from '$lib/ae_journals/ae_journals_functions';
import { decrypt_journal_entry } from '$lib/ae_journals/ae_journals_decryption';
import JournalEntry_Editor from './JournalEntry_Editor.svelte';
import JournalEntry_Header from './JournalEntry_Header.svelte';
@@ -125,9 +126,7 @@
if (!journal?.id) return;
let journal_key = $journals_sess.journal_kv[journal.id]?.typed_journal_passcode;
if (!journal_key?.length) journal_key = journal.private_passcode;
if (!journal_key) return;
is_processing = true;
decryption_error = null;
@@ -137,11 +136,10 @@
return s;
});
const decrypt_key = `${journal.passcode ?? ''}:${journal_key}`;
const result = await ae_util.decrypt_wrapper($lq__journal_entry_obj?.content_encrypted, decrypt_key);
const result = await decrypt_journal_entry($lq__journal_entry_obj, journal, journal_key);
if (result === false) {
decryption_error = 'Decryption failed. Incorrect passcode or corrupted data.';
if (!result.success) {
decryption_error = result.error || 'Decryption failed.';
journals_sess.update(s => {
s.journal_kv[journal.id].journal_passcode_verified = false;
s.journal_kv[journal.id].journal_passcode_decrypted = false;
@@ -152,18 +150,13 @@
}
// SUCCESS
const decrypted_text = typeof result === 'string' ? result : '';
tmp_entry_obj.content = decrypted_text;
tmp_entry_obj.content_md_html = handle_marked(decrypted_text);
if (orig_entry_obj) orig_entry_obj.content = decrypted_text;
tmp_entry_obj.content = result.content;
tmp_entry_obj.content_md_html = handle_marked(result.content || '');
if (orig_entry_obj) orig_entry_obj.content = result.content;
// Decrypt History
if ($lq__journal_entry_obj?.history_encrypted) {
const h_res = await ae_util.decrypt_wrapper($lq__journal_entry_obj.history_encrypted, decrypt_key);
if (h_res !== false) {
tmp_entry_obj.history = h_res;
if (orig_entry_obj) orig_entry_obj.history = h_res;
}
if (result.history) {
tmp_entry_obj.history = result.history;
if (orig_entry_obj) orig_entry_obj.history = result.history;
}
journals_sess.update(s => {

View File

@@ -36,9 +36,12 @@
let name = lines[0].substring(0, 100);
if (lines[0].length > 100) name += "...";
// Remove the first line (title) from the content
const entry_content = lines.slice(1).join('\n').trim();
const data_kv = {
name: name,
content: note_content,
content: entry_content,
type_code: 'note',
private: false, // Ensure notes are public/decrypted by default
enable: true,