From 635535aac2b831b0dbb00beb08e3b05ecb735d61 Mon Sep 17 00:00:00 2001
From: jrandom <jrandom>
Date: Thu, 6 May 2004 07:35:44 +0000
Subject: [PATCH] implement keyfile persistence (storing
 name=privKeyDataBase64\n for each name) filename specified on the command
 line: SAMBridge [keyfile [listenHost] listenPortNum [ name=val]*]

---
 apps/sam/java/src/net/i2p/sam/SAMBridge.java | 83 ++++++++++++++++++--
 1 file changed, 76 insertions(+), 7 deletions(-)

diff --git a/apps/sam/java/src/net/i2p/sam/SAMBridge.java b/apps/sam/java/src/net/i2p/sam/SAMBridge.java
index 018655d8b8..3ead182f22 100644
--- a/apps/sam/java/src/net/i2p/sam/SAMBridge.java
+++ b/apps/sam/java/src/net/i2p/sam/SAMBridge.java
@@ -9,6 +9,11 @@ package net.i2p.sam;
  */
 
 import java.io.IOException;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.FileNotFoundException;
 import java.net.InetAddress;
 import java.net.ServerSocket;
 import java.net.Socket;
@@ -16,6 +21,7 @@ import java.util.Properties;
 import java.util.Map;
 import java.util.HashMap;
 import java.util.Collections;
+import java.util.Iterator;
 
 import net.i2p.data.Destination;
 import net.i2p.data.DataFormatException;
@@ -24,6 +30,7 @@ import net.i2p.data.SigningPrivateKey;
 
 import net.i2p.util.I2PThread;
 import net.i2p.util.Log;
+import net.i2p.I2PAppContext;
 
 /**
  * SAM bridge implementation.
@@ -31,10 +38,14 @@ import net.i2p.util.Log;
  * @author human
  */
 public class SAMBridge implements Runnable {
-
     private final static Log _log = new Log(SAMBridge.class);
     private ServerSocket serverSocket;
     private Properties i2cpProps;
+    /** 
+     * filename in which the name to private key mapping should 
+     * be stored (and loaded from) 
+     */
+    private String persistFilename;
     /** 
      * app designated destination name to the base64 of the I2P formatted 
      * destination keys (Destination+PrivateKey+SigningPrivateKey)
@@ -43,7 +54,8 @@ public class SAMBridge implements Runnable {
 
     private boolean acceptConnections = true;
 
-    private final static int SAM_LISTENPORT = 7656;
+    private static final int SAM_LISTENPORT = 7656;
+    public static final String DEFAULT_SAM_KEYFILE = "sam.keys";
     
     private SAMBridge() {}
     
@@ -53,8 +65,11 @@ public class SAMBridge implements Runnable {
      * @param listenHost hostname to listen for SAM connections on ("0.0.0.0" for all)
      * @param listenPort port number to listen for SAM connections on
      * @param i2cpProps set of I2CP properties for finding and communicating with the router
+     * @param persistFile location to store/load named keys to/from
      */
-    public SAMBridge(String listenHost, int listenPort, Properties i2cpProps) {
+    public SAMBridge(String listenHost, int listenPort, Properties i2cpProps, String persistFile) {
+        persistFilename = persistFile;
+        loadKeys();
         try {
             if ( (listenHost != null) && !("0.0.0.0".equals(listenHost)) ) {
                 serverSocket = new ServerSocket(listenPort, 0, InetAddress.getByName(listenHost));
@@ -114,6 +129,57 @@ public class SAMBridge implements Runnable {
      */
     public void addKeystream(String name, String stream) {
         nameToPrivKeys.put(name, stream);
+        storeKeys();
+    }
+    
+    /**
+     * Load up the keys from the persistFilename
+     *
+     */
+    private synchronized void loadKeys() {
+        Map keys = new HashMap(16);
+        FileInputStream in = null;
+        try {
+            in = new FileInputStream(persistFilename);
+            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+            String line = null;
+            while ( (line = reader.readLine()) != null) {
+                int eq = line.indexOf('=');
+                String name = line.substring(0, eq);
+                String privKeys = line.substring(eq+1);
+                keys.put(name, privKeys);
+            }
+        } catch (FileNotFoundException fnfe) {
+            _log.warn("Key file does not exist at " + persistFilename);
+        } catch (IOException ioe) {
+            _log.error("Unable to read the keys from " + persistFilename, ioe);
+        } finally {
+            if (in != null) try { in.close(); } catch (IOException ioe) {}
+        }
+        nameToPrivKeys = Collections.synchronizedMap(keys);
+    }
+    
+    /**
+     * Store the current keys to disk in the location specified on creation
+     *
+     */
+    private synchronized void storeKeys() {
+        FileOutputStream out = null;
+        try {
+            out = new FileOutputStream(persistFilename);
+            for (Iterator iter = nameToPrivKeys.keySet().iterator(); iter.hasNext(); ) {
+                String name = (String)iter.next();
+                String privKeys = (String)nameToPrivKeys.get(name);
+                out.write(name.getBytes());
+                out.write('=');
+                out.write(privKeys.getBytes());
+                out.write('\n');
+            }
+        } catch (IOException ioe) {
+            _log.error("Error writing out the SAM keys to " + persistFilename, ioe);
+        } finally {
+            if (out != null) try { out.close(); } catch (IOException ioe) {}
+        }
     }
     
     /**
@@ -125,15 +191,17 @@ public class SAMBridge implements Runnable {
      * depth, etc.
      */ 
     public static void main(String args[]) {
+        String keyfile = DEFAULT_SAM_KEYFILE;
         int port = SAM_LISTENPORT;
         String host = "0.0.0.0";
         Properties opts = null;
         if (args.length > 0) {
-            int portIndex = 0;
+            keyfile = args[0];
+            int portIndex = 1;
             try {
                 port = Integer.parseInt(args[portIndex]);
             } catch (NumberFormatException nfe) {
-                host = args[0];
+                host = args[1];
                 portIndex++;
                 try {
                     port = Integer.parseInt(args[portIndex]);
@@ -144,7 +212,7 @@ public class SAMBridge implements Runnable {
             }
             opts = parseOptions(args, portIndex+1);
         }
-        SAMBridge bridge = new SAMBridge(host, port, opts);
+        SAMBridge bridge = new SAMBridge(host, port, opts, keyfile);
         I2PThread t = new I2PThread(bridge, "SAMListener");
         t.start();
     }
@@ -167,7 +235,8 @@ public class SAMBridge implements Runnable {
     }
     
     private static void usage() {
-        System.err.println("Usage: SAMBridge [listenHost listenPortNum[ name=val]*]");
+        System.err.println("Usage: SAMBridge [keyfile [listenHost] listenPortNum[ name=val]*]");
+        System.err.println(" keyfile: location to persist private keys (default sam.keys)");
         System.err.println(" listenHost: interface to listen on (0.0.0.0 for all interfaces)");
         System.err.println(" listenPort: port to listen for SAM connections on (default 7656)");
         System.err.println(" name=val: options to pass when connecting via I2CP, such as ");
-- 
GitLab