[tor-commits] [snowflake/master] Reimagine the badge

cohosh at torproject.org cohosh at torproject.org
Sat Jul 27 16:03:34 UTC 2019


commit e60f22833af9050cafef5ab00931c0c69867130a
Author: Arlo Breault <arlolra at gmail.com>
Date:   Sun Jul 14 09:41:51 2019 +0200

    Reimagine the badge
    
    Trac 27385
---
 .gitignore                                         |   4 +
 proxy/init-badge.js                                | 125 +++++++++++++++++----
 proxy/init-testing.js                              |  83 ++++++++++++++
 proxy/init-webext.js                               | 106 ++++++++++++++++-
 proxy/make.js                                      |  22 ++--
 proxy/static/.htaccess                             |   1 -
 proxy/{webext/popup.css => static/embed.css}       |   7 +-
 proxy/static/embed.html                            |  72 ++++--------
 .../icons/arrowhead-right-12.svg                   |   0
 proxy/{webext => static}/icons/status-off.png      | Bin
 proxy/{webext => static}/icons/status-off.svg      |   0
 proxy/{webext => static}/icons/status-off at 2x.png   | Bin
 proxy/{webext => static}/icons/status-off at 3x.png   | Bin
 proxy/{webext => static}/icons/status-on.png       | Bin
 proxy/{webext => static}/icons/status-on.svg       |   0
 proxy/{webext => static}/icons/status-on at 2x.png    | Bin
 proxy/{webext => static}/icons/status-on at 3x.png    | Bin
 proxy/{webext => static}/icons/status-running.png  | Bin
 proxy/{webext => static}/icons/status-running.svg  |   0
 proxy/static/index.css                             |   5 +
 proxy/static/index.html                            |  11 ++
 proxy/static/koch.jpg                              | Bin 131664 -> 0 bytes
 proxy/static/popup.js                              |  28 +++++
 proxy/static/snowflake.html                        |  60 ----------
 proxy/ui.js                                        | 118 -------------------
 proxy/util.js                                      |  24 ++--
 proxy/webext/{popup.js => embed.js}                |  29 +----
 proxy/webext/manifest.json                         |  32 +++---
 proxy/webext/popup.html                            |  25 -----
 29 files changed, 401 insertions(+), 351 deletions(-)

diff --git a/.gitignore b/.gitignore
index a187011..315500c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,5 +15,9 @@ proxy/build
 proxy/node_modules
 proxy/spec/support
 proxy/webext/snowflake.js
+proxy/webext/popup.js
+proxy/webext/embed.html
+proxy/webext/embed.css
+proxy/webext/icons/
 ignore/
 npm-debug.log
diff --git a/proxy/init-badge.js b/proxy/init-badge.js
index 8646bc4..f85be29 100644
--- a/proxy/init-badge.js
+++ b/proxy/init-badge.js
@@ -1,18 +1,71 @@
 /* global TESTING, Util, Params, Config, DebugUI, BadgeUI, UI, Broker, Snowflake */
 
 /*
-Entry point.
+UI
 */
 
-var snowflake, query, debug, silenceNotifications, log, dbg, init;
+class BadgeUI extends UI {
 
-(function() {
+  constructor() {
+    super();
+    this.popup = new Popup();
+  }
+
+  setStatus() {}
+
+  missingFeature(missing) {
+    this.popup.setImgSrc('off');
+    this.popup.setStatusText("Snowflake is off");
+    this.popup.setStatusDesc(missing, 'firebrick');
+    this.popup.hideButton();
+  }
 
-  if (((typeof TESTING === "undefined" || TESTING === null) || !TESTING) && !Util.featureDetect()) {
-    console.log('webrtc feature not detected. shutting down');
-    return;
+  turnOn() {
+    const clients = this.active ? 1 : 0;
+    this.popup.setChecked(true);
+    this.popup.setToggleText('Turn Off');
+    this.popup.setStatusText(`${clients} client${(clients !== 1) ? 's' : ''} connected.`);
+    // FIXME: Share stats from webext
+    const total = 0;
+    this.popup.setStatusDesc(`Your snowflake has helped ${total} user${(total !== 1) ? 's' : ''} circumvent censorship in the last 24 hours.`);
+    this.popup.setImgSrc(this.active ? "running" : "on");
   }
 
+  turnOff() {
+    this.popup.setChecked(false);
+    this.popup.setToggleText('Turn On');
+    this.popup.setStatusText("Snowflake is off");
+    this.popup.setStatusDesc("");
+    this.popup.setImgSrc("off");
+  }
+
+  setActive(connected) {
+    super.setActive(connected);
+    turnOn();
+  }
+
+}
+
+BadgeUI.prototype.popup = null;
+
+
+/*
+Entry point.
+*/
+
+// Defaults to opt-in.
+var COOKIE_NAME = "snowflake-allow";
+var COOKIE_LIFETIME = "Thu, 01 Jan 2038 00:00:00 GMT";
+var COOKIE_EXPIRE = "Thu, 01 Jan 1970 00:00:01 GMT";
+
+function setSnowflakeCookie(val, expires) {
+  document.cookie = `${COOKIE_NAME}=${val}; path=/; expires=${expires};`;
+}
+
+var debug, snowflake, config, broker, ui, log, dbg, init, update, silenceNotifications, query;
+
+(function() {
+
   snowflake = null;
 
   query = new URLSearchParams(location.search);
@@ -35,32 +88,56 @@ var snowflake, query, debug, silenceNotifications, log, dbg, init;
     }
   };
 
+  update = function() {
+    const cookies = Parse.cookie(document.cookie);
+    if (cookies[COOKIE_NAME] === '1') {
+      ui.turnOn();
+      dbg('Contacting Broker at ' + broker.url);
+      log('Starting snowflake');
+      snowflake.setRelayAddr(config.relayAddr);
+      snowflake.beginWebRTC();
+    } else {
+      ui.turnOff();
+      snowflake.disable();
+      log('Currently not active.');
+    }
+  };
+
   init = function() {
-    var broker, config, ui;
+    ui = new BadgeUI();
+
+    if (!Util.hasWebRTC()) {
+      ui.missingFeature("WebRTC feature is not detected.");
+      return;
+    }
+
+    if (!Util.hasCookies()) {
+      ui.missingFeature("Cookies are not enabled.");
+      return;
+    }
+
+    if (Util.mightBeTBB()) {
+      ui.missingFeature("Will not run within Tor Browser.");
+      return;
+    }
+
     config = new Config;
     if ('off' !== query.get('ratelimit')) {
       config.rateLimitBytes = Params.getByteCount(query, 'ratelimit', config.rateLimitBytes);
     }
-    ui = null;
-    if (document.getElementById('badge') !== null) {
-      ui = new BadgeUI();
-    } else if (document.getElementById('status') !== null) {
-      ui = new DebugUI();
-    } else {
-      ui = new UI();
-    }
     broker = new Broker(config.brokerUrl);
     snowflake = new Snowflake(config, ui, broker);
     log('== snowflake proxy ==');
-    if (Util.snowflakeIsDisabled(config.cookieName)) {
-      // Do not activate the proxy if any number of conditions are true.
-      log('Currently not active.');
-      return;
-    }
-    // Otherwise, begin setting up WebRTC and acting as a proxy.
-    dbg('Contacting Broker at ' + broker.url);
-    snowflake.setRelayAddr(config.relayAddr);
-    return snowflake.beginWebRTC();
+    update();
+
+    document.getElementById('enabled').addEventListener('change', (event) => {
+      if (event.target.checked) {
+        setSnowflakeCookie('1', COOKIE_LIFETIME);
+      } else {
+        setSnowflakeCookie('', COOKIE_EXPIRE);
+      }
+      update();
+    })
   };
 
   // Notification of closing tab with active proxy.
diff --git a/proxy/init-testing.js b/proxy/init-testing.js
new file mode 100644
index 0000000..003f2b6
--- /dev/null
+++ b/proxy/init-testing.js
@@ -0,0 +1,83 @@
+/* global TESTING, Util, Params, Config, DebugUI, UI, Broker, Snowflake */
+
+/*
+Entry point.
+*/
+
+var snowflake, query, debug, silenceNotifications, log, dbg, init;
+
+(function() {
+
+  if (((typeof TESTING === "undefined" || TESTING === null) || !TESTING) && !Util.featureDetect()) {
+    console.log('webrtc feature not detected. shutting down');
+    return;
+  }
+
+  snowflake = null;
+
+  query = new URLSearchParams(location.search);
+
+  debug = Params.getBool(query, 'debug', false);
+
+  silenceNotifications = Params.getBool(query, 'silent', false);
+
+  // Log to both console and UI if applicable.
+  // Requires that the snowflake and UI objects are hooked up in order to
+  // log to console.
+  log = function(msg) {
+    console.log('Snowflake: ' + msg);
+    return snowflake != null ? snowflake.ui.log(msg) : void 0;
+  };
+
+  dbg = function(msg) {
+    if (debug || ((snowflake != null ? snowflake.ui : void 0) instanceof DebugUI)) {
+      return log(msg);
+    }
+  };
+
+  init = function() {
+    var broker, config, ui;
+    config = new Config;
+    if ('off' !== query['ratelimit']) {
+      config.rateLimitBytes = Params.getByteCount(query, 'ratelimit', config.rateLimitBytes);
+    }
+    ui = null;
+    if (document.getElementById('status') !== null) {
+      ui = new DebugUI();
+    } else {
+      ui = new UI();
+    }
+    broker = new Broker(config.brokerUrl);
+    snowflake = new Snowflake(config, ui, broker);
+    log('== snowflake proxy ==');
+    if (Util.snowflakeIsDisabled(config.cookieName)) {
+      // Do not activate the proxy if any number of conditions are true.
+      log('Currently not active.');
+      return;
+    }
+    // Otherwise, begin setting up WebRTC and acting as a proxy.
+    dbg('Contacting Broker at ' + broker.url);
+    snowflake.setRelayAddr(config.relayAddr);
+    return snowflake.beginWebRTC();
+  };
+
+  // Notification of closing tab with active proxy.
+  window.onbeforeunload = function() {
+    if (
+      !silenceNotifications &&
+      snowflake !== null &&
+      Snowflake.MODE.WEBRTC_READY === snowflake.state
+    ) {
+      return Snowflake.MESSAGE.CONFIRMATION;
+    }
+    return null;
+  };
+
+  window.onunload = function() {
+    if (snowflake !== null) { snowflake.disable(); }
+    return null;
+  };
+
+  window.onload = init;
+
+}());
diff --git a/proxy/init-webext.js b/proxy/init-webext.js
index c641621..df618e6 100644
--- a/proxy/init-webext.js
+++ b/proxy/init-webext.js
@@ -2,6 +2,110 @@
 /* eslint no-unused-vars: 0 */
 
 /*
+UI
+*/
+
+class WebExtUI extends UI {
+
+  constructor() {
+    super();
+    this.onConnect = this.onConnect.bind(this);
+    this.onMessage = this.onMessage.bind(this);
+    this.onDisconnect = this.onDisconnect.bind(this);
+    this.initStats();
+    chrome.runtime.onConnect.addListener(this.onConnect);
+  }
+
+  initStats() {
+    this.stats = [0];
+    return setInterval((() => {
+      this.stats.unshift(0);
+      this.stats.splice(24);
+      return this.postActive();
+    }), 60 * 60 * 1000);
+  }
+
+  initToggle() {
+    chrome.storage.local.get("snowflake-enabled", (result) => {
+      if (result['snowflake-enabled'] !== void 0) {
+        this.enabled = result['snowflake-enabled'];
+      } else {
+        log("Toggle state not yet saved");
+      }
+      this.setEnabled(this.enabled);
+    });
+  }
+
+  postActive() {
+    var ref;
+    return (ref = this.port) != null ? ref.postMessage({
+      active: this.active,
+      total: this.stats.reduce((function(t, c) {
+        return t + c;
+      }), 0),
+      enabled: this.enabled
+    }) : void 0;
+  }
+
+  onConnect(port) {
+    this.port = port;
+    port.onDisconnect.addListener(this.onDisconnect);
+    port.onMessage.addListener(this.onMessage);
+    return this.postActive();
+  }
+
+  onMessage(m) {
+    this.enabled = m.enabled;
+    this.setEnabled(this.enabled);
+    this.postActive();
+    chrome.storage.local.set({
+      "snowflake-enabled": this.enabled
+    }, function() {
+      log("Stored toggle state");
+    });
+  }
+
+  onDisconnect() {
+    this.port = null;
+  }
+
+  setActive(connected) {
+    super.setActive(connected);
+    if (connected) {
+      this.stats[0] += 1;
+    }
+    this.postActive();
+    if (this.active) {
+      return chrome.browserAction.setIcon({
+        path: {
+          32: "icons/status-running.png"
+        }
+      });
+    } else {
+      return chrome.browserAction.setIcon({
+        path: {
+          32: "icons/status-on.png"
+        }
+      });
+    }
+  }
+
+  setEnabled(enabled) {
+    update();
+    return chrome.browserAction.setIcon({
+      path: {
+        32: "icons/status-" + (enabled ? "on" : "off") + ".png"
+      }
+    });
+  }
+
+}
+
+WebExtUI.prototype.port = null;
+
+WebExtUI.prototype.stats = null;
+
+/*
 Entry point.
 */
 
@@ -30,7 +134,7 @@ var debug, snowflake, config, broker, ui, log, dbg, init, update, silenceNotific
     }
   };
 
-  if (!Util.featureDetect()) {
+  if (!Util.hasWebRTC()) {
     chrome.runtime.onConnect.addListener(function(port) {
       return port.postMessage({
         missingFeature: true
diff --git a/proxy/make.js b/proxy/make.js
index 5d6e013..52ee098 100755
--- a/proxy/make.js
+++ b/proxy/make.js
@@ -26,14 +26,19 @@ var FILES_SPEC = [
   'spec/websocket.spec.js'
 ];
 
-var OUTFILE = 'snowflake.js';
-
 var STATIC = 'static';
 
-var concatJS = function(outDir, init) {
+var SHARED_FILES = [
+  'embed.html',
+  'embed.css',
+  'popup.js',
+  'icons'
+];
+
+var concatJS = function(outDir, init, outFile) {
   var files;
   files = FILES.concat(`init-${init}.js`);
-  return exec(`cat ${files.join(' ')} > ${outDir}/${OUTFILE}`, function(err) {
+  return exec(`cat ${files.join(' ')} > ${outDir}/${outFile}`, function(err) {
     if (err) {
       throw err;
     }
@@ -53,7 +58,7 @@ task('test', 'snowflake unit tests', function() {
   exec('mkdir -p test');
   exec('jasmine init >&-');
   // Simply concat all the files because we're not using node exports.
-  jasmineFiles = FILES.concat('init-badge.js', FILES_SPEC);
+  jasmineFiles = FILES.concat('init-testing.js', FILES_SPEC);
   outFile = 'test/bundle.spec.js';
   exec('echo "TESTING = true" > ' + outFile);
   exec('cat ' + jasmineFiles.join(' ') + ' | cat >> ' + outFile);
@@ -68,19 +73,20 @@ task('test', 'snowflake unit tests', function() {
 task('build', 'build the snowflake proxy', function() {
   exec('rm -r build');
   exec('cp -r ' + STATIC + '/ build/');
-  concatJS('build', 'badge');
+  concatJS('build', 'badge', 'embed.js');
   console.log('Snowflake prepared.');
 });
 
 task('webext', 'build the webextension', function() {
   exec('mkdir -p webext');
-  concatJS('webext', 'webext');
+  exec(`cp -r ${STATIC}/{${SHARED_FILES.join(',')}} webext/`);
+  concatJS('webext', 'webext', 'snowflake.js');
   console.log('Webextension prepared.');
 });
 
 task('node', 'build the node binary', function() {
   exec('mkdir -p build');
-  concatJS('build', 'node');
+  concatJS('build', 'node', 'snowflake.js');
   console.log('Node prepared.');
 });
 
diff --git a/proxy/static/.htaccess b/proxy/static/.htaccess
index 3dd217d..f733194 100644
--- a/proxy/static/.htaccess
+++ b/proxy/static/.htaccess
@@ -1,4 +1,3 @@
 <Files "embed.html">
     Header always unset X-Frame-Options
 </Files>
-Redirect permanent /options.html /index.html
diff --git a/proxy/webext/popup.css b/proxy/static/embed.css
similarity index 95%
rename from proxy/webext/popup.css
rename to proxy/static/embed.css
index 856e855..e6d8149 100644
--- a/proxy/webext/popup.css
+++ b/proxy/static/embed.css
@@ -2,7 +2,7 @@ body {
   margin: 10px;
   font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
   width: 300px;
-  font-size:12px;
+  font-size: 12px;
 }
 
 #active {
@@ -27,14 +27,13 @@ body {
   display: block;
   position: absolute;
   top: 12px;
-  background-image: url(../icons/arrowhead-right-12.svg);
+  background-image: url('icons/arrowhead-right-12.svg');
   width: 12px;
   height: 12px;
   opacity : 0.6;
   z-index: 9999;
   right: 0px;
   margin-right: 10px;
-
 }
 
 /* Snowflake Status */
@@ -43,14 +42,12 @@ body {
   -webkit-animation:spin 8s linear infinite;
   -moz-animation:spin 8s linear infinite;
   animation:spin 8s linear infinite;
-
   fill: BlueViolet;
 }
 @-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } }
 @-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } }
 @keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } }
 
-
 /* Toggle */
 
 .switch {
diff --git a/proxy/static/embed.html b/proxy/static/embed.html
index 32c26ca..a48daf3 100644
--- a/proxy/static/embed.html
+++ b/proxy/static/embed.html
@@ -1,52 +1,28 @@
 <!doctype html>
 <html>
-<head>
-  <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
-  <meta http-equiv="refresh" content="86400">
-  <script type="text/javascript" src="snowflake.js"></script>
-  <style>
-  * {
-    box-sizing: border-box;
-  }
-  body {
-    position: absolute; width: 100%; height: 100%;
-    top: 0; margin: 0 auto; padding: 0;
-    background-color: #424;
-    text-align: center; cursor: default;
-  }
-  #badge {
-    margin: auto; padding: 0;
-    width: 88px; height: 16px;
-    background-image: url('koch.jpg');
-    white-space: nowrap;
-    color: #000;
-    font-size: 12px; font-weight: 900;
-    font-variant: small-caps;
-    text-shadow: 0 0 5px #fef,
-                 0 1px 2px #fef,
-                 0 -1px 2px #fef,
-                 1px 0px 3px #fef,
-                 -1px 0px 3px #fef;
-  }
-  .active {
-    -webkit-animation: bgScroll 8s linear infinite;
-    animation: bgScroll 8s linear infinite;
-  }
-  @-webkit-keyframes bgScroll {
-    from {background-position: 0 -4%;}
-    to {background-position: 0 104%;}
-  }
-  @keyframes bgScroll {
-    from {background-position: 0 -4%;}
-    to {background-position: 0 104%;}
-  }
-  </style>
-</head>
-<body>
-  <a target="_blank" href="index.html">
-    <div id="badge">
-      Internet Freedom
+  <head>
+    <meta charset="utf-8" />
+    <!-- This should be essentially be a no-opt in the popup -->
+    <meta http-equiv="refresh" content="86400" />
+    <link rel="stylesheet" href="embed.css" />
+    <script src="popup.js"></script>
+    <script src="embed.js"></script>
+  </head>
+  <body>
+    <div id="active">
+      <img src="icons/status-off.png" />
+      <p>Snowflake is off</p>
+      <p></p>
     </div>
-  </a>
-</body>
+    <div class="b button">
+      <label id="toggle" for="enabled">Turn On</label>
+      <label class="switch">
+        <input id="enabled" type="checkbox" />
+        <span class="slider round"></span>
+      </label>
+    </div>
+    <div class="b learn">
+      <a target="_blank" href="https://snowflake.torproject.org/">Learn more</a>
+    </div>
+  </body>
 </html>
diff --git a/proxy/webext/icons/arrowhead-right-12.svg b/proxy/static/icons/arrowhead-right-12.svg
similarity index 100%
rename from proxy/webext/icons/arrowhead-right-12.svg
rename to proxy/static/icons/arrowhead-right-12.svg
diff --git a/proxy/webext/icons/status-off.png b/proxy/static/icons/status-off.png
similarity index 100%
rename from proxy/webext/icons/status-off.png
rename to proxy/static/icons/status-off.png
diff --git a/proxy/webext/icons/status-off.svg b/proxy/static/icons/status-off.svg
similarity index 100%
rename from proxy/webext/icons/status-off.svg
rename to proxy/static/icons/status-off.svg
diff --git a/proxy/webext/icons/status-off at 2x.png b/proxy/static/icons/status-off at 2x.png
similarity index 100%
rename from proxy/webext/icons/status-off at 2x.png
rename to proxy/static/icons/status-off at 2x.png
diff --git a/proxy/webext/icons/status-off at 3x.png b/proxy/static/icons/status-off at 3x.png
similarity index 100%
rename from proxy/webext/icons/status-off at 3x.png
rename to proxy/static/icons/status-off at 3x.png
diff --git a/proxy/webext/icons/status-on.png b/proxy/static/icons/status-on.png
similarity index 100%
rename from proxy/webext/icons/status-on.png
rename to proxy/static/icons/status-on.png
diff --git a/proxy/webext/icons/status-on.svg b/proxy/static/icons/status-on.svg
similarity index 100%
rename from proxy/webext/icons/status-on.svg
rename to proxy/static/icons/status-on.svg
diff --git a/proxy/webext/icons/status-on at 2x.png b/proxy/static/icons/status-on at 2x.png
similarity index 100%
rename from proxy/webext/icons/status-on at 2x.png
rename to proxy/static/icons/status-on at 2x.png
diff --git a/proxy/webext/icons/status-on at 3x.png b/proxy/static/icons/status-on at 3x.png
similarity index 100%
rename from proxy/webext/icons/status-on at 3x.png
rename to proxy/static/icons/status-on at 3x.png
diff --git a/proxy/webext/icons/status-running.png b/proxy/static/icons/status-running.png
similarity index 100%
rename from proxy/webext/icons/status-running.png
rename to proxy/static/icons/status-running.png
diff --git a/proxy/webext/icons/status-running.svg b/proxy/static/icons/status-running.svg
similarity index 100%
rename from proxy/webext/icons/status-running.svg
rename to proxy/static/icons/status-running.svg
diff --git a/proxy/static/index.css b/proxy/static/index.css
index 70b5a24..9502a37 100644
--- a/proxy/static/index.css
+++ b/proxy/static/index.css
@@ -76,3 +76,8 @@ h3 {
 .diagram img, .screenshot img {
   max-width: 100%;
 }
+
+textarea {
+  max-width: 100%;
+  width: 600px;
+}
diff --git a/proxy/static/index.html b/proxy/static/index.html
index e46c373..20fe5c8 100644
--- a/proxy/static/index.html
+++ b/proxy/static/index.html
@@ -77,6 +77,17 @@
       Consider adding keywords <em>snowflake-webextension</em> or <em>snowflake-client</em>
       to let us know how which part of the Snowflake system is experiencing
       problems.</p>
+
+      <h3>EMBED</h3>
+
+      <p>It is now possible to embed the Snowflake badge on any website:</p>
+
+      <textarea readonly><iframe src="https://snowflake.torproject.org/embed.html" width="320px" height="200px" frameborder="0" scrolling="no"></iframe></textarea>
+
+      <p>Which looks like this:</p>
+
+      <iframe src="embed.html" width="320px" height="200px" frameborder="0" scrolling="no"></iframe>
+
     </div>
   </body>
 </html>
diff --git a/proxy/static/koch.jpg b/proxy/static/koch.jpg
deleted file mode 100644
index 1a3c1e3..0000000
Binary files a/proxy/static/koch.jpg and /dev/null differ
diff --git a/proxy/static/popup.js b/proxy/static/popup.js
new file mode 100644
index 0000000..0995775
--- /dev/null
+++ b/proxy/static/popup.js
@@ -0,0 +1,28 @@
+/* exported Popup */
+
+class Popup {
+  constructor() {
+    this.div = document.getElementById('active');
+    this.ps = this.div.querySelectorAll('p');
+    this.img = this.div.querySelector('img');
+  }
+  setImgSrc(src) {
+    this.img.src = `icons/status-${src}.png`;
+  }
+  setStatusText(txt) {
+    this.ps[0].innerText = txt;
+  }
+  setStatusDesc(desc, color) {
+    this.ps[1].innerText = desc;
+    this.ps[1].style.color = color || 'black';
+  }
+  hideButton() {
+    document.querySelector('.button').style.display = 'none';
+  }
+  setChecked(checked) {
+    document.getElementById('enabled').checked = checked;
+  }
+  setToggleText(txt) {
+    document.getElementById('toggle').innerText = txt;
+  }
+}
diff --git a/proxy/static/snowflake.html b/proxy/static/snowflake.html
deleted file mode 100644
index 84790ed..0000000
--- a/proxy/static/snowflake.html
+++ /dev/null
@@ -1,60 +0,0 @@
-<!doctype html>
-<html>
-<head>
-  <title>Snowflake</title>
-  <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
-  <script type="text/javascript" src="snowflake.js"></script>
-  <style>
-  * {
-    box-sizing: border-box;
-    -webkit-transition: all 0.3s;
-    -moz-transition: all 0.3s;
-    transition: all 0.3s;
-  }
-  body {
-    position: absolute;
-    width: 100%; height: 100%; top: 0; margin: 0 auto;
-    background-color: #424;
-    color: #000;
-    text-align: center;
-    font-size: 24px;
-    font-family: monospace;
-    background-image: url('koch.jpg');
-  }
-  textarea {
-    background-color: rgba(0,0,0,0.8);
-    color: #fff;
-    resize: none;
-  }
-  .chatarea {
-    position: relative; border: none;
-    width: 50%; min-width: 40em;
-    padding: 0.5em; margin: auto;
-  }
-  .active { background-color: rgba(0,50,0,0.8); }
-  #msglog {
-    display: block;
-    width: 100%;
-    min-height: 40em;
-    margin-bottom: 1em;
-    padding: 8px;
-  }
-  #status {
-    background-color: rgba(0,0,0,0.9);  color: #999;
-    margin: 8px 0; padding: 8px 1em; cursor: default;
-    font-size: 12px;
-    text-align: left;
-  }
-  </style>
-</head>
-<body>
-  <div class="chatarea">
-    <div id="status">
-      Timeout...
-    </div>
-    <textarea id="msglog" readonly>
-    </textarea>
-  </div>
-
-</body>
-</html>
diff --git a/proxy/ui.js b/proxy/ui.js
index 54e0897..f99affa 100644
--- a/proxy/ui.js
+++ b/proxy/ui.js
@@ -21,23 +21,6 @@ UI.prototype.active = false;
 UI.prototype.enabled = true;
 
 
-class BadgeUI extends UI {
-
-  constructor() {
-    super();
-    this.$badge = document.getElementById('badge');
-  }
-
-  setActive(connected) {
-    super.setActive(connected);
-    return this.$badge.className = connected ? 'active' : '';
-  }
-
-}
-
-BadgeUI.prototype.$badge = null;
-
-
 class DebugUI extends UI {
 
   constructor() {
@@ -75,104 +58,3 @@ class DebugUI extends UI {
 DebugUI.prototype.$msglog = null;
 
 DebugUI.prototype.$status = null;
-
-
-class WebExtUI extends UI {
-
-  constructor() {
-    super();
-    this.onConnect = this.onConnect.bind(this);
-    this.onMessage = this.onMessage.bind(this);
-    this.onDisconnect = this.onDisconnect.bind(this);
-    this.initStats();
-    chrome.runtime.onConnect.addListener(this.onConnect);
-  }
-
-  initStats() {
-    this.stats = [0];
-    return setInterval((() => {
-      this.stats.unshift(0);
-      this.stats.splice(24);
-      return this.postActive();
-    }), 60 * 60 * 1000);
-  }
-
-  initToggle() {
-    chrome.storage.local.get("snowflake-enabled", (result) => {
-      if (result['snowflake-enabled'] !== void 0) {
-        this.enabled = result['snowflake-enabled'];
-      } else {
-        log("Toggle state not yet saved");
-      }
-      this.setEnabled(this.enabled);
-    });
-  }
-
-  postActive() {
-    var ref;
-    return (ref = this.port) != null ? ref.postMessage({
-      active: this.active,
-      total: this.stats.reduce((function(t, c) {
-        return t + c;
-      }), 0),
-      enabled: this.enabled
-    }) : void 0;
-  }
-
-  onConnect(port) {
-    this.port = port;
-    port.onDisconnect.addListener(this.onDisconnect);
-    port.onMessage.addListener(this.onMessage);
-    return this.postActive();
-  }
-
-  onMessage(m) {
-    this.enabled = m.enabled;
-    this.setEnabled(this.enabled);
-    this.postActive();
-    chrome.storage.local.set({
-      "snowflake-enabled": this.enabled
-    }, function() {
-      log("Stored toggle state");
-    });
-  }
-
-  onDisconnect() {
-    this.port = null;
-  }
-
-  setActive(connected) {
-    super.setActive(connected);
-    if (connected) {
-      this.stats[0] += 1;
-    }
-    this.postActive();
-    if (this.active) {
-      return chrome.browserAction.setIcon({
-        path: {
-          32: "icons/status-running.png"
-        }
-      });
-    } else {
-      return chrome.browserAction.setIcon({
-        path: {
-          32: "icons/status-on.png"
-        }
-      });
-    }
-  }
-
-  setEnabled(enabled) {
-    update();
-    return chrome.browserAction.setIcon({
-      path: {
-        32: "icons/status-" + (enabled ? "on" : "off") + ".png"
-      }
-    });
-  }
-
-}
-
-WebExtUI.prototype.port = null;
-
-WebExtUI.prototype.stats = null;
diff --git a/proxy/util.js b/proxy/util.js
index 387f0a1..88a9bf6 100644
--- a/proxy/util.js
+++ b/proxy/util.js
@@ -10,31 +10,21 @@ Contains helpers for parsing query strings and other utilities.
 class Util {
 
   static mightBeTBB() {
-    return Util.TBB_UAS.indexOf(window.navigator.userAgent) > -1 && (window.navigator.mimeTypes && window.navigator.mimeTypes.length === 0);
+    return Util.TBB_UAS.indexOf(window.navigator.userAgent) > -1 && (
+      window.navigator.mimeTypes && window.navigator.mimeTypes.length === 0
+    );
   }
 
   static genSnowflakeID() {
     return Math.random().toString(36).substring(2);
   }
 
-  static snowflakeIsDisabled(cookieName) {
-    var cookies;
-    cookies = Parse.cookie(document.cookie);
-    // Do nothing if snowflake has not been opted in by user.
-    if (cookies[cookieName] !== '1') {
-      log('Not opted-in. Please click the badge to change options.');
-      return true;
-    }
-    // Also do nothing if running in Tor Browser.
-    if (Util.mightBeTBB()) {
-      log('Will not run within Tor Browser.');
-      return true;
-    }
-    return false;
+  static hasWebRTC() {
+    return typeof PeerConnection === 'function';
   }
 
-  static featureDetect() {
-    return typeof PeerConnection === 'function';
+  static hasCookies() {
+    return navigator.cookieEnabled;
   }
 
 }
diff --git a/proxy/webext/popup.js b/proxy/webext/embed.js
similarity index 60%
rename from proxy/webext/popup.js
rename to proxy/webext/embed.js
index d8d6464..e1364bf 100644
--- a/proxy/webext/popup.js
+++ b/proxy/webext/embed.js
@@ -1,36 +1,9 @@
-/* global chrome */
+/* global chrome, Popup */
 
 const port = chrome.runtime.connect({
   name: "popup"
 });
 
-class Popup {
-  constructor() {
-    this.div = document.getElementById('active');
-    this.ps = this.div.querySelectorAll('p');
-    this.img = this.div.querySelector('img');
-  }
-  setImgSrc(src) {
-    this.img.src = `icons/status-${src}.png`;
-  }
-  setStatusText(txt) {
-    this.ps[0].innerText = txt;
-  }
-  setStatusDesc(desc, color) {
-    this.ps[1].innerText = desc;
-    this.ps[1].style.color = color || 'black';
-  }
-  hideButton() {
-    document.querySelector('.button').style.display = 'none';
-  }
-  setChecked(checked) {
-    document.getElementById('enabled').checked = checked;
-  }
-  setToggleText(txt) {
-    document.getElementById('toggle').innerText = txt;
-  }
-}
-
 port.onMessage.addListener((m) => {
   const { active, enabled, total, missingFeature } = m;
   const popup = new Popup();
diff --git a/proxy/webext/manifest.json b/proxy/webext/manifest.json
index 75475ae..3b96055 100644
--- a/proxy/webext/manifest.json
+++ b/proxy/webext/manifest.json
@@ -1,18 +1,18 @@
 {
-	"manifest_version": 2,
-	"name": "Snowflake",
-	"version": "0.0.8",
-	"description": "Snowflake is a WebRTC pluggable transport for Tor.",
-	"background": {
-		"scripts": ["snowflake.js"],
-		"persistent": true
-	},
-	"browser_action": {
-		"default_icon": {
-			"32": "icons/status-on.png"
-		},
-		"default_title": "Snowflake",
-		"default_popup": "popup.html"
-	},
-	"permissions": ["storage"]
+  "manifest_version": 2,
+  "name": "Snowflake",
+  "version": "0.0.8",
+  "description": "Snowflake is a WebRTC pluggable transport for Tor.",
+  "background": {
+    "scripts": ["snowflake.js"],
+    "persistent": true
+  },
+  "browser_action": {
+    "default_icon": {
+      "32": "icons/status-on.png"
+    },
+    "default_title": "Snowflake",
+    "default_popup": "embed.html"
+  },
+  "permissions": ["storage"]
 }
diff --git a/proxy/webext/popup.html b/proxy/webext/popup.html
deleted file mode 100644
index e3ba2f5..0000000
--- a/proxy/webext/popup.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8" />
-    <link rel="stylesheet" href="popup.css" />
-    <script src="popup.js"></script>
-  </head>
-  <body>
-    <div id="active">
-      <img src="icons/status-on.png" />
-        <p></p>
-        <p></p>
-    </div>
-    <div class="b button">
-      <label id="toggle" for="enabled">Turn On</label>
-      <label class="switch">
-        <input id="enabled" type="checkbox" checked/>
-        <span class="slider round"></span>
-      </label>
-    </div>
-    <div class="b learn">
-      <a target="_blank" href="https://snowflake.torproject.org/">Learn more</a>
-    </div>
-  </body>
-</html>





More information about the tor-commits mailing list