| OLD | NEW | 
|---|
| 1 /* | 1 /* | 
| 2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 
| 3  * Copyright (C) 2006-2016 Eyeo GmbH | 3  * Copyright (C) 2006-2016 Eyeo GmbH | 
| 4  * | 4  * | 
| 5  * Adblock Plus is free software: you can redistribute it and/or modify | 5  * Adblock Plus is free software: you can redistribute it and/or modify | 
| 6  * it under the terms of the GNU General Public License version 3 as | 6  * it under the terms of the GNU General Public License version 3 as | 
| 7  * published by the Free Software Foundation. | 7  * published by the Free Software Foundation. | 
| 8  * | 8  * | 
| 9  * Adblock Plus is distributed in the hope that it will be useful, | 9  * Adblock Plus is distributed in the hope that it will be useful, | 
| 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| (...skipping 14 matching lines...) Expand all  Loading... | 
| 25 import java.io.File; | 25 import java.io.File; | 
| 26 import java.io.FileInputStream; | 26 import java.io.FileInputStream; | 
| 27 import java.io.FileOutputStream; | 27 import java.io.FileOutputStream; | 
| 28 import java.io.IOException; | 28 import java.io.IOException; | 
| 29 import java.io.StringReader; | 29 import java.io.StringReader; | 
| 30 import java.net.URL; | 30 import java.net.URL; | 
| 31 import java.nio.charset.StandardCharsets; | 31 import java.nio.charset.StandardCharsets; | 
| 32 import java.security.MessageDigest; | 32 import java.security.MessageDigest; | 
| 33 import java.security.NoSuchAlgorithmException; | 33 import java.security.NoSuchAlgorithmException; | 
| 34 import java.util.ArrayList; | 34 import java.util.ArrayList; | 
|  | 35 import java.util.Arrays; | 
| 35 import java.util.Collection; | 36 import java.util.Collection; | 
| 36 import java.util.Collections; | 37 import java.util.Collections; | 
| 37 import java.util.HashMap; | 38 import java.util.HashMap; | 
| 38 import java.util.HashSet; | 39 import java.util.HashSet; | 
| 39 import java.util.List; | 40 import java.util.List; | 
| 40 import java.util.Locale; | 41 import java.util.Locale; | 
| 41 import java.util.Map; | 42 import java.util.Map; | 
| 42 import java.util.Map.Entry; | 43 import java.util.Map.Entry; | 
| 43 import java.util.zip.GZIPInputStream; | 44 import java.util.zip.GZIPInputStream; | 
| 44 import java.util.zip.GZIPOutputStream; | 45 import java.util.zip.GZIPOutputStream; | 
| 45 | 46 | 
| 46 import android.text.TextUtils; | 47 import android.text.TextUtils; | 
|  | 48 import android.text.format.DateUtils; | 
| 47 import android.util.Log; | 49 import android.util.Log; | 
| 48 | 50 | 
| 49 /** | 51 /** | 
| 50  * Simple subscription representation. | 52  * Simple subscription representation. | 
| 51  */ | 53  */ | 
| 52 final class Subscription | 54 final class Subscription | 
| 53 { | 55 { | 
| 54   private static final String TAG = Subscription.class.getSimpleName(); | 56   private static final String TAG = Subscription.class.getSimpleName(); | 
| 55   public static final String KEY_TITLE = "title"; | 57   public static final String KEY_TITLE = "title"; | 
| 56   public static final String KEY_VERSION = "version"; | 58   public static final String KEY_VERSION = "version"; | 
| 57   public static final String KEY_HTTP_ETAG = "_etag"; | 59   public static final String KEY_HTTP_ETAG = "_etag"; | 
| 58   public static final String KEY_HTTP_LAST_MODIFIED = "_last_modified"; | 60   public static final String KEY_HTTP_LAST_MODIFIED = "_last_modified"; | 
| 59   public static final String KEY_UPDATE_TIMESTAMP = "_update_timestamp"; | 61   public static final String KEY_UPDATE_TIMESTAMP = "_update_timestamp"; | 
| 60   public static final String KEY_TRIED_UPDATE_TIMESTAMP = "_tried_update_timesta
     mp"; | 62   public static final String KEY_TRIED_UPDATE_TIMESTAMP = "_tried_update_timesta
     mp"; | 
| 61   public static final String KEY_DOWNLOAD_COUNT = "_download_count"; | 63   public static final String KEY_DOWNLOAD_COUNT = "_download_count"; | 
| 62   public static final String KEY_ENABLED = "_enabled"; | 64   public static final String KEY_ENABLED = "_enabled"; | 
| 63   public static final String KEY_META_HASH = "_meta_hash"; | 65   public static final String KEY_META_HASH = "_meta_hash"; | 
| 64 | 66 | 
| 65   public static final long MINIMAL_DOWNLOAD_INTERVAL = Engine.MILLIS_PER_HOUR / 
     4; | 67   private static final long MINIMAL_DOWNLOAD_INTERVAL = DateUtils.HOUR_IN_MILLIS
      / 4; | 
| 66   public static final long DOWNLOAD_RETRY_INTERVAL = Engine.MILLIS_PER_HOUR; | 68   private static final long DOWNLOAD_RETRY_INTERVAL = DateUtils.HOUR_IN_MILLIS; | 
| 67 |  | 
| 68   private static final HashSet<String> ALLOWED_META_KEYS = new HashSet<>(); |  | 
| 69   private static final Locale LOCALE_EN = Locale.ENGLISH; |  | 
| 70 |  | 
| 71   private final long updateInterval = Engine.MILLIS_PER_DAY |  | 
| 72       + (long) (Engine.MILLIS_PER_HOUR * 8. * Math.random()); |  | 
| 73 | 69 | 
| 74   /** | 70   /** | 
| 75    * List of meta keys that are allowed to import from a downloaded | 71    * List of meta keys that are allowed to import from a downloaded | 
| 76    * subscription. | 72    * subscription. | 
| 77    */ | 73    */ | 
| 78   private static final String[] ALLOWED_META_KEYS_ARRAY = | 74   private static final String[] ALLOWED_META_KEYS_ARRAY = | 
| 79   { | 75       { | 
| 80       "checksum", KEY_VERSION, KEY_TITLE, "last modified", "expires", "homepage"
     , "licence" | 76           "checksum", KEY_VERSION, KEY_TITLE, "last modified", "expires", "homep
     age", "licence" | 
| 81   }; | 77       }; | 
|  | 78   private static final HashSet<String> ALLOWED_META_KEYS = | 
|  | 79       new HashSet<>(Arrays.asList(ALLOWED_META_KEYS_ARRAY)); | 
|  | 80 | 
|  | 81   private static final Locale LOCALE_EN = Locale.ENGLISH; | 
|  | 82 | 
|  | 83   private final long updateInterval = DateUtils.DAY_IN_MILLIS | 
|  | 84       + (long) (DateUtils.HOUR_IN_MILLIS * 8. * Math.random()); | 
| 82 | 85 | 
| 83   private final URL url; | 86   private final URL url; | 
| 84   private final Type type; | 87   private final Type type; | 
| 85   private final HashMap<String, String> meta = new HashMap<>(); | 88   private final HashMap<String, String> meta = new HashMap<>(); | 
| 86   private final HashSet<String> filters = new HashSet<>(); | 89   private final HashSet<String> filters = new HashSet<>(); | 
| 87 | 90 | 
| 88   private boolean metaDataValid = true; | 91   private boolean metaDataValid = true; | 
| 89   private boolean filtersValid = true; | 92   private boolean filtersValid = true; | 
| 90 | 93 | 
| 91   static |  | 
| 92   { |  | 
| 93     for (final String s : ALLOWED_META_KEYS_ARRAY) |  | 
| 94     { |  | 
| 95       ALLOWED_META_KEYS.add(s); |  | 
| 96     } |  | 
| 97   } |  | 
| 98 |  | 
| 99   /** | 94   /** | 
| 100    * Subscription type. | 95    * Subscription type. | 
| 101    * | 96    * | 
| 102    * @author René Jeschke <rene@adblockplus.org> | 97    * @author René Jeschke <rene@adblockplus.org> | 
| 103    */ | 98    */ | 
| 104   public enum Type | 99   public enum Type | 
| 105   { | 100   { | 
| 106     /** | 101     /** | 
| 107      * Initiated from an URL, can be automatically downloaded. | 102      * Initiated from an URL, can be automatically downloaded. | 
| 108      */ | 103      */ | 
| (...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 349         return "url:" + subscription.url.toString(); | 344         return "url:" + subscription.url.toString(); | 
| 350       case USER: | 345       case USER: | 
| 351         return "user:" + subscription.getMeta(KEY_TITLE); | 346         return "user:" + subscription.getMeta(KEY_TITLE); | 
| 352     } | 347     } | 
| 353     return ""; | 348     return ""; | 
| 354   } | 349   } | 
| 355 | 350 | 
| 356   private static String byteArrayToHexString(final byte[] array) | 351   private static String byteArrayToHexString(final byte[] array) | 
| 357   { | 352   { | 
| 358     final StringBuilder sb = new StringBuilder(array.length * 2); | 353     final StringBuilder sb = new StringBuilder(array.length * 2); | 
| 359     for (int i = 0; i < array.length; i++) | 354     for (final byte b : array) | 
| 360     { | 355     { | 
| 361       final int value = array[i] & 255; | 356       final int value = b & 255; | 
| 362       if (value < 16) | 357       if (value < 16) | 
| 363       { | 358       { | 
| 364         sb.append('0'); | 359         sb.append('0'); | 
| 365       } | 360       } | 
| 366       sb.append(Integer.toHexString(value)); | 361       sb.append(Integer.toHexString(value)); | 
| 367     } | 362     } | 
| 368     return sb.toString(); | 363     return sb.toString(); | 
| 369   } | 364   } | 
| 370 | 365 | 
| 371   private static String createMetaDataHash(final HashMap<String, String> meta) t
     hrows IOException | 366   private static String createMetaDataHash(final HashMap<String, String> meta) t
     hrows IOException | 
| (...skipping 23 matching lines...) Expand all  Loading... | 
| 395     } | 390     } | 
| 396     catch (final NoSuchAlgorithmException e) | 391     catch (final NoSuchAlgorithmException e) | 
| 397     { | 392     { | 
| 398       throw new IOException("MD5 is unavailable: " + e.getMessage(), e); | 393       throw new IOException("MD5 is unavailable: " + e.getMessage(), e); | 
| 399     } | 394     } | 
| 400   } | 395   } | 
| 401 | 396 | 
| 402   public void serializeMetaData(final File metaFile) throws IOException | 397   public void serializeMetaData(final File metaFile) throws IOException | 
| 403   { | 398   { | 
| 404     this.putMeta(KEY_META_HASH, createMetaDataHash(this.meta)); | 399     this.putMeta(KEY_META_HASH, createMetaDataHash(this.meta)); | 
| 405     try (final DataOutputStream metaOut = new DataOutputStream(new GZIPOutputStr
     eam( | 400     try (final DataOutputStream metaOut = new DataOutputStream(new BufferedOutpu
     tStream( | 
| 406         new BufferedOutputStream(new FileOutputStream(metaFile))))) | 401         new GZIPOutputStream(new FileOutputStream(metaFile))))) | 
| 407     { | 402     { | 
| 408       metaOut.writeUTF(this.url != null ? this.url.toString() : ""); | 403       metaOut.writeUTF(this.url != null ? this.url.toString() : ""); | 
| 409       metaOut.writeInt(this.meta.size()); | 404       metaOut.writeInt(this.meta.size()); | 
| 410       for (final Entry<String, String> e : this.meta.entrySet()) | 405       for (final Entry<String, String> e : this.meta.entrySet()) | 
| 411       { | 406       { | 
| 412         metaOut.writeUTF(e.getKey()); | 407         metaOut.writeUTF(e.getKey()); | 
| 413         metaOut.writeUTF(e.getValue()); | 408         metaOut.writeUTF(e.getValue()); | 
| 414       } | 409       } | 
| 415     } | 410     } | 
| 416   } | 411   } | 
| 417 | 412 | 
| 418   public void serializeFilters(final File filtersFile) throws IOException | 413   public void serializeFilters(final File filtersFile) throws IOException | 
| 419   { | 414   { | 
| 420     try (final DataOutputStream filtersOut = new DataOutputStream(new GZIPOutput
     Stream( | 415     try (final DataOutputStream filtersOut = new DataOutputStream(new BufferedOu
     tputStream( | 
| 421         new BufferedOutputStream(new FileOutputStream(filtersFile))))) | 416         new GZIPOutputStream(new FileOutputStream(filtersFile))))) | 
| 422     { | 417     { | 
| 423       filtersOut.writeInt(this.filters.size()); | 418       filtersOut.writeInt(this.filters.size()); | 
| 424       filtersOut.writeUTF(createFilterHash(new ArrayList<>(this.filters))); | 419       filtersOut.writeUTF(createFilterHash(new ArrayList<>(this.filters))); | 
| 425       for (final String s : this.filters) | 420       for (final String s : this.filters) | 
| 426       { | 421       { | 
| 427         final byte[] b = s.getBytes(StandardCharsets.UTF_8); | 422         final byte[] b = s.getBytes(StandardCharsets.UTF_8); | 
| 428         filtersOut.writeInt(b.length); | 423         filtersOut.writeInt(b.length); | 
| 429         filtersOut.write(b); | 424         filtersOut.write(b); | 
| 430       } | 425       } | 
| 431     } | 426     } | 
| 432   } | 427   } | 
| 433 | 428 | 
| 434   public void serializeSubscription(final File metaFile, final File filtersFile)
      throws IOException | 429   public void serializeSubscription(final File metaFile, final File filtersFile)
      throws IOException | 
| 435   { | 430   { | 
| 436     this.serializeMetaData(metaFile); | 431     this.serializeMetaData(metaFile); | 
| 437     this.serializeFilters(filtersFile); | 432     this.serializeFilters(filtersFile); | 
| 438   } | 433   } | 
| 439 | 434 | 
| 440   public static Subscription deserializeSubscription(final File metaFile) | 435   public static Subscription deserializeSubscription(final File metaFile) | 
| 441   { | 436   { | 
| 442     Subscription sub = null; | 437     Subscription sub = null; | 
| 443     try (final DataInputStream in = new DataInputStream(new GZIPInputStream(new 
     BufferedInputStream( | 438     try (final DataInputStream in = new DataInputStream(new BufferedInputStream(
     new GZIPInputStream( | 
| 444         new FileInputStream(metaFile))))) | 439         new FileInputStream(metaFile))))) | 
| 445     { | 440     { | 
| 446       final String urlString = in.readUTF(); | 441       final String urlString = in.readUTF(); | 
| 447       sub = new Subscription(!TextUtils.isEmpty(urlString) ? new URL(urlString) 
     : null); | 442       sub = new Subscription(!TextUtils.isEmpty(urlString) ? new URL(urlString) 
     : null); | 
| 448       sub.metaDataValid = false; | 443       sub.metaDataValid = false; | 
| 449       final int numMetaEntries = in.readInt(); | 444       final int numMetaEntries = in.readInt(); | 
| 450       for (int i = 0; i < numMetaEntries; i++) | 445       for (int i = 0; i < numMetaEntries; i++) | 
| 451       { | 446       { | 
| 452         final String key = in.readUTF(); | 447         final String key = in.readUTF(); | 
| 453         final String value = in.readUTF(); | 448         final String value = in.readUTF(); | 
| 454         sub.meta.put(key, value); | 449         sub.meta.put(key, value); | 
| 455       } | 450       } | 
| 456       sub.metaDataValid = createMetaDataHash(sub.meta).equals(sub.getMeta(KEY_ME
     TA_HASH)); | 451       sub.metaDataValid = createMetaDataHash(sub.meta).equals(sub.getMeta(KEY_ME
     TA_HASH)); | 
| 457     } | 452     } | 
| 458     catch (Throwable t) | 453     catch (Throwable t) | 
| 459     { | 454     { | 
| 460       // We catch Throwable here in order to return whatever we could retrieve f
     rom the meta file | 455       // We catch Throwable here in order to return whatever we could retrieve f
     rom the meta file | 
| 461     } | 456     } | 
| 462     return sub; | 457     return sub; | 
| 463   } | 458   } | 
| 464 | 459 | 
| 465   public void deserializeFilters(final File filtersFile) | 460   public void deserializeFilters(final File filtersFile) | 
| 466   { | 461   { | 
| 467     this.clearFilters(); | 462     this.clearFilters(); | 
| 468     this.filtersValid = false; | 463     this.filtersValid = false; | 
| 469     try (final DataInputStream in = new DataInputStream(new GZIPInputStream(new 
     BufferedInputStream( | 464     try (final DataInputStream in = new DataInputStream(new BufferedInputStream(
     new GZIPInputStream( | 
| 470         new FileInputStream(filtersFile))))) | 465         new FileInputStream(filtersFile))))) | 
| 471     { | 466     { | 
| 472       final int numFilters = in.readInt(); | 467       final int numFilters = in.readInt(); | 
| 473       final String filtersHash = in.readUTF(); | 468       final String filtersHash = in.readUTF(); | 
| 474       for (int i = 0; i < numFilters; i++) | 469       for (int i = 0; i < numFilters; i++) | 
| 475       { | 470       { | 
| 476         final int length = in.readInt(); | 471         final int length = in.readInt(); | 
| 477         final byte[] b = new byte[length]; | 472         final byte[] b = new byte[length]; | 
| 478         in.readFully(b); | 473         in.readFully(b); | 
| 479         this.filters.add(new String(b, StandardCharsets.UTF_8)); | 474         this.filters.add(new String(b, StandardCharsets.UTF_8)); | 
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 605     this.serializeMetaData(metaFile); | 600     this.serializeMetaData(metaFile); | 
| 606     if (filtersChanged) | 601     if (filtersChanged) | 
| 607     { | 602     { | 
| 608       this.serializeFilters(filtersFile); | 603       this.serializeFilters(filtersFile); | 
| 609       this.clearFilters(); | 604       this.clearFilters(); | 
| 610     } | 605     } | 
| 611 | 606 | 
| 612     return filtersChanged; | 607     return filtersChanged; | 
| 613   } | 608   } | 
| 614 } | 609 } | 
| OLD | NEW | 
|---|