Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(47)

Side by Side Diff: remoting/webapp/me2mom/chrome_ex_oauthsimple.js

Issue 7016001: Simple OAuth1 implementation based on http://code.google.com/chrome/extensions/tut_oauth.html. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « remoting/webapp/me2mom/chrome_ex_oauth.js ('k') | remoting/webapp/me2mom/manifest.json » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /* OAuthSimple
2 * A simpler version of OAuth
3 *
4 * author: jr conlin
5 * mail: src@anticipatr.com
6 * copyright: unitedHeroes.net
7 * version: 1.0
8 * url: http://unitedHeroes.net/OAuthSimple
9 *
10 * Copyright (c) 2009, unitedHeroes.net
11 * All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are met:
15 * * Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * * Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * * Neither the name of the unitedHeroes.net nor the
21 * names of its contributors may be used to endorse or promote products
22 * derived from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY UNITEDHEROES.NET ''AS IS'' AND ANY
25 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL UNITEDHEROES.NET BE LIABLE FOR ANY
28 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THI S
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35 var OAuthSimple;
36
37 if (OAuthSimple === undefined)
38 {
39 /* Simple OAuth
40 *
41 * This class only builds the OAuth elements, it does not do the actual
42 * transmission or reception of the tokens. It does not validate elements
43 * of the token. It is for client use only.
44 *
45 * api_key is the API key, also known as the OAuth consumer key
46 * shared_secret is the shared secret (duh).
47 *
48 * Both the api_key and shared_secret are generally provided by the site
49 * offering OAuth services. You need to specify them at object creation
50 * because nobody <explative>ing uses OAuth without that minimal set of
51 * signatures.
52 *
53 * If you want to use the higher order security that comes from the
54 * OAuth token (sorry, I don't provide the functions to fetch that because
55 * sites aren't horribly consistent about how they offer that), you need to
56 * pass those in either with .setTokensAndSecrets() or as an argument to the
57 * .sign() or .getHeaderString() functions.
58 *
59 * Example:
60 <code>
61 var oauthObject = OAuthSimple().sign({path:'http://example.com/rest/',
62 parameters: 'foo=bar&gorp=banana',
63 signatures:{
64 api_key:'12345abcd',
65 shared_secret:'xyz-5309'
66 }});
67 document.getElementById('someLink').href=oauthObject.signed_url;
68 </code>
69 *
70 * that will sign as a "GET" using "SHA1-MAC" the url. If you need more than
71 * that, read on, McDuff.
72 */
73
74 /** OAuthSimple creator
75 *
76 * Create an instance of OAuthSimple
77 *
78 * @param api_key {string} The API Key (sometimes referred to as the c onsumer key) This value is usually supplied by the site you wish to use.
79 * @param shared_secret (string) The shared secret. This value is also usual ly provided by the site you wish to use.
80 */
81 OAuthSimple = function (consumer_key,shared_secret)
82 {
83 /* if (api_key == undefined)
84 throw("Missing argument: api_key (oauth_consumer_key) for OAuthSimpl e. This is usually provided by the hosting site.");
85 if (shared_secret == undefined)
86 throw("Missing argument: shared_secret (shared secret) for OAuthSimp le. This is usually provided by the hosting site.");
87 */ this._secrets={};
88 this._parameters={};
89
90 // General configuration options.
91 if (consumer_key !== undefined) {
92 this._secrets['consumer_key'] = consumer_key;
93 }
94 if (shared_secret !== undefined) {
95 this._secrets['shared_secret'] = shared_secret;
96 }
97 this._default_signature_method= "HMAC-SHA1";
98 this._action = "GET";
99 this._nonce_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmno pqrstuvwxyz";
100
101
102 this.reset = function() {
103 this._parameters={};
104 this._path=undefined;
105 return this;
106 };
107
108 /** set the parameters either from a hash or a string
109 *
110 * @param {string,object} List of parameters for the call, this can eith er be a URI string (e.g. "foo=bar&gorp=banana" or an object/hash)
111 */
112 this.setParameters = function (parameters) {
113 if (parameters === undefined) {
114 parameters = {};
115 }
116 if (typeof(parameters) == 'string') {
117 parameters=this._parseParameterString(parameters);
118 }
119 this._parameters = parameters;
120 if (this._parameters['oauth_nonce'] === undefined) {
121 this._getNonce();
122 }
123 if (this._parameters['oauth_timestamp'] === undefined) {
124 this._getTimestamp();
125 }
126 if (this._parameters['oauth_method'] === undefined) {
127 this.setSignatureMethod();
128 }
129 if (this._parameters['oauth_consumer_key'] === undefined) {
130 this._getApiKey();
131 }
132 if(this._parameters['oauth_token'] === undefined) {
133 this._getAccessToken();
134 }
135
136 return this;
137 };
138
139 /** convienence method for setParameters
140 *
141 * @param parameters {string,object} See .setParameters
142 */
143 this.setQueryString = function (parameters) {
144 return this.setParameters(parameters);
145 };
146
147 /** Set the target URL (does not include the parameters)
148 *
149 * @param path {string} the fully qualified URI (excluding query argumen ts) (e.g "http://example.org/foo")
150 */
151 this.setURL = function (path) {
152 if (path == '') {
153 throw ('No path specified for OAuthSimple.setURL');
154 }
155 this._path = path;
156 return this;
157 };
158
159 /** convienence method for setURL
160 *
161 * @param path {string} see .setURL
162 */
163 this.setPath = function(path){
164 return this.setURL(path);
165 };
166
167 /** set the "action" for the url, (e.g. GET,POST, DELETE, etc.)
168 *
169 * @param action {string} HTTP Action word.
170 */
171 this.setAction = function(action) {
172 if (action === undefined) {
173 action="GET";
174 }
175 action = action.toUpperCase();
176 if (action.match('[^A-Z]')) {
177 throw ('Invalid action specified for OAuthSimple.setAction');
178 }
179 this._action = action;
180 return this;
181 };
182
183 /** set the signatures (as well as validate the ones you have)
184 *
185 * @param signatures {object} object/hash of the token/signature pairs { api_key:, shared_secret:, oauth_token: oauth_secret:}
186 */
187 this.setTokensAndSecrets = function(signatures) {
188 if (signatures)
189 {
190 for (var i in signatures) {
191 this._secrets[i] = signatures[i];
192 }
193 }
194 // Aliases
195 if (this._secrets['api_key']) {
196 this._secrets.consumer_key = this._secrets.api_key;
197 }
198 if (this._secrets['access_token']) {
199 this._secrets.oauth_token = this._secrets.access_token;
200 }
201 if (this._secrets['access_secret']) {
202 this._secrets.oauth_secret = this._secrets.access_secret;
203 }
204 // Gauntlet
205 if (this._secrets.consumer_key === undefined) {
206 throw('Missing required consumer_key in OAuthSimple.setTokensAnd Secrets');
207 }
208 if (this._secrets.shared_secret === undefined) {
209 throw('Missing required shared_secret in OAuthSimple.setTokensAn dSecrets');
210 }
211 if ((this._secrets.oauth_token !== undefined) && (this._secrets.oaut h_secret === undefined)) {
212 throw('Missing oauth_secret for supplied oauth_token in OAuthSim ple.setTokensAndSecrets');
213 }
214 return this;
215 };
216
217 /** set the signature method (currently only Plaintext or SHA-MAC1)
218 *
219 * @param method {string} Method of signing the transaction (only PLAINT EXT and SHA-MAC1 allowed for now)
220 */
221 this.setSignatureMethod = function(method) {
222 if (method === undefined) {
223 method = this._default_signature_method;
224 }
225 //TODO: accept things other than PlainText or SHA-MAC1
226 if (method.toUpperCase().match(/(PLAINTEXT|HMAC-SHA1)/) === undefine d) {
227 throw ('Unknown signing method specified for OAuthSimple.setSign atureMethod');
228 }
229 this._parameters['oauth_signature_method']= method.toUpperCase();
230 return this;
231 };
232
233 /** sign the request
234 *
235 * note: all arguments are optional, provided you've set them using the
236 * other helper functions.
237 *
238 * @param args {object} hash of arguments for the call
239 * {action:, path:, parameters:, method:, signatures:}
240 * all arguments are optional.
241 */
242 this.sign = function (args) {
243 if (args === undefined) {
244 args = {};
245 }
246 // Set any given parameters
247 if(args['action'] !== undefined) {
248 this.setAction(args['action']);
249 }
250 if (args['path'] !== undefined) {
251 this.setPath(args['path']);
252 }
253 if (args['method'] !== undefined) {
254 this.setSignatureMethod(args['method']);
255 }
256 this.setTokensAndSecrets(args['signatures']);
257 if (args['parameters'] !== undefined){
258 this.setParameters(args['parameters']);
259 }
260 // check the parameters
261 var normParams = this._normalizedParameters();
262 this._parameters['oauth_signature']=this._generateSignature(normPara ms);
263 return {
264 parameters: this._parameters,
265 signature: this._oauthEscape(this._parameters['oauth_signature'] ),
266 signed_url: this._path + '?' + this._normalizedParameters(),
267 header: this.getHeaderString()
268 };
269 };
270
271 /** Return a formatted "header" string
272 *
273 * NOTE: This doesn't set the "Authorization: " prefix, which is require d.
274 * I don't set it because various set header functions prefer different
275 * ways to do that.
276 *
277 * @param args {object} see .sign
278 */
279 this.getHeaderString = function(args) {
280 if (this._parameters['oauth_signature'] === undefined) {
281 this.sign(args);
282 }
283
284 var result = 'OAuth ';
285 for (var pName in this._parameters)
286 {
287 if (!pName.match(/^oauth/)) {
288 continue;
289 }
290 if ((this._parameters[pName]) instanceof Array)
291 {
292 var pLength = this._parameters[pName].length;
293 for (var j=0;j<pLength;j++)
294 {
295 result += pName +'="'+this._oauthEscape(this._parameters [pName][j])+'" ';
296 }
297 }
298 else
299 {
300 result += pName + '="'+this._oauthEscape(this._parameters[pN ame])+'" ';
301 }
302 }
303 return result;
304 };
305
306 // Start Private Methods.
307
308 /** convert the parameter string into a hash of objects.
309 *
310 */
311 this._parseParameterString = function(paramString){
312 var elements = paramString.split('&');
313 var result={};
314 for(var element=elements.shift();element;element=elements.shift())
315 {
316 var keyToken=element.split('=');
317 var value='';
318 if (keyToken[1]) {
319 value=decodeURIComponent(keyToken[1]);
320 }
321 if(result[keyToken[0]]){
322 if (!(result[keyToken[0]] instanceof Array))
323 {
324 result[keyToken[0]] = Array(result[keyToken[0]],value);
325 }
326 else
327 {
328 result[keyToken[0]].push(value);
329 }
330 }
331 else
332 {
333 result[keyToken[0]]=value;
334 }
335 }
336 return result;
337 };
338
339 this._oauthEscape = function(string) {
340 if (string === undefined) {
341 return "";
342 }
343 if (string instanceof Array)
344 {
345 throw('Array passed to _oauthEscape');
346 }
347 return encodeURIComponent(string).replace(/\!/g, "%21").
348 replace(/\*/g, "%2A").
349 replace(/'/g, "%27").
350 replace(/\(/g, "%28").
351 replace(/\)/g, "%29");
352 };
353
354 this._getNonce = function (length) {
355 if (length === undefined) {
356 length=5;
357 }
358 var result = "";
359 var cLength = this._nonce_chars.length;
360 for (var i = 0; i < length;i++) {
361 var rnum = Math.floor(Math.random() *cLength);
362 result += this._nonce_chars.substring(rnum,rnum+1);
363 }
364 this._parameters['oauth_nonce']=result;
365 return result;
366 };
367
368 this._getApiKey = function() {
369 if (this._secrets.consumer_key === undefined) {
370 throw('No consumer_key set for OAuthSimple.');
371 }
372 this._parameters['oauth_consumer_key']=this._secrets.consumer_key;
373 return this._parameters.oauth_consumer_key;
374 };
375
376 this._getAccessToken = function() {
377 if (this._secrets['oauth_secret'] === undefined) {
378 return '';
379 }
380 if (this._secrets['oauth_token'] === undefined) {
381 throw('No oauth_token (access_token) set for OAuthSimple.');
382 }
383 this._parameters['oauth_token'] = this._secrets.oauth_token;
384 return this._parameters.oauth_token;
385 };
386
387 this._getTimestamp = function() {
388 var d = new Date();
389 var ts = Math.floor(d.getTime()/1000);
390 this._parameters['oauth_timestamp'] = ts;
391 return ts;
392 };
393
394 this.b64_hmac_sha1 = function(k,d,_p,_z){
395 // heavily optimized and compressed version of http://pajhome.org.uk/cry pt/md5/sha1.js
396 // _p = b64pad, _z = character size; not used here but I left them avail able just in case
397 if(!_p){_p='=';}if(!_z){_z=8;}function _f(t,b,c,d){if(t<20){return(b&c)| ((~b)&d);}if(t<40){return b^c^d;}if(t<60){return(b&c)|(b&d)|(c&d);}return b^c^d; }function _k(t){return(t<20)?1518500249:(t<40)?1859775393:(t<60)?-1894007588:-89 9497514;}function _s(x,y){var l=(x&0xFFFF)+(y&0xFFFF),m=(x>>16)+(y>>16)+(l>>16); return(m<<16)|(l&0xFFFF);}function _r(n,c){return(n<<c)|(n>>>(32-c));}function _ c(x,l){x[l>>5]|=0x80<<(24-l%32);x[((l+64>>9)<<4)+15]=l;var w=[80],a=1732584193,b =-271733879,c=-1732584194,d=271733878,e=-1009589776;for(var i=0;i<x.length;i+=16 ){var o=a,p=b,q=c,r=d,s=e;for(var j=0;j<80;j++){if(j<16){w[j]=x[i+j];}else{w[j]= _r(w[j-3]^w[j-8]^w[j-14]^w[j-16],1);}var t=_s(_s(_r(a,5),_f(j,b,c,d)),_s(_s(e,w[ j]),_k(j)));e=d;d=c;c=_r(b,30);b=a;a=t;}a=_s(a,o);b=_s(b,p);c=_s(c,q);d=_s(d,r); e=_s(e,s);}return[a,b,c,d,e];}function _b(s){var b=[],m=(1<<_z)-1;for(var i=0;i< s.length*_z;i+=_z){b[i>>5]|=(s.charCodeAt(i/8)&m)<<(32-_z-i%32);}return b;}funct ion _h(k,d){var b=_b(k);if(b.length>16){b=_c(b,k.length*_z);}var p=[16],o=[16];f or(var i=0;i<16;i++){p[i]=b[i]^0x36363636;o[i]=b[i]^0x5C5C5C5C;}var h=_c(p.conca t(_b(d)),512+d.length*_z);return _c(o.concat(h),512+160);}function _n(b){var t=" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",s='';for(var i =0;i<b.length*4;i+=3){var r=(((b[i>>2]>>8*(3-i%4))&0xFF)<<16)|(((b[i+1>>2]>>8*(3 -(i+1)%4))&0xFF)<<8)|((b[i+2>>2]>>8*(3-(i+2)%4))&0xFF);for(var j=0;j<4;j++){if(i *8+j*6>b.length*32){s+=_p;}else{s+=t.charAt((r>>6*(3-j))&0x3F);}}}return s;}func tion _x(k,d){return _n(_h(k,d));}return _x(k,d);
Jamie 2011/05/11 20:41:04 I think this line might be a tad over the 80-chara
398 }
399
400
401 this._normalizedParameters = function() {
402 var elements = new Array();
403 var paramNames = [];
404 var ra =0;
405 for (var paramName in this._parameters)
406 {
407 if (ra++ > 1000) {
408 throw('runaway 1');
409 }
410 paramNames.unshift(paramName);
411 }
412 paramNames = paramNames.sort();
413 pLen = paramNames.length;
414 for (var i=0;i<pLen; i++)
415 {
416 paramName=paramNames[i];
417 //skip secrets.
418 if (paramName.match(/\w+_secret/)) {
419 continue;
420 }
421 if (this._parameters[paramName] instanceof Array)
422 {
423 var sorted = this._parameters[paramName].sort();
424 var spLen = sorted.length;
425 for (var j = 0;j<spLen;j++){
426 if (ra++ > 1000) {
427 throw('runaway 1');
428 }
429 elements.push(this._oauthEscape(paramName) + '=' +
430 this._oauthEscape(sorted[j]));
431 }
432 continue;
433 }
434 elements.push(this._oauthEscape(paramName) + '=' +
435 this._oauthEscape(this._parameters[paramName]));
436 }
437 return elements.join('&');
438 };
439
440 this._generateSignature = function() {
441
442 var secretKey = this._oauthEscape(this._secrets.shared_secret)+'&'+
443 this._oauthEscape(this._secrets.oauth_secret);
444 if (this._parameters['oauth_signature_method'] == 'PLAINTEXT')
445 {
446 return secretKey;
447 }
448 if (this._parameters['oauth_signature_method'] == 'HMAC-SHA1')
449 {
450 var sigString = this._oauthEscape(this._action)+'&'+this._oauthE scape(this._path)+'&'+this._oauthEscape(this._normalizedParameters());
451 return this.b64_hmac_sha1(secretKey,sigString);
452 }
453 return null;
454 };
455
456 return this;
457 };
458 }
OLDNEW
« no previous file with comments | « remoting/webapp/me2mom/chrome_ex_oauth.js ('k') | remoting/webapp/me2mom/manifest.json » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698