iOS web browser with a focus on security and privacy
at master 124 lines 3.4 kB view raw
1#!/usr/bin/ruby 2# 3# Endless 4# Copyright (c) 2014-2015 joshua stein <jcs@jcs.org> 5# 6# See LICENSE file for redistribution terms. 7# 8 9require "active_support/core_ext/hash/conversions" 10require "plist" 11require "json" 12require "net/https" 13require "uri" 14 15HTTPS_E_TARGETS_PLIST = "Endless/Resources/https-everywhere_targets.plist" 16HTTPS_E_RULES_PLIST = "Endless/Resources/https-everywhere_rules.plist" 17 18# in b64 for some reason 19HSTS_PRELOAD_LIST = "https://chromium.googlesource.com/chromium/src/net/+/master/http/transport_security_state_static.json?format=TEXT" 20HSTS_PRELOAD_HOSTS_PLIST = "Endless/Resources/hsts_preload.plist" 21 22FORCE = (ARGV[0].to_s == "-f") 23 24# convert all HTTPS Everywhere XML rule files into one big rules hash and write 25# it out as a plist, as well as a standalone hash of target URLs -> rule names 26# to another plist 27def convert_https_e 28 https_e_git_commit = `cd https-everywhere && git show -s`.split("\n")[0]. 29 gsub(/^commit /, "")[0, 12] 30 31 if File.exists?(HTTPS_E_TARGETS_PLIST) 32 if m = File.open(HTTPS_E_TARGETS_PLIST).gets.to_s.match(/Everywhere (.+) - /) 33 if (m[1] == https_e_git_commit) && !FORCE 34 return 35 end 36 end 37 end 38 39 rules = {} 40 targets = {} 41 42 Dir.glob(File.dirname(__FILE__) + 43 "/https-everywhere/src/chrome/content/rules/*.xml").each do |f| 44 hash = Hash.from_xml(File.read(f)) 45 46 raise "no ruleset" if !hash["ruleset"] 47 48 if hash["ruleset"]["default_off"] || 49 hash["ruleset"]["platform"] == "mixedcontent" 50 next # XXX: should we store these? 51 end 52 53 raise "conflict on #{f}" if rules[hash["ruleset"]["name"]] 54 55 # validate regexps 56 begin 57 r = hash["ruleset"]["rule"] 58 r = [ r ] if !r.is_a?(Array) 59 r.each do |h| 60 Regexp.compile(h["from"]) 61 end 62 63 if r = hash["ruleset"]["securecookie"] 64 r = [ r ] if !r.is_a?(Array) 65 r.each do |h| 66 Regexp.compile(h["host"]) 67 Regexp.compile(h["name"]) 68 end 69 end 70 rescue => e 71 STDERR.puts "error in #{f}: #{e} (#{hash.inspect})" 72 exit 1 73 end 74 75 rules[hash["ruleset"]["name"]] = hash 76 77 hash["ruleset"]["target"].each do |target| 78 if !target.is_a?(Hash) 79 # why do some of these get converted into an array? 80 if target.length != 2 || target[0] != "host" 81 puts f 82 raise target.inspect 83 end 84 85 target = { target[0] => target[1] } 86 end 87 88 if targets[target["host"][1]] 89 raise "rules already exist for #{target["host"]}" 90 end 91 92 targets[target["host"]] = hash["ruleset"]["name"] 93 end 94 end 95 96 File.write(HTTPS_E_TARGETS_PLIST, 97 "<!-- generated from HTTPS Everywhere #{https_e_git_commit} - do not " + 98 "directly edit this file -->\n" + 99 targets.to_plist) 100 101 File.write(HTTPS_E_RULES_PLIST, 102 "<!-- generated from HTTPS Everywhere #{https_e_git_commit} - do not " + 103 "directly edit this file -->\n" + 104 rules.to_plist) 105end 106 107def convert_hsts_preload 108 domains = {} 109 110 json = JSON.parse(Net::HTTP.get(URI(HSTS_PRELOAD_LIST)).unpack("m0").first) 111 json["entries"].each do |entry| 112 domains[entry["name"]] = { 113 "include_subdomains" => !!entry["include_subdomains"] 114 } 115 end 116 117 File.write(HSTS_PRELOAD_HOSTS_PLIST, 118 "<!-- generated from #{HSTS_PRELOAD_LIST} - do not directly edit this " + 119 "file -->\n" + 120 domains.to_plist) 121end 122 123convert_https_e 124convert_hsts_preload