Changeset 59280 in spip-zone


Ignore:
Timestamp:
Mar 13, 2012, 9:50:22 PM (8 years ago)
Author:
fil@…
Message:

mise a joru du js de browserid

Location:
_plugins_/authentification/browserid
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • _plugins_/authentification/browserid/browserid.js.html

    r54868 r59280  
    33 *  Plugin BrowserID pour SPIP
    44 *
    5  *  (c) Fil 2011 - Licence GNU/GPL
     5 *  (c) Fil 2012 - Licence GNU/GPL
    66 *
    77 */
  • _plugins_/authentification/browserid/formulaires/login.html

    r54944 r59280  
    33 *  Plugin BrowserID pour SPIP
    44 *
    5  *  (c) Fil 2011 - Licence GNU/GPL
     5 *  (c) Fil 2012 - Licence GNU/GPL
    66 *
    77 */
    88
    9 ]<script type="text/javascript">
     9]
     10
     11[(#REM)
     12        le formulaire de login normal continue de fonctionner ;
     13        on pourrait le desactiver avec une config
     14]
     15<div id="browserid_traditionnel">
     16<INCLURE{fond=prive/formulaires/login,env} />
     17</div>
     18
     19
     20
     21<script type="text/javascript">
    1022[
    1123        var url = (#ENV{url}|sinon{#EVAL{_DIR_RESTREINT_ABS}}|_q);
     
    2537function browserid_start() {
    2638        browserid_message("connexion BrowserID en cours…");
    27         $.getScript('?page=browserid.js&v=8', browserid_login);
     39//      $.getScript('?page=browserid.js&v=8', browserid_login);
     40        browserid_login();
    2841}
    2942</script>
     
    3245<div class="message"></div>
    3346</div>
    34 
    35 [(#REM)
    36         le formulaire de login normal continue de fonctionner ;
    37         on pourrait le desactiver avec une config
    38 ]
    39 <div id="browserid_traditionnel">
    40 <INCLURE{fond=prive/formulaires/login,env} />
    41 </div>
    4247<script type="text/javascript">
    43 $("#browserid_traditionnel").hide();
     48$("#browserid_traditionnel")
     49.hide()
     50.parent()
     51.append("<button onclick='$(\"#browserid_traditionnel\").toggle();'>login traditionnel</button>");
    4452</script>
    45 <button onclick='$("#browserid_traditionnel").show();'>login traditionnel</button>
     53[<script src="(#URL_PAGE{browserid.js}|parametre_url{v,9})" type="text/javascript"></script>]
  • _plugins_/authentification/browserid/javascript/browserid.js

    r54863 r59280  
    22 * Uncompressed source can be found at https://browserid.org/include.orig.js
    33 *
    4  * ***** BEGIN LICENSE BLOCK *****
    5  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
    6  *
    7  * The contents of this file are subject to the Mozilla Public License Version
    8  * 1.1 (the "License"); you may not use this file except in compliance with
    9  * the License. You may obtain a copy of the License at
    10  * http://www.mozilla.org/MPL/
    11  *
    12  * Software distributed under the License is distributed on an "AS IS" basis,
    13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
    14  * for the specific language governing rights and limitations under the
    15  * License.
    16  *
    17  * The Original Code is Mozilla BrowserID.
    18  *
    19  * The Initial Developer of the Original Code is Mozilla.
    20  * Portions created by the Initial Developer are Copyright (C) 2011
    21  * the Initial Developer. All Rights Reserved.
    22  *
    23  * Contributor(s):
    24  *
    25  * Alternatively, the contents of this file may be used under the terms of
    26  * either the GNU General Public License Version 2 or later (the "GPL"), or
    27  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
    28  * in which case the provisions of the GPL or the LGPL are applicable instead
    29  * of those above. If you wish to allow use of your version of this file only
    30  * under the terms of either the GPL or the LGPL, and not to allow others to
    31  * use your version of this file under the terms of the MPL, indicate your
    32  * decision by deleting the provisions above and replace them with the notice
    33  * and other provisions required by the GPL or the LGPL. If you do not delete
    34  * the provisions above, a recipient may use your version of this file under
    35  * the terms of any one of the MPL, the GPL or the LGPL.
    36  *
    37  * ***** END LICENSE BLOCK ***** */
     4 * This Source Code Form is subject to the terms of the Mozilla Public
     5 * License, v. 2.0. If a copy of the MPL was not distributed with this
     6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
    387
    398(function() {
    409  // this is the file that the RP includes to shim in the
    4110  // navigator.id.getVerifiedEmail() function
    42   "use strict";
     11  //  "use strict";
    4312
    4413  // local embedded copy of jschannel: http://github.com/mozilla/jschannel
     14  /**
     15   * js_channel is a very lightweight abstraction on top of
     16   * postMessage which defines message formats and semantics
     17   * to support interactions more rich than just message passing
     18   * js_channel supports:
     19   *  + query/response - traditional rpc
     20   *  + query/update/response - incremental async return of results
     21   *    to a query
     22   *  + notifications - fire and forget
     23   *  + error handling
     24   *
     25   * js_channel is based heavily on json-rpc, but is focused at the
     26   * problem of inter-iframe RPC.
     27   *
     28   * Message types:
     29   *  There are 5 types of messages that can flow over this channel,
     30   *  and you may determine what type of message an object is by
     31   *  examining its parameters:
     32   *  1. Requests
     33   *    + integer id
     34   *    + string method
     35   *    + (optional) any params
     36   *  2. Callback Invocations (or just "Callbacks")
     37   *    + integer id
     38   *    + string callback
     39   *    + (optional) params
     40   *  3. Error Responses (or just "Errors)
     41   *    + integer id
     42   *    + string error
     43   *    + (optional) string message
     44   *  4. Responses
     45   *    + integer id
     46   *    + (optional) any result
     47   *  5. Notifications
     48   *    + string method
     49   *    + (optional) any params
     50   */
    4551  var Channel = (function() {
     52    "use strict";
     53
    4654    // current transaction id, start out at a random *odd* number between 1 and a million
    4755    // There is one current transaction counter id per page, and it's shared between
     
    5058    var s_curTranId = Math.floor(Math.random()*1000001);
    5159
    52     // no two bound channels in the same javascript evaluation context may have the same origin & scope.
    53     // futher if two bound channels have the same scope, they may not have *overlapping* origins
    54     // (either one or both support '*').  This restriction allows a single onMessage handler to efficient
     60    // no two bound channels in the same javascript evaluation context may have the same origin, scope, and window.
     61    // futher if two bound channels have the same window and scope, they may not have *overlapping* origins
     62    // (either one or both support '*').  This restriction allows a single onMessage handler to efficiently
    5563    // route messages based on origin and scope.  The s_boundChans maps origins to scopes, to message
    5664    // handlers.  Request and Notification messages are routed using this table.
     
    5967
    6068    // add a channel to s_boundChans, throwing if a dup exists
    61     function s_addBoundChan(origin, scope, handler) {
     69    function s_addBoundChan(win, origin, scope, handler) {
     70      function hasWin(arr) {
     71        for (var i = 0; i < arr.length; i++) if (arr[i].win === win) return true;
     72        return false;
     73      }
     74
    6275      // does she exist?
    6376      var exists = false;
     77
     78
    6479      if (origin === '*') {
    6580        // we must check all other origins, sadly.
     
    6883          if (k === '*') continue;
    6984          if (typeof s_boundChans[k][scope] === 'object') {
    70             exists = true;
     85            exists = hasWin(s_boundChans[k][scope]);
     86            if (exists) break;
    7187          }
    7288        }
    7389      } else {
    7490        // we must check only '*'
    75         if ((s_boundChans['*'] && s_boundChans['*'][scope]) ||
    76             (s_boundChans[origin] && s_boundChans[origin][scope]))
     91        if ((s_boundChans['*'] && s_boundChans['*'][scope])) {
     92          exists = hasWin(s_boundChans['*'][scope]);
     93        }
     94        if (!exists && s_boundChans[origin] && s_boundChans[origin][scope])
    7795        {
    78           exists = true;
    79         }
    80       }
    81       if (exists) throw "A channel already exists which overlaps with origin '"+ origin +"' and has scope '"+scope+"'";
     96          exists = hasWin(s_boundChans[origin][scope]);
     97        }
     98      }
     99      if (exists) throw "A channel is already bound to the same window which overlaps with origin '"+ origin +"' and has scope '"+scope+"'";
    82100
    83101      if (typeof s_boundChans[origin] != 'object') s_boundChans[origin] = { };
    84       s_boundChans[origin][scope] = handler;
    85     }
    86 
    87     function s_removeBoundChan(origin, scope) {
    88       delete s_boundChans[origin][scope];
    89       // possibly leave a empty object around.  whatevs.
     102      if (typeof s_boundChans[origin][scope] != 'object') s_boundChans[origin][scope] = [ ];
     103      s_boundChans[origin][scope].push({win: win, handler: handler});
     104    }
     105
     106    function s_removeBoundChan(win, origin, scope) {
     107      var arr = s_boundChans[origin][scope];
     108      for (var i = 0; i < arr.length; i++) {
     109        if (arr[i].win === win) {
     110          arr.splice(i,1);
     111        }
     112      }
     113      if (s_boundChans[origin][scope].length === 0) {
     114        delete s_boundChans[origin][scope]
     115      }
    90116    }
    91117
     
    108134    // is more efficient, especially for large numbers of simultaneous channels.
    109135    var s_onMessage = function(e) {
    110       var m = JSON.parse(e.data);
    111       if (typeof m !== 'object') return;
    112 
     136      try {
     137        var m = JSON.parse(e.data);
     138        if (typeof m !== 'object' || m === null) throw "malformed";
     139      } catch(e) {
     140        // just ignore any posted messages that do not consist of valid JSON
     141        return;
     142      }
     143
     144      var w = e.source;
    113145      var o = e.origin;
    114       var s = null;
    115       var i = null;
    116       var meth = null;
     146      var s, i, meth;
    117147
    118148      if (typeof m.method === 'string') {
     
    128158      if (typeof m.id !== 'undefined') i = m.id;
    129159
     160      // w is message source window
    130161      // o is message origin
    131162      // m is parsed message
    132163      // s is message scope
    133       // i is message id (or null)
     164      // i is message id (or undefined)
    134165      // meth is unscoped method name
    135166      // ^^ based on these factors we can route the message
     
    138169      // route using s_boundChans
    139170      if (typeof meth === 'string') {
     171        var delivered = false;
    140172        if (s_boundChans[o] && s_boundChans[o][s]) {
    141           s_boundChans[o][s](o, meth, m);
    142         } else if (s_boundChans['*'] && s_boundChans['*'][s]) {
    143           s_boundChans['*'][s](o, meth, m);
     173          for (var i = 0; i < s_boundChans[o][s].length; i++) {
     174            if (s_boundChans[o][s][i].win === w) {
     175              s_boundChans[o][s][i].handler(o, meth, m);
     176              delivered = true;
     177              break;
     178            }
     179          }
     180        }
     181
     182        if (!delivered && s_boundChans['*'] && s_boundChans['*'][s]) {
     183          for (var i = 0; i < s_boundChans['*'][s].length; i++) {
     184            if (s_boundChans['*'][s][i].win === w) {
     185              s_boundChans['*'][s][i].handler(o, meth, m);
     186              break;
     187            }
     188          }
    144189        }
    145190      }
     
    160205     * Arguments to Channel.build(cfg):
    161206     *
    162      *   cfg.window - the remote window with which we'll communication
     207     *   cfg.window - the remote window with which we'll communicate
    163208     *   cfg.origin - the expected origin of the remote window, may be '*'
    164209     *                which matches any origin
     
    218263          if (cfg.origin === "*") validOrigin = true;
    219264          // allow valid domains under http and https.  Also, trim paths off otherwise valid origins.
    220           else if (null !== (oMatch = cfg.origin.match(/^https?:\/\/(?:[-a-zA-Z0-9\.])+(?::\d+)?/))) {
    221             cfg.origin = oMatch[0];
     265          else if (null !== (oMatch = cfg.origin.match(/^https?:\/\/(?:[-a-zA-Z0-9_\.])+(?::\d+)?/))) {
     266            cfg.origin = oMatch[0].toLowerCase();
    222267            validOrigin = true;
    223268          }
     
    258303            invoke: function(cbName, v) {
    259304              // verify in table
    260               if (!inTbl[id]) throw "attempting to invoke a callback of a non-existant transaction: " + id;
     305              if (!inTbl[id]) throw "attempting to invoke a callback of a nonexistent transaction: " + id;
    261306              // verify that the callback name is valid
    262307              var valid = false;
     
    270315              completed = true;
    271316              // verify in table
    272               if (!inTbl[id]) throw "error called for non-existant message: " + id;
     317              if (!inTbl[id]) throw "error called for nonexistent message: " + id;
    273318
    274319              // remove transaction from table
     
    281326              completed = true;
    282327              // verify in table
    283               if (!inTbl[id]) throw "complete called for non-existant message: " + id;
     328              if (!inTbl[id]) throw "complete called for nonexistent message: " + id;
    284329              // remove transaction from table
    285330              delete inTbl[id];
     
    299344        }
    300345
     346        var setTransactionTimeout = function(transId, timeout, method) {
     347          return window.setTimeout(function() {
     348            if (outTbl[transId]) {
     349              // XXX: what if client code raises an exception here?
     350              var msg = "timeout (" + timeout + "ms) exceeded on method '" + method + "'";
     351              (1,outTbl[transId].error)("timeout_error", msg);
     352              delete outTbl[transId];
     353              delete s_transIds[transId];
     354            }
     355          }, timeout);
     356        }
     357       
    301358        var onMessage = function(origin, method, m) {
    302359          // if an observer was specified at allocation time, invoke it
     
    346403                var error = "runtime_error";
    347404                var message = null;
    348                 // * if its a string then it gets an error code of 'runtime_error' and string is the message
     405                // * if it's a string then it gets an error code of 'runtime_error' and string is the message
    349406                if (typeof e === 'string') {
    350407                  message = e;
    351408                } else if (typeof e === 'object') {
    352409                  // either an array or an object
    353                   // * if its an array of length two, then  array[0] is the code, array[1] is the error message
     410                  // * if it's an array of length two, then  array[0] is the code, array[1] is the error message
    354411                  if (e && s_isArray(e) && e.length == 2) {
    355412                    error = e[0];
    356413                    message = e[1];
    357414                  }
    358                   // * if its an object then we'll look form error and message parameters
     415                  // * if it's an object then we'll look form error and message parameters
    359416                  else if (typeof e.error === 'string') {
    360417                    error = e.error;
     
    369426                  try {
    370427                    message = JSON.stringify(e);
     428                    /* On MSIE8, this can result in 'out of memory', which
     429                     * leaves message undefined. */
     430                    if (typeof(message) == 'undefined')
     431                      message = e.toString();
    371432                  } catch (e2) {
    372433                    message = e.toString();
     
    409470            }
    410471          }
    411         };
     472        }
    412473
    413474        // now register our bound channel for msg routing
    414         s_addBoundChan(cfg.origin, ((typeof cfg.scope === 'string') ? cfg.scope : ''), onMessage);
     475        s_addBoundChan(cfg.window, cfg.origin, ((typeof cfg.scope === 'string') ? cfg.scope : ''), onMessage);
    415476
    416477        // scope method names based on cfg.scope specified when the Channel was instantiated
     
    418479          if (typeof cfg.scope === 'string' && cfg.scope.length) m = [cfg.scope, m].join("::");
    419480          return m;
    420         };
     481        }
    421482
    422483        // a small wrapper around postmessage whose primary function is to handle the
     
    441502            cfg.window.postMessage(JSON.stringify(msg), cfg.origin);
    442503          }
    443         };
     504        }
    444505
    445506        var onReady = function(trans, type) {
     
    485546            if (regTbl[method]) throw "method '"+method+"' is already bound!";
    486547            regTbl[method] = cb;
     548            return this;
    487549          },
    488550          call: function(m) {
     
    517579            if (callbackNames.length) msg.callbacks = callbackNames;
    518580
     581            if (m.timeout)
     582              // XXX: This function returns a timeout ID, but we don't do anything with it.
     583              // We might want to keep track of it so we can cancel it using clearTimeout()
     584              // when the transaction completes.
     585              setTransactionTimeout(s_curTranId, m.timeout, scopeMethod(m.method));
     586
    519587            // insert into the transaction table
    520588            outTbl[s_curTranId] = { callbacks: callbacks, error: m.error, success: m.success };
     
    534602          },
    535603          destroy: function () {
    536             s_removeBoundChan(cfg.origin, ((typeof cfg.scope === 'string') ? cfg.scope : ''));
     604            s_removeBoundChan(cfg.window, cfg.origin, ((typeof cfg.scope === 'string') ? cfg.scope : ''));
    537605            if (window.removeEventListener) window.removeEventListener('message', onMessage, false);
    538606            else if(window.detachEvent) window.detachEvent('onmessage', onMessage);
     
    550618        obj.bind('__ready', onReady);
    551619        setTimeout(function() {
    552           postMessage({ method: scopeMethod('__ready'), params: "ping" }, true);
     620//          postMessage({ method: scopeMethod('__ready'), params: "ping" }, true);
    553621        }, 0);
    554622
     
    556624      }
    557625    };
     626  })();
     627
     628  // local embedded copy of winchan: http://github.com/lloyd/winchan
     629  ;WinChan = (function() {
     630    var RELAY_FRAME_NAME = "__winchan_relay_frame";
     631
     632    // a portable addListener implementation
     633    function addListener(w, event, cb) {
     634      if(w.attachEvent) w.attachEvent('on' + event, cb);
     635      else if (w.addEventListener) w.addEventListener(event, cb, false);
     636    }
     637
     638    // a portable removeListener implementation
     639    function removeListener(w, event, cb) {
     640      if(w.detachEvent) w.detachEvent('on' + event, cb);
     641      else if (w.removeEventListener) w.removeEventListener(event, cb, false);
     642    }
     643
     644    // checking for IE8 or above
     645    function isInternetExplorer() {
     646      var rv = -1; // Return value assumes failure.
     647      if (navigator.appName == 'Microsoft Internet Explorer') {
     648        var ua = navigator.userAgent;
     649        var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
     650        if (re.exec(ua) != null)
     651          rv = parseFloat(RegExp.$1);
     652      }
     653      return rv >= 8;
     654    }
     655
     656    // checking Mobile Firefox (Fennec)
     657    function isFennec() {
     658      try {
     659        return (navigator.userAgent.indexOf('Fennec/') != -1);
     660      } catch(e) {};
     661      return false;
     662    }
     663
     664    // feature checking to see if this platform is supported at all
     665    function isSupported() {
     666      return (window.JSON && window.JSON.stringify &&
     667              window.JSON.parse && window.postMessage);
     668    }
     669
     670    // given a URL, extract the origin
     671    function extractOrigin(url) {
     672      if (!/^https?:\/\//.test(url)) url = window.location.href;
     673      var m = /^(https?:\/\/[-_a-zA-Z\.0-9:]+)/.exec(url);
     674      if (m) return m[1];
     675      return url;
     676    }
     677
     678    // find the relay iframe in the opener
     679    function findRelay() {
     680      var loc = window.location;
     681      var frames = window.opener.frames;
     682      var origin = loc.protocol + '//' + loc.host;
     683      for (i = frames.length - 1; i >= 0; i++) {
     684        try {
     685          if (frames[i].location.href.indexOf(origin) === 0 &&
     686              frames[i].name === RELAY_FRAME_NAME)
     687          {
     688            return frames[i];
     689          }
     690        } catch(e) { }
     691      }
     692      return;
     693    }
     694
     695    var isIE = isInternetExplorer();
     696
     697    if (isSupported()) {
     698      /*  General flow:
     699       *                  0. user clicks
     700       *  (IE SPECIFIC)   1. caller adds relay iframe (served from trusted domain) to DOM
     701       *                  2. caller opens window (with content from trusted domain)
     702       *                  3. window on opening adds a listener to 'message'
     703       *  (IE SPECIFIC)   4. window on opening finds iframe
     704       *                  5. window checks if iframe is "loaded" - has a 'doPost' function yet
     705       *  (IE SPECIFIC5)  5a. if iframe.doPost exists, window uses it to send ready event to caller
     706       *  (IE SPECIFIC5)  5b. if iframe.doPost doesn't exist, window waits for frame ready
     707       *  (IE SPECIFIC5)  5bi. once ready, window calls iframe.doPost to send ready event
     708       *                  6. caller upon reciept of 'ready', sends args
     709       */
     710      return {
     711        open: function(opts, cb) {
     712          if (!cb) throw "missing required callback argument";
     713
     714          // test required options
     715          var err;
     716          if (!opts.url) err = "missing required 'url' parameter";
     717          if (!opts.relay_url) err = "missing required 'relay_url' parameter";
     718          if (err) setTimeout(function() { cb(err); }, 0);
     719
     720          // supply default options
     721          if (!opts.window_features || isFennec()) opts.window_features = undefined;
     722
     723          // opts.params may be undefined
     724
     725          var iframe;
     726
     727          // sanity check, are url and relay_url the same origin?
     728          var origin = extractOrigin(opts.url);
     729          if (origin !== extractOrigin(opts.relay_url)) {
     730            return setTimeout(function() {
     731              cb('invalid arguments: origin of url and relay_url must match');
     732            }, 0);
     733          }
     734
     735          var messageTarget;
     736
     737          if (isIE) {
     738            // first we need to add a "relay" iframe to the document that's served
     739            // from the target domain.  We can postmessage into a iframe, but not a
     740            // window
     741            iframe = document.createElement("iframe");
     742            // iframe.setAttribute('name', framename);
     743            iframe.setAttribute('src', opts.relay_url);
     744            iframe.style.display = "none";
     745            iframe.setAttribute('name', RELAY_FRAME_NAME);
     746            document.body.appendChild(iframe)
     747            messageTarget = iframe.contentWindow;
     748          }
     749
     750          var w = window.open(opts.url, null, opts.window_features);
     751
     752          if (!messageTarget) messageTarget = w;
     753
     754          var req = JSON.stringify({a: 'request', d: opts.params});
     755
     756          // cleanup on unload
     757          function cleanup() {
     758            if (iframe) document.body.removeChild(iframe);
     759            iframe = undefined;
     760            if (w) w.close();
     761            w = undefined;
     762          }
     763
     764          addListener(window, 'unload', cleanup);
     765
     766          function onMessage(e) {
     767            try {
     768              var d = JSON.parse(e.data);
     769              if (d.a === 'ready') messageTarget.postMessage(req, origin);
     770              else if (d.a === 'error') cb(d.d);
     771              else if (d.a === 'response') {
     772                removeListener(window, 'message', onMessage);
     773                removeListener(window, 'unload', cleanup);
     774                cleanup();
     775                cb(null, d.d);
     776              }
     777            } catch(e) { }
     778          };
     779
     780          addListener(window, 'message', onMessage);
     781
     782          return {
     783            close: cleanup,
     784            focus: function() {
     785              if (w) {
     786                try {
     787                  w.focus();
     788                }
     789                catch(e) {
     790                  /* IE7 blows up here, do nothing */
     791                }
     792              }
     793            }
     794          };
     795        }
     796      }
     797    } else {
     798      return {
     799        open: function(url, winopts, arg, cb) {
     800          setTimeout(function() { cb("unsupported browser"); }, 0);
     801        }
     802      };
     803    }
    558804  })();
    559805
     
    583829    function checkIE() {
    584830      var ieVersion = getInternetExplorerVersion(),
    585           ieNosupport = ieVersion > -1 && ieVersion < 9;
     831          ieNosupport = ieVersion > -1 && ieVersion < 8;
    586832
    587833      if(ieNosupport) {
     
    607853    }
    608854
     855    function checkJSON() {
     856      if(!(window.JSON && window.JSON.stringify && window.JSON.parse)) {
     857        return "JSON";
     858      }
     859    }
     860
    609861    function isSupported() {
    610       reason = checkLocalStorage() || checkPostMessage() || explicitNosupport();
     862      reason = checkLocalStorage() || checkPostMessage() || checkJSON() || explicitNosupport();
    611863
    612864      return !reason;
     
    630882      isSupported: isSupported,
    631883      /**
    632        * Called after isSupported, if isSupported returns false.  Gets the reason 
     884       * Called after isSupported, if isSupported returns false.  Gets the reason
    633885       * why browser is not supported.
    634886       * @method getNoSupportReason
     
    637889      getNoSupportReason: getNoSupportReason
    638890    };
    639    
    640891  }());
    641892
     
    644895  function _open_hidden_iframe(doc) {
    645896    var iframe = doc.createElement("iframe");
    646     // iframe.style.display = "none";
    647     doc.body.appendChild(iframe);
    648     iframe.src = ipServer + "/register_iframe";
    649     return iframe;
    650   }
    651 
    652   function _get_relayframe_id() {
    653     var randomString = '';
    654     var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    655     for (var i=0; i < 4; i++) {
    656       randomString += possible.charAt(Math.floor(Math.random() * possible.length));
    657     }
    658     return randomString;
    659   }
    660 
    661   function _open_relayframe(framename) {
    662     var doc = window.document;
    663     var iframe = doc.createElement("iframe");
    664     iframe.setAttribute('name', framename);
    665     iframe.setAttribute('src', ipServer + "/relay");
    666897    iframe.style.display = "none";
    667898    doc.body.appendChild(iframe);
    668 
     899    iframe.src = ipServer + "/communication_iframe";
    669900    return iframe;
    670   }
    671  
    672   function _open_window(url) {
    673     url = url || "about:blank";
    674     // we open the window initially blank, and only after our relay frame has
    675     // been constructed do we update the location.  This is done because we
    676     // must launch the window inside a click handler, but we should wait to
    677     // start loading it until our relay iframe is instantiated and ready.
    678     // see issue #287 & #286
    679     var dialog = window.open(
    680       url,
    681       "_mozid_signin",
    682       isFennec ? undefined : "menubar=0,location=0,resizable=0,scrollbars=0,status=0,dialog=1,width=700,height=375");
    683 
    684     dialog.focus();
    685     return dialog;
    686   }
    687 
    688   function _attach_event(element, name, listener) {
    689     if (element.addEventListener) {
    690       element.addEventListener(name, listener, false);
    691     }
    692     else if(element.attachEvent) {
    693       // IE < 9
    694       element.attachEvent(name, listener);
    695     }
    696   }
    697 
    698   function _detatch_event(element, name, listener) {
    699     if (element.removeEventListener) {
    700       element.removeEventListener(name, listener, false);
    701     }
    702     else if(element.detachEvent) {
    703       element.detachEvent(name, listener);
    704     }
    705901  }
    706902
     
    717913    var ipServer = "https://browserid.org";
    718914    var isFennec = navigator.userAgent.indexOf('Fennec/') != -1;
    719 
    720     var chan, w, iframe;
    721 
    722     // keep track of these so that we can re-use/re-focus an already open window.
    723     navigator.id.getVerifiedEmail = function(callback) {
    724       if (w) {
    725         // if there is already a window open, just focus the old window.
    726         w.focus();
    727         return;
    728       }
    729 
    730       if (!BrowserSupport.isSupported()) {
    731         w = _open_window(ipServer + "/unsupported_dialog");
    732         return;
    733       }
    734 
    735       var frameid = _get_relayframe_id();
    736       var iframe = _open_relayframe("browserid_relay_" + frameid);
    737       w = _open_window();
    738 
    739       // if the RP window closes, close the dialog as well.
    740       _attach_event(window, 'unload', cleanup);
    741 
    742       // clean up a previous channel that never was reaped
    743       if (chan) chan.destroy();
    744       chan = Channel.build({
    745         window: iframe.contentWindow,
    746         origin: ipServer,
    747         scope: "mozid",
    748         onReady: function() {
    749           // We have to change the name of the relay frame every time or else Firefox
    750           // has a problem re-attaching new iframes with the same name.  Code inside
    751           // of frames with the same name sometimes does not get run.
    752           // See https://bugzilla.mozilla.org/show_bug.cgi?id=350023
    753           w = _open_window(ipServer + "/sign_in#" + frameid);
    754         }
    755       });
    756 
    757       function cleanup() {
    758         chan.destroy();
    759         chan = null;
    760 
     915    var windowOpenOpts =
     916      (isFennec ? undefined :
     917       "menubar=0,location=1,resizable=0,scrollbars=0,status=0,dialog=1,width=700,height=375");
     918
     919    var w;
     920
     921    navigator.id.get = function(callback, options) {
     922      if (typeof callback !== 'function') {
     923        throw "navigator.id.get() requires a callback argument";
     924      }
     925
     926      if (options && options.silent) {
     927        _noninteractiveCall('getPersistentAssertion', { }, function(rv) {
     928          callback(rv);
     929        }, function(e, msg) {
     930          callback(null);
     931        });
     932      } else {
     933        // focus an existing window
    761934        if (w) {
    762           w.close();
    763           w = null;
    764         }
    765 
    766         iframe.parentNode.removeChild(iframe);
    767         iframe = null;
    768 
    769         _detatch_event(window, 'unload', cleanup);
    770       }
    771 
    772       chan.call({
    773         method: "getVerifiedEmail",
    774         success: function(rv) {
    775           if (callback) {
    776             // return the string representation of the JWT, the client is responsible for unpacking it.
    777             callback(rv);
    778           }
    779           cleanup();
    780         },
    781         error: function(code, msg) {
    782           // XXX: we don't make the code and msg available to the user.
    783           if (callback) callback(null);
    784           cleanup();
    785         }
     935          try {
     936            w.focus();
     937          }
     938          catch(e) {
     939            /* IE7 blows up here, do nothing */
     940          }
     941          return;
     942        }
     943
     944        if (!BrowserSupport.isSupported()) {
     945          w = window.open(
     946            ipServer + "/unsupported_dialog",
     947            null,
     948            windowOpenOpts);
     949          return;
     950        }
     951
     952        w = WinChan.open({
     953          url: ipServer + '/sign_in',
     954          relay_url: ipServer + '/relay',
     955          window_features: windowOpenOpts,
     956          params: {
     957            method: "get",
     958            params: options
     959          }
     960        }, function(err, r) {
     961          // clear the window handle
     962          w = undefined;
     963          // ignore err!
     964          callback(err ? null : (r ? r : null));
     965        });
     966      }
     967    };
     968
     969    navigator.id.getVerifiedEmail = function (callback, options) {
     970      if (options) {
     971        throw "getVerifiedEmail doesn't accept options.  use navigator.id.get() instead.";
     972      }
     973      navigator.id.get(callback);
     974    };
     975
     976    navigator.id.logout = function(callback) {
     977      _noninteractiveCall('logout', { }, function(rv) {
     978        callback(rv);
     979      }, function() {
     980        callback(null);
    786981      });
    787982    };
    788983
    789   /*
    790     // preauthorize a particular email
    791     // FIXME: lots of cut-and-paste code here, need to refactor
    792     // not refactoring now because experimenting and don't want to break existing code
    793     navigator.id.preauthEmail = function(email, onsuccess, onerror) {
     984    var _noninteractiveCall = function(method, args, onsuccess, onerror) {
    794985      var doc = window.document;
    795       var iframe = _create_iframe(doc);
    796 
    797       // clean up a previous channel that never was reaped
    798       if (chan) chan.destroy();
    799       chan = Channel.build({window: iframe.contentWindow, origin: ipServer, scope: "mozid"});
     986      var ni_iframe = _open_hidden_iframe(doc);
     987
     988      var chan = Channel.build({window: ni_iframe.contentWindow, origin: ipServer, scope: "mozid_ni"});
    800989
    801990      function cleanup() {
    802991        chan.destroy();
    803992        chan = undefined;
    804         doc.body.removeChild(iframe);
    805       }
    806 
    807       chan.call({
    808         method: "preauthEmail",
    809         params: email,
    810         success: function(rv) {
    811           onsuccess(rv);
    812           cleanup();
    813         },
    814         error: function(code, msg) {
    815           if (onerror) onerror(code, msg);
    816           cleanup();
    817         }
    818       });
    819     };
    820     */
    821 
    822     // get a particular verified email
    823     // FIXME: needs to ditched for now until fixed
    824     /*
    825     navigator.id.getSpecificVerifiedEmail = function(email, token, onsuccess, onerror) {
    826       var doc = window.document;
    827 
    828       // if we have a token, we should not be opening a window, rather we should be
    829       // able to do this entirely through IFRAMEs
    830       var w;
    831       if (token) {
    832           var iframe = _create_iframe(doc);
    833           w = iframe.contentWindow;
    834       } else {
    835           _open_window();
    836           _open_relay_frame(doc);
    837       }
    838 
    839       // clean up a previous channel that never was reaped
    840       if (chan) chan.destroy();
    841       chan = Channel.build({window: w, origin: ipServer, scope: "mozid"});
    842 
    843       function cleanup() {
    844         chan.destroy();
    845         chan = undefined;
    846         if (token) {
    847             // just remove the IFRAME
    848             doc.body.removeChild(iframe);
    849         } else {
    850             w.close();
    851         }
    852       }
    853 
    854       chan.call({
    855         method: "getSpecificVerifiedEmail",
    856         params: [email, token],
    857         success: function(rv) {
    858           if (onsuccess) {
    859             // return the string representation of the JWT, the client is responsible for unpacking it.
    860             onsuccess(rv);
    861           }
    862           cleanup();
    863         },
    864         error: function(code, msg) {
    865           if (onerror) onerror(code, msg);
    866           cleanup();
    867         }
    868       });
    869     };
    870     */
    871 
    872     var _noninteractiveCall = function(method, args, onsuccess, onerror) {
    873       var doc = window.document;
    874       iframe = _open_hidden_iframe(doc);
    875 
    876       // clean up channel
    877       if (chan) chan.destroy();
    878       chan = Channel.build({window: iframe.contentWindow, origin: ipServer, scope: "mozid"});
    879      
    880       function cleanup() {
    881         chan.destroy();
    882         chan = undefined;
    883         doc.body.removeChild(iframe);
    884       }
    885      
     993        doc.body.removeChild(ni_iframe);
     994      }
     995
    886996      chan.call({
    887997        method: method,
     
    8971007          cleanup();
    8981008        }
    899       });   
    900     }
    901 
    902     //
    903     // for now, disabling primary support.
    904     //
    905 
    906     /*
    907     // check if a valid cert exists for this verified email
    908     // calls back with true or false
    909     // FIXME: implement it for real, but
    910     // be careful here because this needs to be limited
    911     navigator.id.checkVerifiedEmail = function(email, onsuccess, onerror) {
    912       onsuccess(false);
     1009      });
    9131010    };
    9141011
    915     // generate a keypair
    916     navigator.id.generateKey = function(onsuccess, onerror) {
    917       _noninteractiveCall("generateKey", {},
    918                           onsuccess, onerror);
    919     };
    920    
    921     navigator.id.registerVerifiedEmailCertificate = function(certificate, updateURL, onsuccess, onerror) {
    922       _noninteractiveCall("registerVerifiedEmailCertificate",
    923                           {cert:certificate, updateURL: updateURL},
    924                           onsuccess, onerror);
    925     };
    926     */
    927    
    9281012    navigator.id._getVerifiedEmailIsShimmed = true;
    9291013  }
  • _plugins_/authentification/browserid/plugin.xml

    r54959 r59280  
    22        <nom>BrowserID</nom>
    33        <auteur>Fil</auteur>
    4         <version>0.2</version>
     4        <version>0.3</version>
    55        <etat>
    66        dev
Note: See TracChangeset for help on using the changeset viewer.