Changeset b69677b


Ignore:
Timestamp:
Apr 17, 2016 8:20:10 PM (4 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
2d3d6f7
Parents:
0ceb957
Message:

Addressbook: Add initial support for signatures in subscriptions
More cleanups
SingleFileNamingService?: Store signature properties on write

Files:
2 added
7 edited

Legend:

Unmodified
Added
Removed
  • apps/addressbook/java/src/net/i2p/addressbook/AddressBook.java

    r0ceb957 rb69677b  
    4444 * 
    4545 */
    46 class AddressBook implements Iterable<Map.Entry<String, String>> {
     46class AddressBook implements Iterable<Map.Entry<String, HostTxtEntry>> {
    4747
    4848    private final String location;
    4949    /** either addresses or subFile will be non-null, but not both */
    50     private final Map<String, String> addresses;
     50    private final Map<String, HostTxtEntry> addresses;
    5151    private final File subFile;
    5252    private boolean modified;
     
    8080     *            base64 i2p destinations.
    8181     */
    82     public AddressBook(Map<String, String> addresses) {
     82    public AddressBook(Map<String, HostTxtEntry> addresses) {
    8383        this.addresses = addresses;
    8484        this.subFile = null;
     
    131131     */
    132132    public AddressBook(Subscription subscription, String proxyHost, int proxyPort) {
    133         Map<String, String> a = null;
     133        Map<String, HostTxtEntry> a = null;
    134134        File subf = null;
    135135        try {
     
    168168    public AddressBook(File file) {
    169169        this.location = file.toString();
    170         Map<String, String> a;
     170        Map<String, HostTxtEntry> a;
    171171        try {
    172             a = ConfigParser.parse(file);
     172            a = HostTxtParser.parse(file);
    173173        } catch (IOException exp) {
    174             a = new HashMap<String, String>();
     174            a = new HashMap<String, HostTxtEntry>();
    175175        }
    176176        this.addresses = a;
     
    182182     * @since 0.8.7
    183183     */
    184     public Iterator<Map.Entry<String, String>> iterator() {
     184    public Iterator<Map.Entry<String, HostTxtEntry>> iterator() {
    185185        if (this.subFile != null) {
    186186            try {
     
    189189                return new ConfigIterator();
    190190            }
    191        }
     191        }
    192192        return this.addresses.entrySet().iterator();
    193193    }
     
    232232    /**
    233233     * Do basic validation of the hostname
    234      * hostname was already converted to lower case by ConfigParser.parse()
     234     * hostname was already converted to lower case by HostTxtParser.parse()
    235235     */
    236236    public static boolean isValidKey(String host) {
     
    294294        if (this.addresses == null)
    295295            throw new IllegalStateException();
    296         for (Iterator<Map.Entry<String, String>> iter = other.iterator(); iter.hasNext(); ) {
    297             Map.Entry<String, String> entry = iter.next();
     296        for (Iterator<Map.Entry<String, HostTxtEntry>> iter = other.iterator(); iter.hasNext(); ) {
     297            Map.Entry<String, HostTxtEntry> entry = iter.next();
    298298            String otherKey = entry.getKey();
    299             String otherValue = entry.getValue();
    300 
    301             if (isValidKey(otherKey) && isValidDest(otherValue)) {
     299            HostTxtEntry otherValue = entry.getValue();
     300
     301            if (isValidKey(otherKey) && isValidDest(otherValue.getDest())) {
    302302                if (this.addresses.containsKey(otherKey) && !overwrite) {
    303303                    if (DEBUG && log != null &&
    304                         !this.addresses.get(otherKey).equals(otherValue)) {
     304                        !this.addresses.get(otherKey).equals(otherValue.getDest())) {
    305305                        log.append("Conflict for " + otherKey + " from "
    306306                                + other.location
     
    335335        if (this.modified) {
    336336            try {
    337                 ConfigParser.write(this.addresses, file);
     337                HostTxtParser.write(this.addresses, file);
    338338            } catch (IOException exp) {
    339339                System.err.println("Error writing addressbook " + file.getAbsolutePath() + " : " + exp.toString());
  • apps/addressbook/java/src/net/i2p/addressbook/ConfigIterator.java

    r0ceb957 rb69677b  
    4343 *  to ensure the underlying stream is closed.
    4444 *
     45 *  Warning - misnamed - this is not used for config files.
     46 *  It is only used for subscriptions.
     47 *
    4548 *  @since 0.8.7
    4649 */
    47 class ConfigIterator implements Iterator<Map.Entry<String, String>>, Closeable {
     50class ConfigIterator implements Iterator<Map.Entry<String, HostTxtEntry>>, Closeable {
    4851
    4952    private BufferedReader input;
     
    7174            String inputLine;
    7275            while ((inputLine = input.readLine()) != null) {
    73                 inputLine = ConfigParser.stripComments(inputLine);
    74                 if (inputLine.length() == 0)
     76                HostTxtEntry he = HostTxtParser.parse(inputLine);
     77                if (he == null)
    7578                    continue;
    76                 String[] splitLine = DataHelper.split(inputLine, "=", 2);
    77                 if (splitLine.length == 2) {
    78                     next = new ConfigEntry(splitLine[0].trim().toLowerCase(Locale.US), splitLine[1].trim());
    79                     return true;
    80                 }
     79                next = new ConfigEntry(he.getName(), he);
     80                return true;
    8181            }
    8282        } catch (IOException ioe) {}
     
    8787    }
    8888
    89     public Map.Entry<String, String> next() {
     89    public Map.Entry<String, HostTxtEntry> next() {
    9090        if (!hasNext())
    9191            throw new NoSuchElementException();
    92         Map.Entry<String, String> rv = next;
     92        Map.Entry<String, HostTxtEntry> rv = next;
    9393        next = null;
    9494        return rv;
     
    113113     *  The object returned by the iterator.
    114114     */
    115     private static class ConfigEntry implements Map.Entry<String, String> {
     115    private static class ConfigEntry implements Map.Entry<String, HostTxtEntry> {
    116116        private final String key;
    117         private final String value;
     117        private final HostTxtEntry value;
    118118
    119         public ConfigEntry(String k, String v) {
     119        public ConfigEntry(String k, HostTxtEntry v) {
    120120            key = k;
    121121            value = v;
     
    126126        }
    127127
    128         public String getValue() {
     128        public HostTxtEntry getValue() {
    129129            return value;
    130130        }
    131131
    132         public String setValue(String v) {
     132        public HostTxtEntry setValue(HostTxtEntry v) {
    133133            throw new UnsupportedOperationException();
    134134        }
  • apps/addressbook/java/src/net/i2p/addressbook/Daemon.java

    r0ceb957 rb69677b  
    3737import net.i2p.data.DataFormatException;
    3838import net.i2p.data.Destination;
     39import net.i2p.util.OrderedProperties;
    3940import net.i2p.util.SecureDirectory;
    4041import net.i2p.util.SystemVersion;
     
    5455    /** @since 0.9.12 */
    5556    static final String OLD_DEFAULT_SUB = "http://www.i2p2.i2p/hosts.txt";
     57    /** Any properties we receive from the subscription, we store to the
     58     *  addressbook with this prefix, so it knows it's part of the signature.
     59     *  This is also chosen so that it can't be spoofed.
     60     */
     61    private static final String RCVD_PROP_PREFIX = "=";
     62    private static final boolean MUST_VALIDATE = false;
    5663   
    5764    /**
     
    138145            }
    139146            int old = 0, nnew = 0, invalid = 0, conflict = 0, total = 0;
    140             for (Iterator<Map.Entry<String, String>> eIter = sub.iterator(); eIter.hasNext(); ) {
    141                 Map.Entry<String, String> entry = eIter.next();
     147            for (Iterator<Map.Entry<String, HostTxtEntry>> eIter = sub.iterator(); eIter.hasNext(); ) {
     148                Map.Entry<String, HostTxtEntry> entry = eIter.next();
    142149                String key = entry.getKey();
    143150                boolean isKnown;
     
    158165                    if (!isKnown) {
    159166                        if (AddressBook.isValidKey(key)) {
    160                             Destination dest = new Destination(entry.getValue());
    161                             Properties props = new Properties();
     167                            HostTxtEntry he = entry.getValue();
     168                            Destination dest = new Destination(he.getDest());
     169                            Properties props = new OrderedProperties();
    162170                            props.setProperty("s", sub.getLocation());
     171                            if (he.hasValidSig()) {
     172                                props.setProperty("v", "true");
     173                            } else if (MUST_VALIDATE) {
     174                                // TODO
     175                                //if (log != null)
     176                                //    log.append("Bad signature for new key " + key);
     177                                continue;
     178                            }
     179                            Properties hprops = he.getProps();
     180                            if (hprops != null) {
     181                                // merge in all the received properties
     182                                for (Map.Entry<Object, Object> e : hprops.entrySet()) {
     183                                    // Add prefix to indicate received property
     184                                    props.setProperty(RCVD_PROP_PREFIX + e.getKey(), (String) e.getValue());
     185                                }
     186                            }
    163187                            boolean success = router.put(key, dest, props);
    164188                            if (log != null) {
     
    173197                                if (publishedNS == null)
    174198                                    publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath());
    175                                 success = publishedNS.putIfAbsent(key, dest);
     199                                success = publishedNS.putIfAbsent(key, dest, props);
    176200                                if (log != null && !success) {
    177201                                    try {
     
    238262        boolean should_publish = Boolean.parseBoolean(settings.get("should_publish"));
    239263        if (should_publish)
    240             published = new File(home, settings
    241                 .get("published_addressbook"));
    242         File subscriptionFile = new File(home, settings
    243                 .get("subscriptions"));
     264            published = new File(home, settings.get("published_addressbook"));
     265        File subscriptionFile = new File(home, settings.get("subscriptions"));
    244266        File logFile = new File(home, settings.get("log"));
    245267        File etagsFile = new File(home, settings.get("etags"));
    246         File lastModifiedFile = new File(home, settings
    247                 .get("last_modified"));
    248         File lastFetchedFile = new File(home, settings
    249                 .get("last_fetched"));
     268        File lastModifiedFile = new File(home, settings.get("last_modified"));
     269        File lastFetchedFile = new File(home, settings.get("last_fetched"));
    250270        long delay;
    251271        try {
     
    261281       
    262282        SubscriptionList subscriptions = new SubscriptionList(subscriptionFile,
    263                 etagsFile, lastModifiedFile, lastFetchedFile, delay, defaultSubs, settings
    264                 .get("proxy_host"), Integer.parseInt(settings.get("proxy_port")));
     283                                                              etagsFile, lastModifiedFile, lastFetchedFile,
     284                                                              delay, defaultSubs, settings.get("proxy_host"),
     285                                                              Integer.parseInt(settings.get("proxy_port")));
    265286        Log log = SystemVersion.isAndroid() ? null : new Log(logFile);
    266287
  • apps/addressbook/java/src/net/i2p/addressbook/SubscriptionIterator.java

    r0ceb957 rb69677b  
    8686            //                   " ago but the minimum delay is " +
    8787            //                   DataHelper.formatDuration(this.delay));
    88             return new AddressBook(Collections.<String, String> emptyMap());
     88            return new AddressBook(Collections.<String, HostTxtEntry>emptyMap());
    8989        }
    9090    }
  • core/java/src/net/i2p/client/naming/SingleFileNamingService.java

    r0ceb957 rb69677b  
    6060    private volatile boolean _isClosed;
    6161
     62    private static final String RCVD_PROP_PREFIX = "=";
     63    private static final String PROPS_SEPARATOR = "#!";
     64    private static final char PROP_SEPARATOR = '#';
     65
    6266    public SingleFileNamingService(I2PAppContext context, String filename) {
    6367        super(context);
     
    166170    /**
    167171     *  @param hostname case-sensitive; caller should convert to lower case
    168      *  @param options ignored
     172     *  @param options if non-null, any prefixed with '=' will be appended
     173     *                 in subscription format
    169174     */
    170175    @Override
     
    197202            out.write('=');
    198203            out.write(d.toBase64());
     204            // subscription options
     205            if (options != null)
     206                writeOptions(options, out);
    199207            out.newLine();
    200208            out.close();
     
    216224    /**
    217225     *  @param hostname case-sensitive; caller should convert to lower case
    218      *  @param options ignored
     226     *  @param options if non-null, any prefixed with '=' will be appended
     227     *                 in subscription format
    219228     */
    220229    @Override
    221230    public boolean putIfAbsent(String hostname, Destination d, Properties options) {
    222         OutputStream out = null;
     231        BufferedWriter out = null;
    223232        if (!getWriteLock())
    224233            return false;
     
    237246                // else new file
    238247            }
    239             out = new SecureFileOutputStream(_file, true);
     248            out = new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(_file, true), "UTF-8"));
    240249            // FIXME fails if previous last line didn't have a trailing \n
    241             out.write(hostname.getBytes("UTF-8"));
     250            out.write(hostname);
    242251            out.write('=');
    243             out.write(DataHelper.getASCII(d.toBase64()));
     252            out.write(d.toBase64());
     253            // subscription options
     254            if (options != null)
     255                writeOptions(options, out);
    244256            out.write('\n');
    245257            out.close();
     
    253265            return false;
    254266        } finally { releaseWriteLock(); }
     267    }
     268
     269    /**
     270     *  Write the subscription options part of the line (after the #!).
     271     *  Only options starting with '=' (if any) are written (with the '=' stripped).
     272     *  Does not write a newline.
     273     *
     274     *  @param options non-null
     275     *  @since 0.9.26
     276     */
     277    private static void writeOptions(Properties options, Writer out) throws IOException {
     278        boolean started = false;
     279        for (Map.Entry<Object, Object> e : options.entrySet()) {
     280            String k = (String) e.getKey();
     281            if (!k.startsWith(RCVD_PROP_PREFIX))
     282                continue;
     283            k = k.substring(1);
     284            String v = (String) e.getValue();
     285            if (started) {
     286                out.write(PROP_SEPARATOR);
     287            } else {
     288                started = true;
     289                out.write(PROPS_SEPARATOR);
     290            }
     291            out.write(k);
     292            out.write('=');
     293            out.write(v);
     294        }
    255295    }
    256296
  • history.txt

    r0ceb957 rb69677b  
     12016-04-17 zzz
     2 * Addressbook:
     3   - Several cleanups and refactoring
     4   - Add initial support for signatures in subscriptions
     5   - Fix main-class in addressbook.jar
     6   - Fix corrupted manifest in addressbook.jar
     7 * Build: Fix broken build from scratch in jetty build.xml
     8 * Console:
     9   - Add JSTL version to /logs
     10   - Update version warnings
     11   - Add OpenJDK check for ARM
     12 * PrivateKeyFile: Add method to specify sig type on creation
     13 * SingleFileNamingService: Store signature properties on write
     14 * TunnelId: Add max value check
     15
    1162016-04-13 zzz
    217 * SOCKS: Fix NPE on lookup failure in SOCKS 4a
  • router/java/src/net/i2p/router/RouterVersion.java

    r0ceb957 rb69677b  
    1919    public final static String ID = "Monotone";
    2020    public final static String VERSION = CoreVersion.VERSION;
    21     public final static long BUILD = 2;
     21    public final static long BUILD = 3;
    2222
    2323    /** for example "-test" */
Note: See TracChangeset for help on using the changeset viewer.