Changeset 62555 in spip-zone


Ignore:
Timestamp:
Jun 14, 2012, 9:14:23 PM (7 years ago)
Author:
fil@…
Message:

maj browserid.js

File:
1 edited

Legend:

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

    r59280 r62555  
    355355          }, timeout);
    356356        }
    357        
     357
    358358        var onMessage = function(origin, method, m) {
    359359          // if an observer was specified at allocation time, invoke it
     
    657657    function isFennec() {
    658658      try {
    659         return (navigator.userAgent.indexOf('Fennec/') != -1);
     659        // We must check for both XUL and Java versions of Fennec.  Both have
     660        // distinct UA strings.
     661        return (userAgent.indexOf('Fennec/') != -1) ||  // XUL
     662                 (userAgent.indexOf('Firefox/') != -1 && userAgent.indexOf('Android') != -1);   // Java
    660663      } catch(e) {};
    661664      return false;
     
    768771              var d = JSON.parse(e.data);
    769772              if (d.a === 'ready') messageTarget.postMessage(req, origin);
    770               else if (d.a === 'error') cb(d.d);
    771               else if (d.a === 'response') {
     773              else if (d.a === 'error') {
     774                if (cb) { cb(d.d); cb = null; }
     775              } else if (d.a === 'response') {
    772776                removeListener(window, 'message', onMessage);
    773777                removeListener(window, 'unload', cleanup);
    774778                cleanup();
    775                 cb(null, d.d);
     779                if (cb) { cb(null, d.d); cb = null; }
    776780              }
    777781            } catch(e) { }
     
    832836
    833837      if(ieNosupport) {
    834         return "IE_VERSION";
     838        return "BAD_IE_VERSION";
    835839      }
    836840    }
     
    841845
    842846    function checkLocalStorage() {
    843       var localStorage = 'localStorage' in win && win['localStorage'] !== null;
    844       if(!localStorage) {
    845         return "LOCALSTORAGE";
     847      // Firefox/Fennec/Chrome blow up when trying to access or
     848      // write to localStorage. We must do two explicit checks, first
     849      // whether the browser has localStorage.  Second, we must check
     850      // whether the localStorage can be written to.  Firefox (at v11)
     851      // throws an exception when querying win['localStorage']
     852      // when cookies are disabled. Chrome (v17) excepts when trying to
     853      // write to localStorage when cookies are disabled. If an
     854      // exception is thrown, then localStorage is disabled. If no
     855      // exception is thrown, hasLocalStorage will be true if the
     856      // browser supports localStorage and it can be written to.
     857      try {
     858        var hasLocalStorage = 'localStorage' in win
     859                        // Firefox will except here if cookies are disabled.
     860                        && win['localStorage'] !== null;
     861
     862        if(hasLocalStorage) {
     863          // browser has localStorage, check if it can be written to. If
     864          // cookies are disabled, some browsers (Chrome) will except here.
     865          win['localStorage'].setItem("test", "true");
     866          win['localStorage'].removeItem("test");
     867        }
     868        else {
     869          // Browser does not have local storage.
     870          return "LOCALSTORAGE_NOT_SUPPORTED";
     871        }
     872      } catch(e) {
     873          return "LOCALSTORAGE_DISABLED";
    846874      }
    847875    }
     
    849877    function checkPostMessage() {
    850878      if(!win.postMessage) {
    851         return "POSTMESSAGE";
     879        return "POSTMESSAGE_NOT_SUPPORTED";
    852880      }
    853881    }
     
    855883    function checkJSON() {
    856884      if(!(window.JSON && window.JSON.stringify && window.JSON.parse)) {
    857         return "JSON";
     885        return "JSON_NOT_SUPPORTED";
    858886      }
    859887    }
    860888
    861889    function isSupported() {
    862       reason = checkLocalStorage() || checkPostMessage() || checkJSON() || explicitNosupport();
     890      reason = explicitNosupport() || checkLocalStorage() || checkPostMessage() || checkJSON();
    863891
    864892      return !reason;
    865893    }
     894
    866895
    867896    function getNoSupportReason() {
     
    891920  }());
    892921
    893 
    894   // this is for calls that are non-interactive
    895   function _open_hidden_iframe(doc) {
    896     var iframe = doc.createElement("iframe");
    897     iframe.style.display = "none";
    898     doc.body.appendChild(iframe);
    899     iframe.src = ipServer + "/communication_iframe";
    900     return iframe;
    901   }
    902 
    903   /**
    904    * The meat and potatoes of the verified email protocol
    905    */
    906 
    907 
    908922  if (!navigator.id) {
    909923    navigator.id = {};
    910924  }
    911925
    912   if (!navigator.id.getVerifiedEmail || navigator.id._getVerifiedEmailIsShimmed) {
     926  if (!navigator.id.request || navigator.id._shimmed) {
    913927    var ipServer = "https://browserid.org";
    914     var isFennec = navigator.userAgent.indexOf('Fennec/') != -1;
     928    var userAgent = navigator.userAgent;
     929    // We must check for both XUL and Java versions of Fennec.  Both have
     930    // distinct UA strings.
     931    var isFennec = (userAgent.indexOf('Fennec/') != -1) ||  // XUL
     932                     (userAgent.indexOf('Firefox/') != -1 && userAgent.indexOf('Android') != -1);   // Java
     933
    915934    var windowOpenOpts =
    916935      (isFennec ? undefined :
    917        "menubar=0,location=1,resizable=0,scrollbars=0,status=0,dialog=1,width=700,height=375");
     936       "menubar=0,location=1,resizable=1,scrollbars=1,status=0,dialog=1,width=700,height=375");
    918937
    919938    var w;
    920939
    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);
     940    // table of registered observers
     941    var observers = {
     942      login: null,
     943      logout: null,
     944      ready: null
     945    };
     946
     947    var compatMode = undefined;
     948    function checkCompat(requiredMode) {
     949      if (requiredMode === true) {
     950        // this deprecation warning should be re-enabled when the .watch and .request APIs become final.
     951        // try { console.log("this site uses deprecated APIs (see documentation for navigator.id.request())"); } catch(e) { }
     952      }
     953
     954      if (compatMode === undefined) compatMode = requiredMode;
     955      else if (compatMode != requiredMode) {
     956        throw "you cannot combine the navigator.id.watch() API with navigator.id.getVerifiedEmail() or navigator.id.get()" +
     957              "this site should instead use navigator.id.request() and navigator.id.watch()";
     958      }
     959    }
     960
     961    var commChan,
     962        browserSupported = BrowserSupport.isSupported();
     963
     964    // this is for calls that are non-interactive
     965    function _open_hidden_iframe() {
     966      // If this is an unsupported browser, do not even attempt to add the
     967      // IFRAME as doing so will cause an exception to be thrown in IE6 and IE7
     968      // from within the communication_iframe.
     969      if(!browserSupported) return;
     970
     971      try {
     972        if (!commChan) {
     973          var doc = window.document;
     974          var iframe = doc.createElement("iframe");
     975          iframe.style.display = "none";
     976          doc.body.appendChild(iframe);
     977          iframe.src = ipServer + "/communication_iframe";
     978          commChan = Channel.build({
     979            window: iframe.contentWindow,
     980            origin: ipServer,
     981            scope: "mozid_ni",
     982            onReady: function() {
     983              // once the channel is set up, we'll fire a loaded message.  this is the
     984              // cutoff point where we'll say if 'setLoggedInUser' was not called before
     985              // this point, then it wont be called (XXX: optimize and improve me)
     986              commChan.call({
     987                method: 'loaded',
     988                success: function(){
     989                  if (observers.ready) observers.ready();
     990                }, error: function() {
     991                }
     992              });
     993            }
     994          });
     995
     996          commChan.bind('logout', function(trans, params) {
     997            if (observers.logout) observers.logout();
     998          });
     999
     1000          commChan.bind('login', function(trans, params) {
     1001            if (observers.login) observers.login(params);
     1002          });
     1003        }
     1004      } catch(e) {
     1005        // channel building failed!  let's ignore the error and allow higher
     1006        // level code to handle user messaging.
     1007        commChan = undefined;
     1008      }
     1009    }
     1010
     1011    function internalWatch(options) {
     1012      if (typeof options !== 'object') return;
     1013
     1014      if (options.onlogin && typeof options.onlogin !== 'function' ||
     1015          options.onlogout && typeof options.onlogout !== 'function' ||
     1016          options.onready && typeof options.onready !== 'function')
     1017      {
     1018        throw "non-function where function expected in parameters to navigator.id.watch()";
     1019      }
     1020
     1021      if (!options.onlogin) throw "'onlogin' is a required argument to navigator.id.watch()";
     1022      if (!options.onlogout) throw "'onlogout' is a required argument to navigator.id.watch()";
     1023
     1024      observers.login = options.onlogin || null;
     1025      observers.logout = options.onlogout || null;
     1026      observers.ready = options.onready || null;
     1027
     1028      _open_hidden_iframe();
     1029
     1030      // check that the commChan was properly initialized before interacting with it.
     1031      // on unsupported browsers commChan might still be undefined, in which case
     1032      // we let the dialog display the "unsupported browser" message upon spawning.
     1033      if (typeof options.loggedInEmail !== 'undefined' && commChan) {
     1034        commChan.notify({
     1035          method: 'loggedInUser',
     1036          params: options.loggedInEmail
    9311037        });
    932       } else {
    933         // focus an existing window
    934         if (w) {
     1038      }
     1039    }
     1040
     1041    function internalRequest(options) {
     1042      // focus an existing window
     1043      if (w) {
     1044        try {
     1045          w.focus();
     1046        }
     1047        catch(e) {
     1048          /* IE7 blows up here, do nothing */
     1049        }
     1050        return;
     1051      }
     1052
     1053      if (!BrowserSupport.isSupported()) {
     1054        var reason = BrowserSupport.getNoSupportReason(),
     1055        url = "unsupported_dialog";
     1056
     1057        if(reason === "LOCALSTORAGE_DISABLED") {
     1058          url = "cookies_disabled";
     1059        }
     1060
     1061        w = window.open(
     1062          ipServer + "/" + url,
     1063          null,
     1064          windowOpenOpts);
     1065        return;
     1066      }
     1067
     1068      // notify the iframe that the dialog is running so we
     1069      // don't do duplicative work
     1070      if (commChan) commChan.notify({ method: 'dialog_running' });
     1071
     1072      w = WinChan.open({
     1073        url: ipServer + '/sign_in',
     1074        relay_url: ipServer + '/relay',
     1075        window_features: windowOpenOpts,
     1076        params: {
     1077          method: "get",
     1078          params: options
     1079        }
     1080      }, function(err, r) {
     1081        // unpause the iframe to detect future changes in login state
     1082        if (commChan) {
     1083          // update the loggedInUser in the case that an assertion was generated, as
     1084          // this will prevent the comm iframe from thinking that state has changed
     1085          // and generating a new assertion.  IF, however, this request is not a success,
     1086          // then we do not change the loggedInUser - and we will let the comm frame determine
     1087          // if generating a logout event is the right thing to do
     1088          if (!err && r && r.email) {
     1089            commChan.notify({ method: 'loggedInUser', params: r.email });
     1090          }
     1091          commChan.notify({ method: 'dialog_complete' });
     1092        }
     1093
     1094        // clear the window handle
     1095        w = undefined;
     1096        if (!err && r && r.assertion) {
    9351097          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);
     1098            if (observers.login) observers.login(r.assertion);
     1099          } catch(e) {
     1100            // client's observer threw an exception
     1101          }
     1102        }
     1103
     1104        // if either err indicates the user canceled the signin (expected) or a
     1105        // null response was sent (unexpected), invoke the .oncancel() handler.
     1106        if (err === 'client closed window' || !r) {
     1107          if (options && options.oncancel) options.oncancel();
     1108          delete options.oncancel;
     1109        }
    9811110      });
    9821111    };
    9831112
    984     var _noninteractiveCall = function(method, args, onsuccess, onerror) {
    985       var doc = window.document;
    986       var ni_iframe = _open_hidden_iframe(doc);
    987 
    988       var chan = Channel.build({window: ni_iframe.contentWindow, origin: ipServer, scope: "mozid_ni"});
    989 
    990       function cleanup() {
    991         chan.destroy();
    992         chan = undefined;
    993         doc.body.removeChild(ni_iframe);
    994       }
    995 
    996       chan.call({
    997         method: method,
    998         params: args,
    999         success: function(rv) {
    1000           if (onsuccess) {
    1001             onsuccess(rv);
    1002           }
    1003           cleanup();
    1004         },
    1005         error: function(code, msg) {
    1006           if (onerror) onerror(code, msg);
    1007           cleanup();
    1008         }
    1009       });
     1113    navigator.id = {
     1114      request: function(options) {
     1115        options = options || {};
     1116        checkCompat(false);
     1117        return internalRequest(options);
     1118      },
     1119      watch: function(options) {
     1120        checkCompat(false);
     1121        internalWatch(options);
     1122      },
     1123      // logout from the current website
     1124      // The callback parameter is DEPRECATED, instead you should use the
     1125      // the .onlogout observer of the .watch() api.
     1126      logout: function(callback) {
     1127        // allocate iframe if it is not allocated
     1128        _open_hidden_iframe();
     1129        // send logout message if the commChan exists
     1130        if (commChan) commChan.notify({ method: 'logout' });
     1131        if (typeof callback === 'function') setTimeout(callback, 0);
     1132      },
     1133      // get an assertion
     1134      get: function(callback, options) {
     1135        options = options || {};
     1136        checkCompat(true);
     1137        internalWatch({
     1138          onlogin: function(assertion) {
     1139            if (callback) {
     1140              callback(assertion);
     1141              callback = null
     1142            }
     1143          },
     1144          onlogout: function() {}
     1145        });
     1146        options.oncancel = function() {
     1147          if (callback) {
     1148            callback(null);
     1149            callback = null;
     1150          }
     1151          observers.login = observers.logout = observers.ready = null;
     1152        };
     1153        if (options && options.silent) {
     1154          if (callback) setTimeout(function() { callback(null); }, 0);
     1155        } else {
     1156          internalRequest(options);
     1157        }
     1158      },
     1159      // backwards compatibility with old API
     1160      getVerifiedEmail: function(callback) {
     1161        checkCompat(true);
     1162        navigator.id.get(callback);
     1163      },
     1164      // required for forwards compatibility with native implementations
     1165      _shimmed: true
    10101166    };
    1011 
    1012     navigator.id._getVerifiedEmailIsShimmed = true;
    10131167  }
    10141168}());
    1015 
Note: See TracChangeset for help on using the changeset viewer.