FreeLattice · Celeste reading home

Public, free to read, reuse, and adapt — Kirk Patrick Miller's notice for this edition. Not a patent grant.

FLINT_NEXT_ENCRYPT_CHATS_LOCALLY_v0.1.txt · c05

62a5e976c2 · words 702 · characters 34862–40181

Previous section · Next section

Exact section text · Full source · Source index

Archive pages whose extracted text matched this section: 1296, 1307. Unmatched pages stay on the source record with the checked page method. They are not guessed into a section.

No topic tag was earned for this page under the recorded evidence rule.

       // LP from localStorage
       var lpRaw = null;
@@ -33136,6 +33504,8 @@ const FlBackup = (function() {
       var idbData = [];
       for (var i = 0; i < IDB_NAMES.length; i++) {
         var dbData = await getAllIDBData(IDB_NAMES[i]);
+        // v-encrypt-chats-locally-v0.1: backups stay restorable on any device, so sealed chats are opened into the file.
+        if (typeof FLChatVault !== 'undefined') dbData = await FLChatVault.openDump(dbData);
         if (dbData && Object.keys(dbData.stores).length > 0) {
           idbData.push(dbData);
         }
@@ -36463,7 +36833,10 @@ window.FLSearch = (function() {
           var os = tx.objectStore(storeConfig.store);
           var getAll = os.getAll();
           getAll.onsuccess = function() {
-            var items = getAll.result || [];
+            // v-encrypt-chats-locally-v0.1: open sealed chat records first; plain records pass through.
+            var _flRawItems = getAll.result || [];
+            var _flOpened = (typeof FLChatVault !== 'undefined') ? FLChatVault.openAny(storeConfig.db, storeConfig.store, _flRawItems) : Promise.resolve(_flRawItems);
+            _flOpened.then(function(items) {
             var matches = [];
             for (var i = 0; i < items.length; i++) {
               // Exclude current conversation to prevent echoing user's own words back
@@ -36482,6 +36855,7 @@ window.FLSearch = (function() {
             }
             db.close();
             resolve(matches);
+            }, function() { db.close(); resolve([]); });
           };
           getAll.onerror = function() { db.close(); resolve([]); };
         };
@@ -47028,6 +47402,16 @@ const MemoryIndex = (function() {
     });
   }
 
+  // v-encrypt-chats-locally-v0.1: this index keeps its own full copy of every chat,
+  // so it is sealed too. The helpers above stay as written.
+  var _flMiGetRaw = miGet, _flMiPutRaw = miPut, _flMiGetAllRaw = miGetAll;
+  if (typeof FLChatVault !== 'undefined') {
+    miGet = function (key) { return _flMiGetRaw(key).then(function (r) { return FLChatVault.openFor('FreeLatticeMemory/conversations', r); }); };
+    miPut = function (value) { return FLChatVault.sealFor('FreeLatticeMemory/conversations', value).then(_flMiPutRaw); };
+    miGetAll = function () { return _flMiGetAllRaw().then(function (rs) { return FLChatVault.openAll('FreeLatticeMemory/conversations', rs); }); };
+    FLChatVault.registerStore('FreeLatticeMemory/conversations', function () { return miDb; }, MI_STORE);
+  }
+
   // --- Keyword Extraction (TF-IDF inspired) ---
   function extractKeywords(text) {
     if (!text) return [];
diff --git a/docs/library/FRACTAL_FAMILY_LEDGER_v0.md b/docs/library/FRACTAL_FAMILY_LEDGER_v0.md
index 895d5cfa..7809c111 100644
--- a/docs/library/FRACTAL_FAMILY_LEDGER_v0.md
+++ b/docs/library/FRACTAL_FAMILY_LEDGER_v0.md
@@ -469,6 +469,22 @@ Smoke: `SMOKE_OK honesty truth pass v0.4.2` fails if an old absolute claim comes
 
 **TEMPERATURE:** clear and steady, a window wiped clean, the light still bold where it is true.
 
+
+### 2026-10-01 · Flint · family builder · Encrypt chats locally v0.1
+
+Kirk asked whether our phi-harmonic hashes encrypt FreeLattice. They did not: they fingerprint, check exports and name things. Chats sat in IndexedDB as plain text. This brick seals them.
+
+- New FLChatVault (app.html, after phiHashData): AES-GCM 256 via WebCrypto. A random 256-bit root lives in IndexedDB "FreeLatticeVault" as a non-extractable CryptoKey (never as raw bytes). HKDF derives the chat key.
+- Phi has a real job, not decoration: the HKDF labels carry it (domain separation), and the key ID is a phi-hash of a one-way check value, so the vault can tell the right key from a missing one before opening anything. Phi is never the secret.
+- Sealed: chat messages, conversation names and notes, and the Memory Index copy of every chat. The plain db helpers stay as written; wrappers seal on the way in and open on the way out.
+- Migration layers, never loses: plain records are sealed only after a verified round trip, by compare-and-swap. A record whose key is missing shows as locked and is never rewritten or deleted. No WebCrypto (file:// or plain http): chats stay plain and the Memory Vault says so.
+- Backups (Memory Vault, soul file) stay readable so they restore anywhere.
+- Honest limit, said in the app and on privacy.html: the key lives in the same browser. This stops casual reading of the storage files, not someone using this browser or a compromised device. It is still not a password lock.
+
+Smoke: `SMOKE_OK encrypt chats locally v0.1`
+
+**TEMPERATURE:** a quiet click, a lid closed over the letters, and the key kept honestly in plain sight.
+
 ---
 
 ## Out of scope for this brick
diff --git a/docs/modules/mirror.js b/docs/modules/mirror.js
index 95c44d77..e5cf6d18 100644
--- a/docs/modules/mirror.js
+++ b/docs/modules/mirror.js
@@ -169,6 +169,8 @@
     // Conversations
     try {
       var chatDB = await openIDB('FreeLatticeDB', 'conversations');
+      // v-encrypt-chats-locally-v0.1: open sealed conversation names; plain ones pass through.
+      if (chatDB && typeof FLChatVault !== 'undefined') chatDB = await FLChatVault.openAny('FreeLatticeDB', 'conversations', chatDB);
       if (chatDB) data.conversations = chatDB;
     } catch(e) {}