diff --git a/src/lib/ae_journals/ae_journals__journal.ts b/src/lib/ae_journals/ae_journals__journal.ts
index dddc378a..b9cd3dd0 100644
--- a/src/lib/ae_journals/ae_journals__journal.ts
+++ b/src/lib/ae_journals/ae_journals__journal.ts
@@ -720,6 +720,8 @@ export async function db_save_ae_obj_li__journal(
passcode: obj.passcode, // For Journal Entry encryption password
passcode_timeout: obj.passcode_timeout,
+ private_passcode: obj.private_passcode, // Combine with Journal passcode to encrypt and decrypt Entries
+
auth_key: obj.auth_key, // For Journal authorization without sign in
enable: obj.enable,
@@ -738,6 +740,8 @@ export async function db_save_ae_obj_li__journal(
// tmp_sort_1: `${obj.original_datetime}_${obj.group}_${obj.priority}_${obj.sort}`,
// tmp_sort_2: `${obj.group}_${obj.original_datetime}_${obj.priority}_${obj.sort}`,
+ combined_passcode: `${obj.passcode}:${obj.private_passcode}`, // Combined Journal passcode and Journal private passcode to encrypt and decrypt Entries
+
// From SQL view
journal_entry_count: obj.journal_entry_count,
@@ -834,6 +838,8 @@ let properties_to_save = [
'passcode', // For Journal Entry encryption password
'passcode_timeout',
+ 'private_passcode', // Combine with Journal passcode to encrypt and decrypt Entries
+
'auth_key', // For Journal authorization without sign in
'enable',
@@ -852,6 +858,8 @@ let properties_to_save = [
// tmp_sort_1: `${obj.original_datetime}_${obj.group}_${obj.priority}_${obj.sort}`,
// tmp_sort_2: `${obj.group}_${obj.original_datetime}_${obj.priority}_${obj.sort}`,
+ 'combined_passcode',
+
// From SQL view
'journal_entry_count',
@@ -945,6 +953,8 @@ export async function process_ae_obj__journal_props(
passcode: obj.passcode, // For Journal Entry encryption password
passcode_timeout: obj.passcode_timeout,
+ private_passcode: obj.private_passcode, // Combine with Journal passcode to encrypt and decrypt Entries
+
auth_key: obj.auth_key, // For Journal authorization without sign in
enable: obj.enable,
@@ -963,6 +973,8 @@ export async function process_ae_obj__journal_props(
// tmp_sort_1: `${obj.original_datetime}_${obj.group}_${obj.priority}_${obj.sort}`,
// tmp_sort_2: `${obj.group}_${obj.original_datetime}_${obj.priority}_${obj.sort}`,
+ combined_passcode: `${obj.passcode}:${obj.private_passcode}`, // Combined Journal passcode and Journal private passcode to encrypt and decrypt Entries
+
// From SQL view
journal_entry_count: obj.journal_entry_count,
diff --git a/src/lib/ae_journals/ae_journals_stores.ts b/src/lib/ae_journals/ae_journals_stores.ts
index d738b955..ae378d2f 100644
--- a/src/lib/ae_journals/ae_journals_stores.ts
+++ b/src/lib/ae_journals/ae_journals_stores.ts
@@ -94,6 +94,10 @@ let journals_session_data_struct: key_val = {
tmp_obj: {},
},
+
+ journal_kv: {
+ // journal_id: {},
+ },
};
// console.log(`AE Stores - App Journals Session Storage Data:`, journals_session_data_struct);
export let journals_sess = writable(journals_session_data_struct);
diff --git a/src/lib/ae_journals/db_journals.ts b/src/lib/ae_journals/db_journals.ts
index 86dc55b5..3bf336a5 100644
--- a/src/lib/ae_journals/db_journals.ts
+++ b/src/lib/ae_journals/db_journals.ts
@@ -71,6 +71,8 @@ export interface Journal {
passcode?: null|string; // For Journal Entry encryption password
passcode_timeout?: null|number; // Timeout in seconds
+ private_passcode?: null|string; // Combine with the Journal passcode for Journal Entry encryption password
+
auth_key?: null|string; // For Journal authorization without sign in
enable: null|boolean;
@@ -89,6 +91,8 @@ export interface Journal {
tmp_sort_2?: null|string;
tmp_sort_3?: null|string;
+ combined_passcode?: null|string; // For Journal Entry encryption password
+
// Additional fields for convenience (database views)
file_count?: null|number; // Only files directly under a journal
journal_file_id_li_json?: null|string;
diff --git a/src/lib/ae_utils/ae_utils__crypto.ts b/src/lib/ae_utils/ae_utils__crypto.ts
index 34f63bf5..547b6be9 100644
--- a/src/lib/ae_utils/ae_utils__crypto.ts
+++ b/src/lib/ae_utils/ae_utils__crypto.ts
@@ -91,16 +91,10 @@ export let split_iv_and_base64 = function split_iv_and_base64(
if (log_lvl) {
console.log(`IV: ${iv}; Encrypted:`, base64);
}
-
- // const [ivBase64, base64] = combined.split(':');
- // const iv = Uint8Array.from(atob(ivBase64), c => c.charCodeAt(0));
- // if (log_lvl) {
- // console.log(`IV: ${iv}; Encrypted: ${base64}`);
- // }
return { iv, base64 };
}
-// Updated 2025-05-08
+// Updated 2025-05-15
export let decrypt_wrapper = async function decrypt_wrapper(
combined: string,
keyData: string
@@ -110,11 +104,17 @@ export let decrypt_wrapper = async function decrypt_wrapper(
return '';
}
const { iv, base64 } = split_iv_and_base64(combined);
- const decrypted = await decrypt_content(base64, iv, keyData);
- if (log_lvl > 1) {
- console.log(`IV: ${iv}; Decrypted:`, decrypted);
- } else if (log_lvl) {
- console.log(`IV: ${iv}`);
+ let decrypted;
+ try {
+ decrypted = await decrypt_content(base64, iv, keyData);
+ if (log_lvl > 1) {
+ console.log(`IV: ${iv}; Decrypted:`, decrypted);
+ } else if (log_lvl) {
+ console.log(`IV: ${iv}`);
+ }
+ } catch (error) {
+ console.error('Decryption failed:', error);
+ return '';
}
return decrypted;
}
\ No newline at end of file
diff --git a/src/routes/journals/[journal_id]/+layout.svelte b/src/routes/journals/[journal_id]/+layout.svelte
index 3bcafd26..b7bd3bfd 100644
--- a/src/routes/journals/[journal_id]/+layout.svelte
+++ b/src/routes/journals/[journal_id]/+layout.svelte
@@ -195,7 +195,7 @@ async function handle_update_journal() {
{:else}
-
+ -->
{/if}
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 1ffd4eb0..b3eb2dfe 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
@@ -588,7 +588,7 @@ async function change_journal_id() {
// let journal_key: string = $state( 'my-secret-key-111');
// let journal_key: string = $state($lq__journal_obj?.passcode);
let journal_key = $derived(() => {
- return $lq__journal_obj?.passcode || 'my-secret-key-111';
+ return $lq__journal_obj?.passcode || 'temp-secret-key';
});
// console.log('TEST: journal_key', journal_key);
let content = ''; // "This is my test content to encrypt and decrypt.";
@@ -599,10 +599,19 @@ let trigger_decrypt: boolean = $state(false);
let decrypted_history: string = $state('');
$effect(() => {
- if ($lq__journal_obj?.passcode) {
- console.log('TEST: lq__journal_obj?.passcode', $lq__journal_obj?.passcode);
+ if ($journals_sess.journal_kv[$lq__journal_obj?.id]?.journal_passcode_verified) {
+ journal_key = $lq__journal_obj?.combined_passcode;
+ } else if ($lq__journal_obj?.passcode) {
journal_key = $lq__journal_obj?.passcode;
+ } else {
+ 'temp-secret-key';
}
+ console.log('TEST: journal_key', journal_key);
+
+ // if ($lq__journal_obj?.passcode) {
+ // console.log('TEST: lq__journal_obj?.passcode', $lq__journal_obj?.passcode);
+ // journal_key = $lq__journal_obj?.passcode;
+ // }
});
// $effect(async () => {
@@ -713,39 +722,39 @@ async function handle_decrypt_string(encrypted_string: string, passcode: string)
// return decrypted_string;
}
-async function handle_encrypt_string(text_string: string, passcode: string) {
- // log_lvl = 1;
- if (log_lvl) {
- console.log('TEST: handle_encrypt_string');
- }
- if (!text_string) {
- console.log('TEST: No text string provided');
- return '';
- }
- if (!passcode) {
- console.log('TEST: No journal key provided');
- return false;
- }
+// async function handle_encrypt_string(text_string: string, passcode: string) {
+// // log_lvl = 1;
+// if (log_lvl) {
+// console.log('TEST: handle_encrypt_string');
+// }
+// if (!text_string) {
+// console.log('TEST: No text string provided');
+// return '';
+// }
+// if (!passcode) {
+// console.log('TEST: No journal key provided');
+// return false;
+// }
- let combined_data_2 = await ae_util.encrypt_wrapper(text_string, passcode);
- if (log_lvl) {
- console.log('TEST: Encrypted string:', combined_data_2);
- }
- return combined_data_2;
+// let combined_data_2 = await ae_util.encrypt_wrapper(text_string, passcode);
+// if (log_lvl) {
+// console.log('TEST: Encrypted string:', combined_data_2);
+// }
+// return combined_data_2;
- // Encrypt the string using the journal key
- // let encrypted_base64 = await ae_util.encrypt_content(text_string, passcode);
- // let encrypted_base64_string = encrypted_base64.base64;
- // let encryption_iv = encrypted_base64.iv;
- // console.log(`IV: ${encryption_iv}; Encrypted: ${encrypted_base64_string}`);
+// // Encrypt the string using the journal key
+// // let encrypted_base64 = await ae_util.encrypt_content(text_string, passcode);
+// // let encrypted_base64_string = encrypted_base64.base64;
+// // let encryption_iv = encrypted_base64.iv;
+// // console.log(`IV: ${encryption_iv}; Encrypted: ${encrypted_base64_string}`);
- // const combined_data = ae_util.combine_iv_and_base64(encrypted_base64_string, encryption_iv);
+// // const combined_data = ae_util.combine_iv_and_base64(encrypted_base64_string, encryption_iv);
- // Combine the IV and encrypted content
- // const combined_data = Array.from(encryption_iv).map(byte => byte.toString(16).padStart(2, '0')).join('') + ':' + encrypted_base64_string;
+// // Combine the IV and encrypted content
+// // const combined_data = Array.from(encryption_iv).map(byte => byte.toString(16).padStart(2, '0')).join('') + ':' + encrypted_base64_string;
- // return combined_data;
-}
+// // return combined_data;
+// }
// return new_string and cut_string
function handle_cut_string(old_string: string) {
@@ -805,7 +814,9 @@ function handle_cut_string(old_string: string) {
function handle_marked(text_string: string) {
if (!text_string) {
- console.log('TEST: No text string provided');
+ if (log_lvl) {
+ console.log('No text string provided');
+ }
return '';
}
// let cleaned_string = text_string.replace(/<[^>]*>/g, ''); // Remove HTML tags
diff --git a/src/routes/journals/ae_comp__journal_obj_id_view.svelte b/src/routes/journals/ae_comp__journal_obj_id_view.svelte
index fb9ed03e..184d0174 100644
--- a/src/routes/journals/ae_comp__journal_obj_id_view.svelte
+++ b/src/routes/journals/ae_comp__journal_obj_id_view.svelte
@@ -3,14 +3,15 @@
// *** Import other supporting libraries
import {
- BookPlus, BookOpenText
+ BookPlus, BookOpenText,
+ FilePlus, Menu, Pencil
} from '@lucide/svelte';
// *** Import Aether specific variables and functions
import { ae_util } from '$lib/ae_utils/ae_utils';
import { ae_snip, ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
import { journals_loc, journals_sess, journals_slct, journals_trig, journals_prom } from '$lib/ae_journals/ae_journals_stores';
-// import { journals_func } from '$lib/ae_journals/ae_journals_functions';
+import { journals_func } from '$lib/ae_journals/ae_journals_functions';
interface Props {
log_lvl?: number;
@@ -28,7 +29,56 @@ let { log_lvl = 0,
// let ae_trigger: any = null;
// let ae_triggers: key_val = {};
-// Reminder: Styling is being done with Tailwind CSS, not Bootstrap.
+let show_menu: boolean = $state(false);
+let typed_journal_passcode: string = $state('');
+let passcode_timer: any = $state(null);
+
+$effect(() => {
+ if (typed_journal_passcode?.length > 4) {
+ log_lvl = 1;
+ verify_journal_passcode();
+ }
+
+ // We need to set a timeout to force the user to re-enter their private passcode
+ if ($lq__journal_obj?.id && $journals_sess?.journal_kv[$lq__journal_obj?.id] && $journals_sess?.journal_kv[$lq__journal_obj?.id]?.journal_passcode_verified) {
+ if (passcode_timer) {
+ if (log_lvl) {
+ console.log('Passcode timer already set');
+ }
+ return;
+ }
+ console.log('Setting passcode timer');
+ passcode_timer = setTimeout(() => {
+ if (log_lvl) {
+ console.log('Passcode timer expired');
+ }
+ typed_journal_passcode = '';
+ $journals_sess.journal_kv[$lq__journal_obj?.id].journal_passcode_verified = false;
+ }, 1000 * 60 * 1); // 1 minutes
+ // }, 1000 * $lq__journal_obj?.passcode_timeout); // 5 minutes
+ }
+});
+
+function verify_journal_passcode() {
+ if (log_lvl) {
+ console.log(`verify_journal_passcode: typed_journal_passcode = ${typed_journal_passcode} journal private passcode = ${$lq__journal_obj?.private_passcode}`);
+ }
+
+ if (typed_journal_passcode === $lq__journal_obj?.private_passcode) {
+ console.log('Matched journal private passcode');
+ if (!$journals_sess?.journal_kv[$lq__journal_obj?.id]) {
+ $journals_sess.journal_kv[$lq__journal_obj?.id] = {};
+ }
+ $journals_sess.journal_kv[$lq__journal_obj?.id] = {
+ typed_journal_passcode: typed_journal_passcode,
+ journal_passcode_verified: true
+ };
+
+ typed_journal_passcode = '';
+ } else {
+
+ }
+}
@@ -40,7 +90,7 @@ let { log_lvl = 0,
"
bind:clientHeight={$ae_loc.iframe_height_modal_body}>
-