Bug 1127004 - Receive OOB auth images from Gaia. r=janx
authorJ. Ryan Stinnett <jryans@gmail.com>
Thu, 05 Feb 2015 15:26:14 -0600
changeset 227766 78af92a0f9452a46d26f9890871f38cc69eb9437
parent 227765 c0783a0a2d415901dadc89cef8eb5d8d50436e13
child 227767 6fcfaa95e84a754e125725747a8da9e0bcbf12d2
push id28239
push userryanvm@gmail.com
push dateFri, 06 Feb 2015 13:52:40 +0000
treeherdermozilla-central@03b0004eba32 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjanx
bugs1127004
milestone38.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1127004 - Receive OOB auth images from Gaia. r=janx
b2g/chrome/content/devtools/debugger.js
--- a/b2g/chrome/content/devtools/debugger.js
+++ b/b2g/chrome/content/devtools/debugger.js
@@ -51,53 +51,119 @@ let RemoteDebugger = {
   allowConnection(session) {
     if (this._promptingForAllow) {
       // Don't stack connection prompts if one is already open
       return DebuggerServer.AuthenticationResult.DENY;
     }
     this._listen();
 
     this._promptingForAllow = new Promise(resolve => {
-      this._handleAllowResult = allowed => {
+      this._handleAllowResult = detail => {
         this._handleAllowResult = null;
         this._promptingForAllow = null;
-        if (allowed) {
+        if (detail.value) {
           resolve(DebuggerServer.AuthenticationResult.ALLOW);
         } else {
           resolve(DebuggerServer.AuthenticationResult.DENY);
         }
       };
 
       shell.sendChromeEvent({
         type: "remote-debugger-prompt",
         session
       });
     });
 
     return this._promptingForAllow;
   },
 
+  /**
+   * During OOB_CERT authentication, the user must transfer some data through some
+   * out of band mechanism from the client to the server to authenticate the
+   * devices.
+   *
+   * This implementation instructs Gaia to continually capture images which are
+   * passed back here and run through a QR decoder.
+   *
+   * @return An object containing:
+   *         * sha256: hash(ClientCert)
+   *         * k     : K(random 128-bit number)
+   *         A promise that will be resolved to the above is also allowed.
+   */
+  receiveOOB() {
+    if (this._receivingOOB) {
+      return this._receivingOOB;
+    }
+    this._listen();
+
+    const QR = devtools.require("devtools/toolkit/qrcode/index");
+    this._receivingOOB = new Promise((resolve, reject) => {
+      this._handleAuthEvent = detail => {
+        debug(detail.action);
+        if (detail.action === "abort") {
+          this._handleAuthEvent = null;
+          this._receivingOOB = null;
+          reject();
+          return;
+        }
+
+        if (detail.action !== "capture") {
+          return;
+        }
+
+        let url = detail.url;
+        QR.decodeFromURI(url).then(data => {
+          debug("Got auth data: " + data);
+          let oob = JSON.parse(data);
+
+          shell.sendChromeEvent({
+            type: "devtools-auth",
+            action: "stop"
+          });
+
+          this._handleAuthEvent = null;
+          this._receivingOOB = null;
+          resolve(oob);
+        }).catch(() => {
+          debug("No auth data, requesting new capture");
+          shell.sendChromeEvent({
+            type: "devtools-auth",
+            action: "capture"
+          });
+        });
+      };
+
+      // Show QR scanning dialog, get an initial capture
+      shell.sendChromeEvent({
+        type: "devtools-auth",
+        action: "start"
+      });
+    });
+
+    return this._receivingOOB;
+  },
+
   _listen: function() {
     if (this._listening) {
       return;
     }
 
     this.handleEvent = this.handleEvent.bind(this);
     let content = shell.contentBrowser.contentWindow;
     content.addEventListener("mozContentEvent", this, false, true);
     this._listening = true;
   },
 
   handleEvent: function(event) {
     let detail = event.detail;
-    if (detail.type !== "remote-debugger-prompt") {
-      return;
+    if (detail.type === "remote-debugger-prompt" && this._handleAllowResult) {
+      this._handleAllowResult(detail);
     }
-    if (this._handleAllowResult) {
-      this._handleAllowResult(detail.value);
+    if (detail.type === "devtools-auth" && this._handleAuthEvent) {
+      this._handleAuthEvent(detail);
     }
   },
 
   initServer: function() {
     if (DebuggerServer.initialized) {
       return;
     }
 
@@ -143,16 +209,18 @@ let RemoteDebugger = {
       AdbController.updateState();
     });
 #endif
   }
 };
 
 RemoteDebugger.allowConnection =
   RemoteDebugger.allowConnection.bind(RemoteDebugger);
+RemoteDebugger.receiveOOB =
+  RemoteDebugger.receiveOOB.bind(RemoteDebugger);
 
 let USBRemoteDebugger = {
 
   get isDebugging() {
     if (!this._listener) {
       return false;
     }
 
@@ -212,16 +280,17 @@ let WiFiRemoteDebugger = {
 
     RemoteDebugger.initServer();
 
     try {
       debug("Starting WiFi debugger");
       let AuthenticatorType = DebuggerServer.Authenticators.get("OOB_CERT");
       let authenticator = new AuthenticatorType.Server();
       authenticator.allowConnection = RemoteDebugger.allowConnection;
+      authenticator.receiveOOB = RemoteDebugger.receiveOOB;
       this._listener = DebuggerServer.createListener();
       this._listener.portOrPath = -1 /* any available port */;
       this._listener.authenticator = authenticator;
       this._listener.discoverable = true;
       this._listener.encryption = true;
       this._listener.open();
       let port = this._listener.port;
       debug("Started WiFi debugger on " + port);