avm99963 | 04def3e | 2016-11-27 22:53:05 +0100 | [diff] [blame] | 1 | /*
|
| 2 | * Copyright 2008 Netflix, Inc.
|
| 3 | *
|
| 4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 | * you may not use this file except in compliance with the License.
|
| 6 | * You may obtain a copy of the License at
|
| 7 | *
|
| 8 | * http://www.apache.org/licenses/LICENSE-2.0
|
| 9 | *
|
| 10 | * Unless required by applicable law or agreed to in writing, software
|
| 11 | * distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 | * See the License for the specific language governing permissions and
|
| 14 | * limitations under the License.
|
| 15 | */
|
| 16 |
|
| 17 | /* Here's some JavaScript software for implementing OAuth.
|
| 18 |
|
| 19 | This isn't as useful as you might hope. OAuth is based around
|
| 20 | allowing tools and websites to talk to each other. However,
|
| 21 | JavaScript running in web browsers is hampered by security
|
| 22 | restrictions that prevent code running on one website from
|
| 23 | accessing data stored or served on another.
|
| 24 |
|
| 25 | Before you start hacking, make sure you understand the limitations
|
| 26 | posed by cross-domain XMLHttpRequest.
|
| 27 |
|
| 28 | On the bright side, some platforms use JavaScript as their
|
| 29 | language, but enable the programmer to access other web sites.
|
| 30 | Examples include Google Gadgets, and Microsoft Vista Sidebar.
|
| 31 | For those platforms, this library should come in handy.
|
| 32 | */
|
| 33 |
|
| 34 | // The HMAC-SHA1 signature method calls b64_hmac_sha1, defined by
|
| 35 | // http://pajhome.org.uk/crypt/md5/sha1.js
|
| 36 |
|
| 37 | /* An OAuth message is represented as an object like this:
|
| 38 | {method: "GET", action: "http://server.com/path", parameters: ...}
|
| 39 |
|
| 40 | The parameters may be either a map {name: value, name2: value2}
|
| 41 | or an Array of name-value pairs [[name, value], [name2, value2]].
|
| 42 | The latter representation is more powerful: it supports parameters
|
| 43 | in a specific sequence, or several parameters with the same name;
|
| 44 | for example [["a", 1], ["b", 2], ["a", 3]].
|
| 45 |
|
| 46 | Parameter names and values are NOT percent-encoded in an object.
|
| 47 | They must be encoded before transmission and decoded after reception.
|
| 48 | For example, this message object:
|
| 49 | {method: "GET", action: "http://server/path", parameters: {p: "x y"}}
|
| 50 | ... can be transmitted as an HTTP request that begins:
|
| 51 | GET /path?p=x%20y HTTP/1.0
|
| 52 | (This isn't a valid OAuth request, since it lacks a signature etc.)
|
| 53 | Note that the object "x y" is transmitted as x%20y. To encode
|
| 54 | parameters, you can call OAuth.addToURL, OAuth.formEncode or
|
| 55 | OAuth.getAuthorization.
|
| 56 |
|
| 57 | This message object model harmonizes with the browser object model for
|
| 58 | input elements of an form, whose value property isn't percent encoded.
|
| 59 | The browser encodes each value before transmitting it. For example,
|
| 60 | see consumer.setInputs in example/consumer.js.
|
| 61 | */
|
| 62 |
|
| 63 | /* This script needs to know what time it is. By default, it uses the local
|
| 64 | clock (new Date), which is apt to be inaccurate in browsers. To do
|
| 65 | better, you can load this script from a URL whose query string contains
|
| 66 | an oauth_timestamp parameter, whose value is a current Unix timestamp.
|
| 67 | For example, when generating the enclosing document using PHP:
|
| 68 |
|
| 69 | <script src="oauth.js?oauth_timestamp=<?=time()?>" ...
|
| 70 |
|
| 71 | Another option is to call OAuth.correctTimestamp with a Unix timestamp.
|
| 72 | */
|
| 73 |
|
| 74 | var OAuth; if (OAuth == null) OAuth = {};
|
| 75 |
|
| 76 | OAuth.setProperties = function setProperties(into, from) {
|
| 77 | if (into != null && from != null) {
|
| 78 | for (var key in from) {
|
| 79 | into[key] = from[key];
|
| 80 | }
|
| 81 | }
|
| 82 | return into;
|
| 83 | }
|
| 84 |
|
| 85 | OAuth.setProperties(OAuth, // utility functions
|
| 86 | {
|
| 87 | percentEncode: function percentEncode(s) {
|
| 88 | if (s == null) {
|
| 89 | return "";
|
| 90 | }
|
| 91 | if (s instanceof Array) {
|
| 92 | var e = "";
|
| 93 | for (var i = 0; i < s.length; ++s) {
|
| 94 | if (e != "") e += '&';
|
| 95 | e += OAuth.percentEncode(s[i]);
|
| 96 | }
|
| 97 | return e;
|
| 98 | }
|
| 99 | s = encodeURIComponent(s);
|
| 100 | // Now replace the values which encodeURIComponent doesn't do
|
| 101 | // encodeURIComponent ignores: - _ . ! ~ * ' ( )
|
| 102 | // OAuth dictates the only ones you can ignore are: - _ . ~
|
| 103 | // Source: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Functions:encodeURIComponent
|
| 104 | s = s.replace(/\!/g, "%21");
|
| 105 | s = s.replace(/\*/g, "%2A");
|
| 106 | s = s.replace(/\'/g, "%27");
|
| 107 | s = s.replace(/\(/g, "%28");
|
| 108 | s = s.replace(/\)/g, "%29");
|
| 109 | return s;
|
| 110 | }
|
| 111 | ,
|
| 112 | decodePercent: function decodePercent(s) {
|
| 113 | if (s != null) {
|
| 114 | // Handle application/x-www-form-urlencoded, which is defined by
|
| 115 | // http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
|
| 116 | s = s.replace(/\+/g, " ");
|
| 117 | }
|
| 118 | return decodeURIComponent(s);
|
| 119 | }
|
| 120 | ,
|
| 121 | /** Convert the given parameters to an Array of name-value pairs. */
|
| 122 | getParameterList: function getParameterList(parameters) {
|
| 123 | if (parameters == null) {
|
| 124 | return [];
|
| 125 | }
|
| 126 | if (typeof parameters != "object") {
|
| 127 | return OAuth.decodeForm(parameters + "");
|
| 128 | }
|
| 129 | if (parameters instanceof Array) {
|
| 130 | return parameters;
|
| 131 | }
|
| 132 | var list = [];
|
| 133 | for (var p in parameters) {
|
| 134 | list.push([p, parameters[p]]);
|
| 135 | }
|
| 136 | return list;
|
| 137 | }
|
| 138 | ,
|
| 139 | /** Convert the given parameters to a map from name to value. */
|
| 140 | getParameterMap: function getParameterMap(parameters) {
|
| 141 | if (parameters == null) {
|
| 142 | return {};
|
| 143 | }
|
| 144 | if (typeof parameters != "object") {
|
| 145 | return OAuth.getParameterMap(OAuth.decodeForm(parameters + ""));
|
| 146 | }
|
| 147 | if (parameters instanceof Array) {
|
| 148 | var map = {};
|
| 149 | for (var p = 0; p < parameters.length; ++p) {
|
| 150 | var key = parameters[p][0];
|
| 151 | if (map[key] === undefined) { // first value wins
|
| 152 | map[key] = parameters[p][1];
|
| 153 | }
|
| 154 | }
|
| 155 | return map;
|
| 156 | }
|
| 157 | return parameters;
|
| 158 | }
|
| 159 | ,
|
| 160 | getParameter: function getParameter(parameters, name) {
|
| 161 | if (parameters instanceof Array) {
|
| 162 | for (var p = 0; p < parameters.length; ++p) {
|
| 163 | if (parameters[p][0] == name) {
|
| 164 | return parameters[p][1]; // first value wins
|
| 165 | }
|
| 166 | }
|
| 167 | } else {
|
| 168 | return OAuth.getParameterMap(parameters)[name];
|
| 169 | }
|
| 170 | return null;
|
| 171 | }
|
| 172 | ,
|
| 173 | formEncode: function formEncode(parameters) {
|
| 174 | var form = "";
|
| 175 | var list = OAuth.getParameterList(parameters);
|
| 176 | for (var p = 0; p < list.length; ++p) {
|
| 177 | var value = list[p][1];
|
| 178 | if (value == null) value = "";
|
| 179 | if (form != "") form += '&';
|
| 180 | form += OAuth.percentEncode(list[p][0])
|
| 181 | +'='+ OAuth.percentEncode(value);
|
| 182 | }
|
| 183 | return form;
|
| 184 | }
|
| 185 | ,
|
| 186 | decodeForm: function decodeForm(form) {
|
| 187 | var list = [];
|
| 188 | var nvps = form.split('&');
|
| 189 | for (var n = 0; n < nvps.length; ++n) {
|
| 190 | var nvp = nvps[n];
|
| 191 | if (nvp == "") {
|
| 192 | continue;
|
| 193 | }
|
| 194 | var equals = nvp.indexOf('=');
|
| 195 | var name;
|
| 196 | var value;
|
| 197 | if (equals < 0) {
|
| 198 | name = OAuth.decodePercent(nvp);
|
| 199 | value = null;
|
| 200 | } else {
|
| 201 | name = OAuth.decodePercent(nvp.substring(0, equals));
|
| 202 | value = OAuth.decodePercent(nvp.substring(equals + 1));
|
| 203 | }
|
| 204 | list.push([name, value]);
|
| 205 | }
|
| 206 | return list;
|
| 207 | }
|
| 208 | ,
|
| 209 | setParameter: function setParameter(message, name, value) {
|
| 210 | var parameters = message.parameters;
|
| 211 | if (parameters instanceof Array) {
|
| 212 | for (var p = 0; p < parameters.length; ++p) {
|
| 213 | if (parameters[p][0] == name) {
|
| 214 | if (value === undefined) {
|
| 215 | parameters.splice(p, 1);
|
| 216 | } else {
|
| 217 | parameters[p][1] = value;
|
| 218 | value = undefined;
|
| 219 | }
|
| 220 | }
|
| 221 | }
|
| 222 | if (value !== undefined) {
|
| 223 | parameters.push([name, value]);
|
| 224 | }
|
| 225 | } else {
|
| 226 | parameters = OAuth.getParameterMap(parameters);
|
| 227 | parameters[name] = value;
|
| 228 | message.parameters = parameters;
|
| 229 | }
|
| 230 | }
|
| 231 | ,
|
| 232 | setParameters: function setParameters(message, parameters) {
|
| 233 | var list = OAuth.getParameterList(parameters);
|
| 234 | for (var i = 0; i < list.length; ++i) {
|
| 235 | OAuth.setParameter(message, list[i][0], list[i][1]);
|
| 236 | }
|
| 237 | }
|
| 238 | ,
|
| 239 | /** Fill in parameters to help construct a request message.
|
| 240 | This function doesn't fill in every parameter.
|
| 241 | The accessor object should be like:
|
| 242 | {consumerKey:'foo', consumerSecret:'bar', accessorSecret:'nurn', token:'krelm', tokenSecret:'blah'}
|
| 243 | The accessorSecret property is optional.
|
| 244 | */
|
| 245 | completeRequest: function completeRequest(message, accessor) {
|
| 246 | if (message.method == null) {
|
| 247 | message.method = "GET";
|
| 248 | }
|
| 249 | var map = OAuth.getParameterMap(message.parameters);
|
| 250 | if (map.oauth_consumer_key == null) {
|
| 251 | OAuth.setParameter(message, "oauth_consumer_key", accessor.consumerKey || "");
|
| 252 | }
|
| 253 | if (map.oauth_token == null && accessor.token != null) {
|
| 254 | OAuth.setParameter(message, "oauth_token", accessor.token);
|
| 255 | }
|
| 256 | if (map.oauth_version == null) {
|
| 257 | OAuth.setParameter(message, "oauth_version", "1.0");
|
| 258 | }
|
| 259 | if (map.oauth_timestamp == null) {
|
| 260 | OAuth.setParameter(message, "oauth_timestamp", OAuth.timestamp());
|
| 261 | }
|
| 262 | if (map.oauth_nonce == null) {
|
| 263 | OAuth.setParameter(message, "oauth_nonce", OAuth.nonce(6));
|
| 264 | }
|
| 265 | OAuth.SignatureMethod.sign(message, accessor);
|
| 266 | }
|
| 267 | ,
|
| 268 | setTimestampAndNonce: function setTimestampAndNonce(message) {
|
| 269 | OAuth.setParameter(message, "oauth_timestamp", OAuth.timestamp());
|
| 270 | OAuth.setParameter(message, "oauth_nonce", OAuth.nonce(6));
|
| 271 | }
|
| 272 | ,
|
| 273 | addToURL: function addToURL(url, parameters) {
|
| 274 | newURL = url;
|
| 275 | if (parameters != null) {
|
| 276 | var toAdd = OAuth.formEncode(parameters);
|
| 277 | if (toAdd.length > 0) {
|
| 278 | var q = url.indexOf('?');
|
| 279 | if (q < 0) newURL += '?';
|
| 280 | else newURL += '&';
|
| 281 | newURL += toAdd;
|
| 282 | }
|
| 283 | }
|
| 284 | return newURL;
|
| 285 | }
|
| 286 | ,
|
| 287 | /** Construct the value of the Authorization header for an HTTP request. */
|
| 288 | getAuthorizationHeader: function getAuthorizationHeader(realm, parameters) {
|
| 289 | var header = 'OAuth realm="' + OAuth.percentEncode(realm) + '"';
|
| 290 | var list = OAuth.getParameterList(parameters);
|
| 291 | for (var p = 0; p < list.length; ++p) {
|
| 292 | var parameter = list[p];
|
| 293 | var name = parameter[0];
|
| 294 | if (name.indexOf("oauth_") == 0) {
|
| 295 | header += ',' + OAuth.percentEncode(name) + '="' + OAuth.percentEncode(parameter[1]) + '"';
|
| 296 | }
|
| 297 | }
|
| 298 | return header;
|
| 299 | }
|
| 300 | ,
|
| 301 | /** Correct the time using a parameter from the URL from which the last script was loaded. */
|
| 302 | correctTimestampFromSrc: function correctTimestampFromSrc(parameterName) {
|
| 303 | parameterName = parameterName || "oauth_timestamp";
|
| 304 | var scripts = document.getElementsByTagName('script');
|
| 305 | if (scripts == null || !scripts.length) return;
|
| 306 | var src = scripts[scripts.length-1].src;
|
| 307 | if (!src) return;
|
| 308 | var q = src.indexOf("?");
|
| 309 | if (q < 0) return;
|
| 310 | parameters = OAuth.getParameterMap(OAuth.decodeForm(src.substring(q+1)));
|
| 311 | var t = parameters[parameterName];
|
| 312 | if (t == null) return;
|
| 313 | OAuth.correctTimestamp(t);
|
| 314 | }
|
| 315 | ,
|
| 316 | /** Generate timestamps starting with the given value. */
|
| 317 | correctTimestamp: function correctTimestamp(timestamp) {
|
| 318 | OAuth.timeCorrectionMsec = (timestamp * 1000) - (new Date()).getTime();
|
| 319 | }
|
| 320 | ,
|
| 321 | /** The difference between the correct time and my clock. */
|
| 322 | timeCorrectionMsec: 0
|
| 323 | ,
|
| 324 | timestamp: function timestamp() {
|
| 325 | var t = (new Date()).getTime() + OAuth.timeCorrectionMsec;
|
| 326 | return Math.floor(t / 1000);
|
| 327 | }
|
| 328 | ,
|
| 329 | nonce: function nonce(length) {
|
| 330 | var chars = OAuth.nonce.CHARS;
|
| 331 | var result = "";
|
| 332 | for (var i = 0; i < length; ++i) {
|
| 333 | var rnum = Math.floor(Math.random() * chars.length);
|
| 334 | result += chars.substring(rnum, rnum+1);
|
| 335 | }
|
| 336 | return result;
|
| 337 | }
|
| 338 | });
|
| 339 |
|
| 340 | OAuth.nonce.CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
|
| 341 |
|
| 342 | /** Define a constructor function,
|
| 343 | without causing trouble to anyone who was using it as a namespace.
|
| 344 | That is, if parent[name] already existed and had properties,
|
| 345 | copy those properties into the new constructor.
|
| 346 | */
|
| 347 | OAuth.declareClass = function declareClass(parent, name, newConstructor) {
|
| 348 | var previous = parent[name];
|
| 349 | parent[name] = newConstructor;
|
| 350 | if (newConstructor != null && previous != null) {
|
| 351 | for (var key in previous) {
|
| 352 | if (key != "prototype") {
|
| 353 | newConstructor[key] = previous[key];
|
| 354 | }
|
| 355 | }
|
| 356 | }
|
| 357 | return newConstructor;
|
| 358 | }
|
| 359 |
|
| 360 | /** An abstract algorithm for signing messages. */
|
| 361 | OAuth.declareClass(OAuth, "SignatureMethod", function OAuthSignatureMethod(){});
|
| 362 |
|
| 363 | OAuth.setProperties(OAuth.SignatureMethod.prototype, // instance members
|
| 364 | {
|
| 365 | /** Add a signature to the message. */
|
| 366 | sign: function sign(message) {
|
| 367 | var baseString = OAuth.SignatureMethod.getBaseString(message);
|
| 368 | var signature = this.getSignature(baseString);
|
| 369 | OAuth.setParameter(message, "oauth_signature", signature);
|
| 370 | return signature; // just in case someone's interested
|
| 371 | }
|
| 372 | ,
|
| 373 | /** Set the key string for signing. */
|
| 374 | initialize: function initialize(name, accessor) {
|
| 375 | var consumerSecret;
|
| 376 | if (accessor.accessorSecret != null
|
| 377 | && name.length > 9
|
| 378 | && name.substring(name.length-9) == "-Accessor")
|
| 379 | {
|
| 380 | consumerSecret = accessor.accessorSecret;
|
| 381 | } else {
|
| 382 | consumerSecret = accessor.consumerSecret;
|
| 383 | }
|
| 384 | this.key = OAuth.percentEncode(consumerSecret)
|
| 385 | +"&"+ OAuth.percentEncode(accessor.tokenSecret);
|
| 386 | }
|
| 387 | });
|
| 388 |
|
| 389 | /* SignatureMethod expects an accessor object to be like this:
|
| 390 | {tokenSecret: "lakjsdflkj...", consumerSecret: "QOUEWRI..", accessorSecret: "xcmvzc..."}
|
| 391 | The accessorSecret property is optional.
|
| 392 | */
|
| 393 | // Class members:
|
| 394 | OAuth.setProperties(OAuth.SignatureMethod, // class members
|
| 395 | {
|
| 396 | sign: function sign(message, accessor) {
|
| 397 | var name = OAuth.getParameterMap(message.parameters).oauth_signature_method;
|
| 398 | if (name == null || name == "") {
|
| 399 | name = "HMAC-SHA1";
|
| 400 | OAuth.setParameter(message, "oauth_signature_method", name);
|
| 401 | }
|
| 402 | OAuth.SignatureMethod.newMethod(name, accessor).sign(message);
|
| 403 | }
|
| 404 | ,
|
| 405 | /** Instantiate a SignatureMethod for the given method name. */
|
| 406 | newMethod: function newMethod(name, accessor) {
|
| 407 | var impl = OAuth.SignatureMethod.REGISTERED[name];
|
| 408 | if (impl != null) {
|
| 409 | var method = new impl();
|
| 410 | method.initialize(name, accessor);
|
| 411 | return method;
|
| 412 | }
|
| 413 | var err = new Error("signature_method_rejected");
|
| 414 | var acceptable = "";
|
| 415 | for (var r in OAuth.SignatureMethod.REGISTERED) {
|
| 416 | if (acceptable != "") acceptable += '&';
|
| 417 | acceptable += OAuth.percentEncode(r);
|
| 418 | }
|
| 419 | err.oauth_acceptable_signature_methods = acceptable;
|
| 420 | throw err;
|
| 421 | }
|
| 422 | ,
|
| 423 | /** A map from signature method name to constructor. */
|
| 424 | REGISTERED : {}
|
| 425 | ,
|
| 426 | /** Subsequently, the given constructor will be used for the named methods.
|
| 427 | The constructor will be called with no parameters.
|
| 428 | The resulting object should usually implement getSignature(baseString).
|
| 429 | You can easily define such a constructor by calling makeSubclass, below.
|
| 430 | */
|
| 431 | registerMethodClass: function registerMethodClass(names, classConstructor) {
|
| 432 | for (var n = 0; n < names.length; ++n) {
|
| 433 | OAuth.SignatureMethod.REGISTERED[names[n]] = classConstructor;
|
| 434 | }
|
| 435 | }
|
| 436 | ,
|
| 437 | /** Create a subclass of OAuth.SignatureMethod, with the given getSignature function. */
|
| 438 | makeSubclass: function makeSubclass(getSignatureFunction) {
|
| 439 | var superClass = OAuth.SignatureMethod;
|
| 440 | var subClass = function() {
|
| 441 | superClass.call(this);
|
| 442 | };
|
| 443 | subClass.prototype = new superClass();
|
| 444 | // Delete instance variables from prototype:
|
| 445 | // delete subclass.prototype... There aren't any.
|
| 446 | subClass.prototype.getSignature = getSignatureFunction;
|
| 447 | subClass.prototype.constructor = subClass;
|
| 448 | return subClass;
|
| 449 | }
|
| 450 | ,
|
| 451 | getBaseString: function getBaseString(message) {
|
| 452 | var URL = message.action;
|
| 453 | var q = URL.indexOf('?');
|
| 454 | var parameters;
|
| 455 | if (q < 0) {
|
| 456 | parameters = message.parameters;
|
| 457 | } else {
|
| 458 | // Combine the URL query string with the other parameters:
|
| 459 | parameters = OAuth.decodeForm(URL.substring(q + 1));
|
| 460 | var toAdd = OAuth.getParameterList(message.parameters);
|
| 461 | for (var a = 0; a < toAdd.length; ++a) {
|
| 462 | parameters.push(toAdd[a]);
|
| 463 | }
|
| 464 | }
|
| 465 | return OAuth.percentEncode(message.method.toUpperCase())
|
| 466 | +'&'+ OAuth.percentEncode(OAuth.SignatureMethod.normalizeUrl(URL))
|
| 467 | +'&'+ OAuth.percentEncode(OAuth.SignatureMethod.normalizeParameters(parameters));
|
| 468 | }
|
| 469 | ,
|
| 470 | normalizeUrl: function normalizeUrl(url) {
|
| 471 | var uri = OAuth.SignatureMethod.parseUri(url);
|
| 472 | var scheme = uri.protocol.toLowerCase();
|
| 473 | var authority = uri.authority.toLowerCase();
|
| 474 | var dropPort = (scheme == "http" && uri.port == 80)
|
| 475 | || (scheme == "https" && uri.port == 443);
|
| 476 | if (dropPort) {
|
| 477 | // find the last : in the authority
|
| 478 | var index = authority.lastIndexOf(":");
|
| 479 | if (index >= 0) {
|
| 480 | authority = authority.substring(0, index);
|
| 481 | }
|
| 482 | }
|
| 483 | var path = uri.path;
|
| 484 | if (!path) {
|
| 485 | path = "/"; // conforms to RFC 2616 section 3.2.2
|
| 486 | }
|
| 487 | // we know that there is no query and no fragment here.
|
| 488 | return scheme + "://" + authority + path;
|
| 489 | }
|
| 490 | ,
|
| 491 | parseUri: function parseUri (str) {
|
| 492 | /* This function was adapted from parseUri 1.2.1
|
| 493 | http://stevenlevithan.com/demo/parseuri/js/assets/parseuri.js
|
| 494 | */
|
| 495 | var o = {key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
|
| 496 | parser: {strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/ }};
|
| 497 | var m = o.parser.strict.exec(str);
|
| 498 | var uri = {};
|
| 499 | var i = 14;
|
| 500 | while (i--) uri[o.key[i]] = m[i] || "";
|
| 501 | return uri;
|
| 502 | }
|
| 503 | ,
|
| 504 | normalizeParameters: function normalizeParameters(parameters) {
|
| 505 | if (parameters == null) {
|
| 506 | return "";
|
| 507 | }
|
| 508 | var list = OAuth.getParameterList(parameters);
|
| 509 | var sortable = [];
|
| 510 | for (var p = 0; p < list.length; ++p) {
|
| 511 | var nvp = list[p];
|
| 512 | if (nvp[0] != "oauth_signature") {
|
| 513 | sortable.push([ OAuth.percentEncode(nvp[0])
|
| 514 | + " " // because it comes before any character that can appear in a percentEncoded string.
|
| 515 | + OAuth.percentEncode(nvp[1])
|
| 516 | , nvp]);
|
| 517 | }
|
| 518 | }
|
| 519 | sortable.sort(function(a,b) {
|
| 520 | if (a[0] < b[0]) return -1;
|
| 521 | if (a[0] > b[0]) return 1;
|
| 522 | return 0;
|
| 523 | });
|
| 524 | var sorted = [];
|
| 525 | for (var s = 0; s < sortable.length; ++s) {
|
| 526 | sorted.push(sortable[s][1]);
|
| 527 | }
|
| 528 | return OAuth.formEncode(sorted);
|
| 529 | }
|
| 530 | });
|
| 531 |
|
| 532 | OAuth.SignatureMethod.registerMethodClass(["PLAINTEXT", "PLAINTEXT-Accessor"],
|
| 533 | OAuth.SignatureMethod.makeSubclass(
|
| 534 | function getSignature(baseString) {
|
| 535 | return this.key;
|
| 536 | }
|
| 537 | ));
|
| 538 |
|
| 539 | OAuth.SignatureMethod.registerMethodClass(["HMAC-SHA1", "HMAC-SHA1-Accessor"],
|
| 540 | OAuth.SignatureMethod.makeSubclass(
|
| 541 | function getSignature(baseString) {
|
| 542 | b64pad = '=';
|
| 543 | var signature = b64_hmac_sha1(this.key, baseString);
|
| 544 | return signature;
|
| 545 | }
|
| 546 | ));
|
| 547 |
|
| 548 | try {
|
| 549 | OAuth.correctTimestampFromSrc();
|
| 550 | } catch(e) {
|
| 551 | }
|