1717/* Hardcoded public key used to verify the signature over the update data */
1818const RULESET_UPDATE_KEY = '' ;
1919
20- /* extension release branch preference key */
20+ /* extension release branch pereference key */
2121const BRANCH_PREF = 'extensions.https_everywhere.branch_name' ;
2222
2323/* extension release version preference key */
@@ -74,8 +74,9 @@ function fetchUpdate() {
7474function conditionallyApplyUpdate ( update ) {
7575 https_everywhereLog ( INFO , "Got update data:" ) ;
7676 https_everywhereLog ( INFO , update ) ;
77+ var em = Cc [ '@mozilla.org/extensions/manager;1' ] . getService ( Ci . nsIExtensionManager ) ;
7778 var updateObj = JSON . parse ( update ) ;
78- var extVersion = _prefs . getCharPref ( VERSION_PREF ) ;
79+ var extVersion = em . getItemForID ( "https-everywhere@eff.org" ) . version ;
7980 var extBranch = _prefs . getCharPref ( BRANCH_PREF ) ;
8081 var rulesetVersion = _prefs . getCharPref ( RULESET_VERSION_PREF ) ;
8182 https_everywhereLog ( INFO , "Inside call to conditionallyApplyUpdate" ) ;
@@ -94,7 +95,7 @@ function conditionallyApplyUpdate(update) {
9495 https_everywhereLog ( INFO , "Successfully fetched update.json.sig file data" ) ;
9596 if ( verifyUpdateSignature ( update , signature ) ) {
9697 https_everywhereLog ( INFO , "Ruleset update data signature verified successfully" ) ;
97- fetchRulesetDBFile ( updateObj . source , updateObj . hashfn , updateObj . hash ) ;
98+ fetchVerifyAndApplyDBFile ( updateObj . source , updateObj . version , updateObj . hashfn , updateObj . hash ) ;
9899 } else {
99100 https_everywhereLog ( WARN , 'Validation of the update signature provided failed.' ) ;
100101 // TODO
@@ -145,19 +146,24 @@ function checkVersionRequirements(extVersion, rsVersion, newVersion) {
145146 * @return string - The hex-encoded hash of the file's contents.
146147 */
147148function hashBinaryFile ( path , length , hashfn ) {
149+ var READONLY = 0x01 ;
150+ var READ_PERMISSIONS = 0444 ;
151+ var NOFLAGS = 0 ;
148152 var f = Cc [ '@mozilla.org/file/local;1' ] . createInstance ( Ci . nsILocalFile ) ;
149153 var istream = Cc [ '@mozilla.org/network/file-input-stream;1' ]
150154 . createInstance ( Ci . nsIFileInputStream ) ;
151155 var binaryIn = Cc [ '@mozilla.org/binaryinputstream;1' ] . createInstance ( Ci . nsIBinaryInputStream ) ;
152156 var hashing = Cc [ '@mozilla.org/security/hash;1' ] . createInstance ( Ci . nsICryptoHash ) ;
153- if ( hashfn === 'md5' ) hashing . init ( hashing . MD5 ) ;
154- else if ( hashfn === 'sha1' ) hashing . init ( hashing . SHA1 ) ;
155- else if ( hashfn === 'sha256' ) hashing . init ( hashing . SHA256 ) ;
156- else if ( hashfn === 'sha384' ) hashing . init ( hashing . SHA384 ) ;
157- else if ( hashfn === 'sha512' ) hashing . init ( hashing . SHA512 ) ;
158- else return null ; // It's a better idea to fail than do the wrong thing here.
157+ switch ( hashfn ) {
158+ case 'md5' : hashing . init ( hashing . MD5 ) ; break ;
159+ case 'sha1' : hashing . init ( hashing . SHA1 ) ; break ;
160+ case 'sha256' : hashing . init ( hashing . SHA256 ) ; break ;
161+ case 'sha384' : hashing . init ( hashing . SHA384 ) ; break ;
162+ case 'sha512' : hashing . init ( hashing . SHA512 ) ; break ;
163+ default : return '' ;
164+ }
159165 f . initWithPath ( path ) ;
160- istream . init ( f , 0x01 , 0444 , 0 ) ;
166+ istream . init ( f , READONLY , READ_PERMISSIONS , NOFLAGS ) ;
161167 binaryIn . setInputStream ( istream ) ;
162168 hashing . updateFromStream ( binaryIn , length ) ;
163169 var hash = hashing . finish ( false ) ; // Get binary data back
@@ -172,51 +178,66 @@ function hashBinaryFile(path, length, hashfn) {
172178 * matches what update.json says it should be, and then makes the call to apply the new
173179 * rulesets database.
174180 *
175- * @param url - The URL from which to fetch the new rulesets database file.
176- * @param hashfn - The name of the hash function to use when hashingthe database file.
177- * @param hash - The hash provided by update.json.
181+ * @param url - The URL from which to fetch the new rulesets database file.
182+ * @param version - The ruleset version (eg: 5.0.0.1).
183+ * @param hashfn - The name of the hash function to use when hashingthe database file.
184+ * @param hash - The hash provided by update.json.
178185 */
179- function fetchRulesetDBFile ( url , hashfn , hash ) {
180- https_everywhereLog ( INFO , "Making request to get database file at " + url ) ;
181- var xhr = Cc [ '@mozilla.org/xmlextras/xmlhttprequest;1' ] . createInstance ( Ci . nsIXMLHttpRequest ) ;
182- xhr . open ( "GET" , url , true ) ;
183- xhr . responseType = 'arraybuffer' ;
184- xhr . onload = function ( evt ) {
185- var arrayBuffer = xhr . response ;
186- if ( arrayBuffer ) {
187- var byteArray = new Uint8Array ( arrayBuffer ) ;
188- https_everywhereLog ( INFO , "byteArray has length " + byteArray . length ) ;
189- var file = Cc [ '@mozilla.org/file/local;1' ] . createInstance ( Ci . nsILocalFile ) ;
190- var outstream = Cc [ '@mozilla.org/network/file-output-stream;1' ]
191- . createInstance ( Ci . nsIFileOutputStream ) ;
192- var binout = Cc [ '@mozilla.org/binaryoutputstream;1' ] . createInstance ( Ci . nsIBinaryOutputStream ) ;
193- file . initWithPath ( TMP_RULESET_DBFILE_PATH ) ;
194- outstream . init ( file , - 1 , - 1 , 0 ) ;
195- binout . setOutputStream ( outstream ) ;
196- binout . writeByteArray ( byteArray , byteArray . length ) ;
197- outstream . close ( ) ;
198- dbHash = hashBinaryFile ( TMP_RULESET_DBFILE_PATH , byteArray . length , hashfn ) ;
199- https_everywhereLog ( INFO , "dbhash = " + dbHash ) ;
200- if ( dbHash === hash ) {
201- https_everywhereLog ( INFO ,
202- 'Hash of database file downloaded matches the hash provided by update.json' ) ;
203- applyNewRuleset ( ) ;
186+ function fetchVerifyAndApplyDBFile ( url , version , hashfn , hash ) {
187+ var DEFAULT_PERMISSIONS = - 1 ;
188+ var NOFLAGS = 0 ;
189+ ( function recur ( max_times ) {
190+ https_everywhereLog ( INFO , "Making request to get database file at " + url ) ;
191+ var xhr = Cc [ '@mozilla.org/xmlextras/xmlhttprequest;1' ] . createInstance ( Ci . nsIXMLHttpRequest ) ;
192+ xhr . open ( "GET" , url , true ) ;
193+ xhr . responseType = 'arraybuffer' ;
194+ xhr . onload = function ( evt ) {
195+ var arrayBuffer = xhr . response ;
196+ if ( arrayBuffer ) {
197+ var byteArray = new Uint8Array ( arrayBuffer ) ;
198+ https_everywhereLog ( INFO , "byteArray has length " + byteArray . length ) ;
199+ var file = Cc [ '@mozilla.org/file/local;1' ] . createInstance ( Ci . nsILocalFile ) ;
200+ var outstream = Cc [ '@mozilla.org/network/file-output-stream;1' ]
201+ . createInstance ( Ci . nsIFileOutputStream ) ;
202+ var binout = Cc [ '@mozilla.org/binaryoutputstream;1' ] . createInstance ( Ci . nsIBinaryOutputStream ) ;
203+ file . initWithPath ( TMP_RULESET_DBFILE_PATH ) ;
204+ outstream . init ( file , DEFAULT_PERMISSIONS , DEFAULT_PERMISSIONS , NOFLAGS ) ;
205+ binout . setOutputStream ( outstream ) ;
206+ binout . writeByteArray ( byteArray , byteArray . length ) ;
207+ outstream . close ( ) ;
208+ var dbHash = hashBinaryFile ( TMP_RULESET_DBFILE_PATH , byteArray . length , hashfn ) ;
209+ https_everywhereLog ( INFO , "dbhash = " + dbHash ) ;
210+ if ( dbHash === hash ) {
211+ https_everywhereLog ( INFO ,
212+ 'Hash of database file downloaded matches the hash provided by update.json' ) ;
213+ applyNewRuleset ( version ) ;
214+ } else {
215+ https_everywhereLog ( INFO , 'Hash of database file did not match the one in update.json' ) ;
216+ if ( max_times > 0 ) { // Strict limit test
217+ recur ( max_times - 1 ) ;
218+ }
219+ // TODO: Ping EFF URL to report authenticity verification failure
220+ }
204221 } else {
205- https_everywhereLog ( INFO , 'Hash of database file did not match the one in update.json' ) ;
206- // TODO: Ping EFF URL to report authenticity verification failure
222+ https_everywhereLog ( INFO , 'Did not download any database data' ) ;
223+ if ( max_times > 0 ) { // Strict limit test
224+ recur ( max_times - 1 ) ;
225+ }
226+ // TODO: Ping EFF URL to report download failure
207227 }
208- } else {
209- https_everywhereLog ( INFO , 'Did not download any database data' ) ;
210- // TODO: Ping EFF URL to report download failure
211- }
212- } ;
213- xhr . send ( null ) ;
228+ } ;
229+ xhr . send ( null ) ;
230+ } ) ( MAX_RSUPDATE_FETCHES ) ;
214231}
215232
216233/* Moves the downloaded rulesets database into a permanent location and reinitializes
217234 * HTTPSRules to use the rulesets.
235+ *
236+ * @param version - The ruleset version.
218237 */
219- function applyNewRuleset ( ) {
238+ function applyNewRuleset ( version ) {
239+ var DIRECTORY_TYPE = 1 ;
240+ var DIRECTORY_PERMISSIONS = 0777 ;
220241 https_everywhereLog ( INFO , 'In applyNewRuleset' ) ;
221242 var updatedPath = HTTPSEverywhere . instance . UPDATED_RULESET_DBFILE_PATH ( ) ;
222243 var permFile = Cc [ '@mozilla.org/file/local;1' ] . createInstance ( Ci . nsILocalFile ) ;
@@ -229,14 +250,15 @@ function applyNewRuleset() {
229250 permFile . remove ( false ) ;
230251 https_everywhereLog ( INFO , 'Removed existing updated database file' ) ;
231252 } else if ( ! permParent . exists ( ) ) {
232- permParent . create ( 1 , 0777 ) ;
253+ permParent . create ( DIRECTORY_TYPE , DIRECTORY_PERMISSIONS ) ;
233254 https_everywhereLog ( INFO , 'Created directory for downloaded ruleset database files' ) ;
234255 }
235256 tempFile . moveTo (
236257 permParent ,
237258 OS . Path . basename ( updatedPath ) ) ;
238259 https_everywhereLog ( INFO , 'Copied new database file to permanent location' ) ;
239260 HTTPSRules . init ( ) ;
261+ _prefs . setCharPref ( RULESET_VERSION_PREF , version ) ;
240262 https_everywhereLog ( INFO , 'Reinitialized HTTPSRules with new database' ) ;
241263}
242264
0 commit comments