From 8c81f6f65e58e3a4c3256aafe284e463d729c4e6 Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Thu, 8 May 2025 19:37:15 -0400 Subject: [PATCH] Work on making the Journal Entry saving better. --- .../ae_events__event_presentation.ts | 4 +- .../ae_journals/ae_journals__journal_entry.ts | 147 +++++-- src/lib/ae_journals/ae_journals_stores.ts | 1 + src/lib/ae_utils/ae_utils__crypto.ts | 45 ++- .../ae_comp__journal_entry_obj_id_view.svelte | 373 ++++++++++++++---- 5 files changed, 437 insertions(+), 133 deletions(-) diff --git a/src/lib/ae_events/ae_events__event_presentation.ts b/src/lib/ae_events/ae_events__event_presentation.ts index 8d803aac..459eae95 100644 --- a/src/lib/ae_events/ae_events__event_presentation.ts +++ b/src/lib/ae_events/ae_events__event_presentation.ts @@ -411,7 +411,9 @@ export async function update_ae_obj__event_presentation( if (event_presentation_obj_update_result) { if (try_cache) { db_save_ae_obj_li__event_presentation({ - obj_type: 'event_presentation', obj_li: [event_presentation_obj_update_result] + obj_type: 'event_presentation', + obj_li: [event_presentation_obj_update_result], + log_lvl: log_lvl }); } return event_presentation_obj_update_result; diff --git a/src/lib/ae_journals/ae_journals__journal_entry.ts b/src/lib/ae_journals/ae_journals__journal_entry.ts index 3868027b..b7dfda0a 100644 --- a/src/lib/ae_journals/ae_journals__journal_entry.ts +++ b/src/lib/ae_journals/ae_journals__journal_entry.ts @@ -261,27 +261,90 @@ export async function delete_ae_obj_id__journal_entry( // Updated 2025-03-15 +// export async function update_ae_obj__journal_entry( +// { +// api_cfg, +// journal_entry_id, +// data_kv, +// params = {}, +// try_cache = true, +// log_lvl = 0 +// }: { +// api_cfg: any, +// journal_entry_id: string, +// data_kv: key_val, +// params?: key_val, +// try_cache?: boolean, +// log_lvl?: number +// } +// ) { +// if (log_lvl) { +// console.log(`*** update_ae_obj__journal_entry() *** journal_entry_id=${journal_entry_id}`, data_kv); +// } +// ae_promises.update__journal_entry_obj = api.update_ae_obj_id_crud({ +// api_cfg: api_cfg, +// obj_type: 'journal_entry', +// obj_id: journal_entry_id, +// fields: data_kv, +// key: api_cfg.api_crud_super_key, +// params: params, +// return_obj: true, +// log_lvl: log_lvl +// }) +// .then(async function (journal_entry_obj_update_result) { +// // if (journal_entry_obj_update_result) { +// if (try_cache) { +// db_save_ae_obj_li__journal_entry({ +// obj_type: 'journal_entry', +// obj_li: [journal_entry_obj_update_result], +// log_lvl: log_lvl +// }) +// .then(function (result) { +// return result; +// }) +// .finally(function () { +// return journal_entry_obj_update_result; +// }); +// } else { +// return journal_entry_obj_update_result; +// } +// // } else { +// // return null; +// // } +// }) +// .catch(function (error) { +// console.log('No results returned or failed.', error); +// }) +// .finally(function () { +// }); + +// if (log_lvl) { +// console.log('ae_promises.update__journal_entry_obj:', ae_promises.update__journal_entry_obj); +// } +// return await ae_promises.update__journal_entry_obj; +// } + export async function update_ae_obj__journal_entry( - { - api_cfg, - journal_entry_id, - data_kv, - params = {}, - try_cache = true, - log_lvl = 0 - }: { - api_cfg: any, - journal_entry_id: string, - data_kv: key_val, - params?: key_val, - try_cache?: boolean, - log_lvl?: number - } - ) { + { + api_cfg, + journal_entry_id, + data_kv, + params = {}, + try_cache = true, + log_lvl = 0, + }: { + api_cfg: any; + journal_entry_id: string; + data_kv: key_val; + params?: key_val, + try_cache?: boolean, + log_lvl?: number; + }) { if (log_lvl) { console.log(`*** update_ae_obj__journal_entry() *** journal_entry_id=${journal_entry_id}`, data_kv); } - ae_promises.update__journal_entry_obj = await api.update_ae_obj_id_crud({ + + const result = await api.update_ae_obj_id_crud({ api_cfg: api_cfg, obj_type: 'journal_entry', obj_id: journal_entry_id, @@ -289,31 +352,24 @@ export async function update_ae_obj__journal_entry( key: api_cfg.api_crud_super_key, params: params, return_obj: true, - log_lvl: log_lvl - }) - .then(async function (journal_entry_obj_update_result) { - if (journal_entry_obj_update_result) { - if (try_cache) { - await db_save_ae_obj_li__journal_entry({ - obj_type: 'journal_entry', obj_li: [journal_entry_obj_update_result], - log_lvl: log_lvl - }); - } - return journal_entry_obj_update_result; - } else { - return null; - } - }) - .catch(function (error) { - console.log('No results returned or failed.', error); - }) - .finally(function () { + log_lvl: log_lvl, }); - if (log_lvl) { - console.log('ae_promises.update__journal_entry_obj:', ae_promises.update__journal_entry_obj); + if (result) { + if (try_cache) { + console.log('Saving to DB...'); + await db_save_ae_obj_li__journal_entry({ + obj_type: 'journal_entry', + obj_li: [result], + log_lvl: log_lvl, + }); + console.log('DB save completed.'); + } + return result; + } else { + console.error('Failed to update journal entry.'); + return null; } - return ae_promises.update__journal_entry_obj; } @@ -331,11 +387,14 @@ export async function db_save_ae_obj_li__journal_entry( } ) { if (log_lvl) { - console.log(`*** db_save_ae_obj_li__journal_entry() ***`, log_lvl); + console.log(`*** db_save_ae_obj_li__journal_entry() *** obj_type=${obj_type}`, obj_li); } if (obj_li && obj_li.length) { - obj_li.forEach(async function (obj: any) { + // let obj_li_id = obj_li.map((obj: any) => obj.journal_entry_id_random); + let obj_li_id: string[] = []; + for (const obj of obj_li) { + // obj_li.forEach(async function (obj: any) { if (log_lvl) { console.log(`ae_obj ${obj_type}:`, obj); } @@ -501,6 +560,7 @@ export async function db_save_ae_obj_li__journal_entry( if (log_lvl) { console.log(`Updated record with ID: ${obj_record.id}`); } + obj_li_id.push(obj_record.id); } if (!id_random) { console.log(`Failed to save record with ID: ${obj_record.id}`); @@ -509,8 +569,9 @@ export async function db_save_ae_obj_li__journal_entry( console.log(`Saved record with ID: ${obj_record.id}`); } } - }); + // }); + } - return true; + return obj_li_id; } } diff --git a/src/lib/ae_journals/ae_journals_stores.ts b/src/lib/ae_journals/ae_journals_stores.ts index 43dcf38a..d738b955 100644 --- a/src/lib/ae_journals/ae_journals_stores.ts +++ b/src/lib/ae_journals/ae_journals_stores.ts @@ -88,6 +88,7 @@ let journals_session_data_struct: key_val = { tmp_obj: {}, }, entry: { + decrypt_kv: {}, // Essentially flag that the entry (content and history) can be decrypted. edit: false, edit_kv: {}, diff --git a/src/lib/ae_utils/ae_utils__crypto.ts b/src/lib/ae_utils/ae_utils__crypto.ts index 40fdce30..34f63bf5 100644 --- a/src/lib/ae_utils/ae_utils__crypto.ts +++ b/src/lib/ae_utils/ae_utils__crypto.ts @@ -1,12 +1,13 @@ -let log_lvl = 1; // 0 = no logging, 1 = some logging, 2 = all logging +let log_lvl = 0; // 0 = no logging, 1 = some logging, 2 = all logging +// Updated 2025-05-08 async function generate_iv() { const data = new Uint8Array(16); crypto.getRandomValues(data); return data; } - +// Updated 2025-05-08 export let encrypt_content = async function encrypt_content( content: string, keyData: string @@ -16,36 +17,52 @@ export let encrypt_content = async function encrypt_content( const key = await crypto.subtle.importKey('raw', keyBytes, { name: 'AES-CBC' }, false, ['encrypt']); const encodedContent = await crypto.subtle.encrypt({ name: 'AES-CBC', iv }, key, new TextEncoder().encode(content)); const base64 = btoa(String.fromCharCode(...new Uint8Array(encodedContent))); - console.log('Base64 Encoded Content:', base64); + if (log_lvl) { + console.log(`IV: ${iv}; Encrypted:`, base64); + } return { base64, iv }; } +// Updated 2025-05-08 export let combine_iv_and_base64 = function combine_iv_and_base64( base64: string, iv: Uint8Array ) { - console.log(`IV: ${iv}; Encrypted: ${base64}`); + if (log_lvl) { + console.log(`IV: ${iv}; Encrypted:`, base64); + } // Combine the IV and encrypted content const combined = Array.from(iv).map(byte => byte.toString(16).padStart(2, '0')).join('') + ':' + base64; - console.log('Combined Data v1:', combined); - + if (log_lvl) { + console.log('Combined IV and Base64:', combined); + } // const ivBase64 = btoa(String.fromCharCode(...iv)); // const combined = `${ivBase64}:${base64}`; // console.log('Combined IV and Base64 v2:', combined); return combined; } +// Updated 2025-05-08 export let encrypt_wrapper = async function encrypt_wrapper( content: string, keyData: string ) { + if (!content) { + console.error('No content provided. Returning empty string.'); + return ''; + } + if (!keyData) { + console.error('No keyData provided. Returning empty string.'); + return ''; + } const { base64, iv } = await encrypt_content(content, keyData); const combined = combine_iv_and_base64(base64, iv); return combined; } // This does not handle errors (invalid key/password) well. +// Updated 2025-05-08 export let decrypt_content = async function decrypt_content( base64Content: string, iv: Uint8Array, @@ -60,14 +77,19 @@ export let decrypt_content = async function decrypt_content( return decodedContent; } +// Updated 2025-05-08 export let split_iv_and_base64 = function split_iv_and_base64( combined: string ) { + if (!combined) { + console.error('No combined string provided. Returning empty object.'); + return { iv: new Uint8Array(), base64: '' }; + } let [iv_hex, encrypted_base64_string] = combined.split(':'); let base64 = encrypted_base64_string let iv = new Uint8Array(iv_hex.match(/.{1,2}/g).map(byte => parseInt(byte, 16))); if (log_lvl) { - console.log(`IV: ${iv}; Encrypted: ${base64}`); + console.log(`IV: ${iv}; Encrypted:`, base64); } // const [ivBase64, base64] = combined.split(':'); @@ -78,14 +100,21 @@ export let split_iv_and_base64 = function split_iv_and_base64( return { iv, base64 }; } +// Updated 2025-05-08 export let decrypt_wrapper = async function decrypt_wrapper( combined: string, keyData: string ) { + if (!combined) { + console.error('No combined string provided. Returning empty string.'); + return ''; + } const { iv, base64 } = split_iv_and_base64(combined); const decrypted = await decrypt_content(base64, iv, keyData); - if (log_lvl) { + if (log_lvl > 1) { console.log(`IV: ${iv}; Decrypted:`, decrypted); + } else if (log_lvl) { + console.log(`IV: ${iv}`); } return decrypted; } \ No newline at end of file diff --git a/src/routes/journals/ae_comp__journal_entry_obj_id_view.svelte b/src/routes/journals/ae_comp__journal_entry_obj_id_view.svelte index 62478940..82ad1c67 100644 --- a/src/routes/journals/ae_comp__journal_entry_obj_id_view.svelte +++ b/src/routes/journals/ae_comp__journal_entry_obj_id_view.svelte @@ -1,6 +1,7 @@ @@ -1270,6 +1442,7 @@ function handle_cut_string(old_string: string) { // Setting private to false will cause the update_journal_entry() function to decrypt the content. This will also copy it to tmp_entry_obj.content. tmp_entry_obj.private = false; + // tmp_entry_obj. // handle_decrypt_content(); update_journal_entry(); } else { @@ -1299,28 +1472,50 @@ function handle_cut_string(old_string: string) { decrypted_content = ''; // tmp_entry_obj.content = null; } else if (tmp_entry_obj?.private && tmp_entry_obj?.content_encrypted) { - if (confirm('Are you sure you want to decrypt the content to view/edit?')) { - // trigger_decrypt = true; - // handle_decrypt_content(); - // handle_decrypt_string(tmp_entry_obj?.content_encrypted, journal_key).then((result) => { - // decrypted_content = result; - // console.log('TEST: Decrypted content:', decrypted_content); - // }); - decrypted_content = await ae_util.decrypt_wrapper(tmp_entry_obj?.content_encrypted, journal_key); + if (!$journals_loc?.entry?.decrypt_kv[$lq__journal_entry_obj?.journal_entry_id]) { + if (confirm('Are you sure you want to decrypt the content to view/edit?')) { + $journals_loc.entry.decrypt_kv[$lq__journal_entry_obj?.journal_entry_id] = true; + $journals_loc.entry.edit_kv[$lq__journal_entry_obj?.journal_entry_id] = 'current'; - // decrypted_content = await handle_decrypt_string(tmp_entry_obj?.content_encrypted, journal_key); - tmp_entry_obj.content = decrypted_content; - console.log('TEST: Decrypted content:', decrypted_content); + if (!tmp_entry_obj?.content && tmp_entry_obj?.content_encrypted) { + console.log('TEST: Decrypting the content...'); + tmp_entry_obj.content = await ae_util.decrypt_wrapper(tmp_entry_obj?.content_encrypted, journal_key); + tmp_entry_obj.content_md_html = handle_marked(tmp_entry_obj?.content); + } + if (!tmp_entry_obj?.history && tmp_entry_obj?.history_encrypted) { + console.log('TEST: Decrypting the history...'); + tmp_entry_obj.history = await ae_util.decrypt_wrapper(tmp_entry_obj?.history_encrypted, journal_key); + tmp_entry_obj.history_md_html = handle_marked(tmp_entry_obj?.history); + } + // trigger_decrypt = true; + // handle_decrypt_content(); + // handle_decrypt_string(tmp_entry_obj?.content_encrypted, journal_key).then((result) => { + // decrypted_content = result; + // console.log('TEST: Decrypted content:', decrypted_content); + // }); + // decrypted_content = await ae_util.decrypt_wrapper(tmp_entry_obj?.content_encrypted, journal_key); + + // // decrypted_content = await handle_decrypt_string(tmp_entry_obj?.content_encrypted, journal_key); + // tmp_entry_obj.content = decrypted_content; + // console.log('TEST: Decrypted content:', decrypted_content); + } else { + return false; + } } else { - return false; + $journals_loc.entry.decrypt_kv[$lq__journal_entry_obj?.journal_entry_id] = false; + $journals_loc.entry.edit_kv[$lq__journal_entry_obj?.journal_entry_id] = false; + tmp_entry_obj.content = null; + tmp_entry_obj.content_md_html = null; + tmp_entry_obj.history = null; + tmp_entry_obj.history_md_html = null; } } }} - class:hidden={!$lq__journal_entry_obj?.private} + class:hidden={!$lq__journal_entry_obj?.private || !tmp_entry_obj?.content_encrypted} class="btn-icon btn-icon-sm variant-soft-secondary hover:variant-filled-secondary transition" title="Toggle viewing/editing of private encrypted content" > - {#if $lq__journal_entry_obj?.private && decrypted_content} + {#if $lq__journal_entry_obj?.private && tmp_entry_obj?.content} {:else if $lq__journal_entry_obj?.private && tmp_entry_obj?.content_encrypted} @@ -1588,7 +1783,19 @@ tabindex={$ae_loc.edit_mode ? 0 : -1} --> " id="rendered_journal_entry_content_{$lq__journal_entry_obj?.journal_entry_id}" > - {#if decrypted_content?.length} + {#if tmp_entry_obj.content_md_html} + {@html tmp_entry_obj.content_md_html} + {:else if tmp_entry_obj?.content_encrypted && tmp_entry_obj?.private} +
+ +
Encrypted:
+ +
+ {tmp_entry_obj?.content_encrypted} +
+
+ {/if} + {:else} {@html $lq__journal_entry_obj?.content_md_html} - {/if} + {/if} --> - {#if ($lq__journal_entry_obj?.content_encrypted && !decrypted_content)} + {#if (!tmp_entry_obj?.content && tmp_entry_obj?.content_encrypted)}
--> +