implement keyfile persistence (storing name=privKeyDataBase64\n for each name)
filename specified on the command line: SAMBridge [keyfile [listenHost] listenPortNum [ name=val]*]
This commit is contained in:
@ -9,6 +9,11 @@ package net.i2p.sam;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import java.io.IOException;
|
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.InetAddress;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
@ -16,6 +21,7 @@ import java.util.Properties;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
import net.i2p.data.Destination;
|
import net.i2p.data.Destination;
|
||||||
import net.i2p.data.DataFormatException;
|
import net.i2p.data.DataFormatException;
|
||||||
@ -24,6 +30,7 @@ import net.i2p.data.SigningPrivateKey;
|
|||||||
|
|
||||||
import net.i2p.util.I2PThread;
|
import net.i2p.util.I2PThread;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
import net.i2p.I2PAppContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SAM bridge implementation.
|
* SAM bridge implementation.
|
||||||
@ -31,10 +38,14 @@ import net.i2p.util.Log;
|
|||||||
* @author human
|
* @author human
|
||||||
*/
|
*/
|
||||||
public class SAMBridge implements Runnable {
|
public class SAMBridge implements Runnable {
|
||||||
|
|
||||||
private final static Log _log = new Log(SAMBridge.class);
|
private final static Log _log = new Log(SAMBridge.class);
|
||||||
private ServerSocket serverSocket;
|
private ServerSocket serverSocket;
|
||||||
private Properties i2cpProps;
|
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
|
* app designated destination name to the base64 of the I2P formatted
|
||||||
* destination keys (Destination+PrivateKey+SigningPrivateKey)
|
* destination keys (Destination+PrivateKey+SigningPrivateKey)
|
||||||
@ -43,7 +54,8 @@ public class SAMBridge implements Runnable {
|
|||||||
|
|
||||||
private boolean acceptConnections = true;
|
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() {}
|
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 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 listenPort port number to listen for SAM connections on
|
||||||
* @param i2cpProps set of I2CP properties for finding and communicating with the router
|
* @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 {
|
try {
|
||||||
if ( (listenHost != null) && !("0.0.0.0".equals(listenHost)) ) {
|
if ( (listenHost != null) && !("0.0.0.0".equals(listenHost)) ) {
|
||||||
serverSocket = new ServerSocket(listenPort, 0, InetAddress.getByName(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) {
|
public void addKeystream(String name, String stream) {
|
||||||
nameToPrivKeys.put(name, 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.
|
* depth, etc.
|
||||||
*/
|
*/
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
|
String keyfile = DEFAULT_SAM_KEYFILE;
|
||||||
int port = SAM_LISTENPORT;
|
int port = SAM_LISTENPORT;
|
||||||
String host = "0.0.0.0";
|
String host = "0.0.0.0";
|
||||||
Properties opts = null;
|
Properties opts = null;
|
||||||
if (args.length > 0) {
|
if (args.length > 0) {
|
||||||
int portIndex = 0;
|
keyfile = args[0];
|
||||||
|
int portIndex = 1;
|
||||||
try {
|
try {
|
||||||
port = Integer.parseInt(args[portIndex]);
|
port = Integer.parseInt(args[portIndex]);
|
||||||
} catch (NumberFormatException nfe) {
|
} catch (NumberFormatException nfe) {
|
||||||
host = args[0];
|
host = args[1];
|
||||||
portIndex++;
|
portIndex++;
|
||||||
try {
|
try {
|
||||||
port = Integer.parseInt(args[portIndex]);
|
port = Integer.parseInt(args[portIndex]);
|
||||||
@ -144,7 +212,7 @@ public class SAMBridge implements Runnable {
|
|||||||
}
|
}
|
||||||
opts = parseOptions(args, portIndex+1);
|
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");
|
I2PThread t = new I2PThread(bridge, "SAMListener");
|
||||||
t.start();
|
t.start();
|
||||||
}
|
}
|
||||||
@ -167,7 +235,8 @@ public class SAMBridge implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void usage() {
|
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(" 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(" listenPort: port to listen for SAM connections on (default 7656)");
|
||||||
System.err.println(" name=val: options to pass when connecting via I2CP, such as ");
|
System.err.println(" name=val: options to pass when connecting via I2CP, such as ");
|
||||||
|
Reference in New Issue
Block a user