commit d8b658a92b6e6a958a8aabe38147749065826033
parent 88e0ee7c60c800d1f539669280dc2136a477d182
Author: Luxferre <lux@ferre>
Date:   Sat, 26 Oct 2024 20:22:10 +0300
added content_id field to control message integrity (TBD how)
Diffstat:
2 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/ii-doc.txt b/ii-doc.txt
@@ -133,7 +133,7 @@ This algorithm must be implemented by every station to generate message IDs:
 1. Calculate SHA256 of the message in the Node-to-Point format as binary data.
 2. Calculate Base64 of the resulting binary hash sum.
 3. Truncate to the first 20 characters.
-4. Replace all occurrences of + or - with A, and / or _ with Z.
+4. Replace all occurrences of + or - with A, and / or _ with z.
 5. The result of these operations is your ii message ID.
 
 Implementation notes
diff --git a/tiifetch.tcl b/tiifetch.tcl
@@ -15,6 +15,7 @@
 package require http
 package require uri
 package require sqlite3
+package require sha256
 
 # autodetect TclTLS support and enable HTTPS request support if detected
 set tls_support 0
@@ -190,6 +191,14 @@ proc listcomp {a b} {
   return $diff
 }
 
+# generate ID from the Node-to-Point msg contents
+# (exactly how it was transferred inside base64)
+proc n2p_id {binmsg} {
+  set hash [::sha2::sha256 -bin -- $binmsg]
+  set trimbased [string range [binary encode base64 $hash] 0 19]
+  return [string map {+ A - A / z _ z} $trimbased]
+}
+
 # main logic proc
 proc fetchiidb {url echos dbfile dolog maxids} {
   if {$maxids < 12} {set maxids 12}
@@ -200,8 +209,9 @@ proc fetchiidb {url echos dbfile dolog maxids} {
   # prepare starting script
   sqlite3 msgdb $dbfile
   msgdb eval {
-    CREATE TABLE IF NOT EXISTS `msg` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `msgid` VARCHAR(20), `timestamp` INT, `echoname` VARCHAR(120),
-      `repto` TEXT, `msgfrom` TEXT, `msgfromaddr` TEXT, `msgto` TEXT, `subj` TEXT, `body` TEXT);
+    CREATE TABLE IF NOT EXISTS `msg` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `msgid` VARCHAR(20) UNIQUE,
+      `timestamp` INT, `echoname` VARCHAR(120), `repto` TEXT, `msgfrom` TEXT, `msgfromaddr` TEXT,
+      `msgto` TEXT, `subj` TEXT, `body` TEXT, `content_id` VARCHAR(20));
   }
 
   # attempt to fetch the echolist if echos are empty
@@ -308,7 +318,10 @@ proc fetchiidb {url echos dbfile dolog maxids} {
         set parts [split $bline ":"]
         if {[llength $parts] > 1} { # valid message
           set mid [lindex $parts 0]
-          set mdata [encoding convertfrom utf-8 [binary decode base64 [lindex $parts 1]]]
+          set bdata [binary decode base64 [lindex $parts 1]]
+          # calculate ii Node-to-Point ID to verify the message integrity
+          set content_id [n2p_id $bdata]
+          set mdata [encoding convertfrom utf-8 $bdata]
           set msglines [split $mdata "\n"]
           set replyto ""
           set tags [split [lindex $msglines 0] "/"]
@@ -322,8 +335,8 @@ proc fetchiidb {url echos dbfile dolog maxids} {
           set msgto [string trim [lindex $msglines 5]]
           set subj [string trim [lindex $msglines 6]]
           set msgbody [string trimright [lrange $msglines 8 end]]
-          msgdb eval {INSERT INTO `msg` (`msgid`, `timestamp`, `echoname`, `repto`, `msgfrom`, `msgfromaddr`, `msgto`, `subj`, `body`) 
-            VALUES ($mid, $timestamp, $echoarea, $replyto, $msgfrom, $msgfromaddr, $msgto, $subj, $msgbody);}
+          msgdb eval {INSERT OR IGNORE INTO `msg` (`msgid`, `timestamp`, `echoname`, `repto`, `msgfrom`, `msgfromaddr`, `msgto`, `subj`, `body`, `content_id`) 
+            VALUES ($mid, $timestamp, $echoarea, $replyto, $msgfrom, $msgfromaddr, $msgto, $subj, $msgbody, $content_id);}
         }
       }
     }