|
1 // Generated by CoffeeScript 1.6.2 |
|
2 /* |
|
3 # CoffeeDoc example documentation # |
|
4 |
|
5 This is a module-level docstring, and will be displayed at the top of the module documentation. |
|
6 Documentation generated by [CoffeeDoc](http://github.com/omarkhan/coffeedoc) |
|
7 |
|
8 npm install -g coffeedoc |
|
9 */ |
|
10 |
|
11 |
|
12 (function() { |
|
13 var $, Authomatic, BaseProvider, Flickr, Foursquare, Google, LinkedIn, Oauth1Provider, Oauth2Provider, WindowsLive, deserializeCredentials, format, getProviderClass, globalOptions, jsonPCallbackCounter, log, openWindow, parseQueryString, parseUrl, _ref, _ref1, _ref2, _ref3, _ref4, _ref5, |
|
14 __slice = [].slice, |
|
15 __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, |
|
16 __hasProp = {}.hasOwnProperty, |
|
17 __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; |
|
18 |
|
19 $ = jQuery; |
|
20 |
|
21 jsonPCallbackCounter = 0; |
|
22 |
|
23 globalOptions = { |
|
24 logging: true, |
|
25 popupWidth: 800, |
|
26 popupHeight: 600, |
|
27 popupLinkSelector: 'a.authomatic', |
|
28 popupFormSelector: 'form.authomatic', |
|
29 popupFormValidator: function($form) { |
|
30 return true; |
|
31 }, |
|
32 backend: null, |
|
33 forceBackend: false, |
|
34 substitute: {}, |
|
35 params: {}, |
|
36 headers: {}, |
|
37 body: '', |
|
38 jsonpCallbackPrefix: 'authomaticJsonpCallback', |
|
39 onPopupInvalid: null, |
|
40 onPopupOpen: null, |
|
41 onLoginComplete: null, |
|
42 onBackendStart: null, |
|
43 onBackendComplete: null, |
|
44 onAccessSuccess: null, |
|
45 onAccessComplete: null |
|
46 }; |
|
47 |
|
48 log = function() { |
|
49 var args, _ref; |
|
50 |
|
51 args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; |
|
52 if (globalOptions.logging && ((typeof console !== "undefined" && console !== null ? (_ref = console.log) != null ? _ref.apply : void 0 : void 0) != null)) { |
|
53 return typeof console !== "undefined" && console !== null ? console.log.apply(console, ['Authomatic:'].concat(__slice.call(args))) : void 0; |
|
54 } |
|
55 }; |
|
56 |
|
57 openWindow = function(url) { |
|
58 var height, left, settings, top, width; |
|
59 |
|
60 width = globalOptions.popupWidth; |
|
61 height = globalOptions.popupHeight; |
|
62 top = (screen.height / 2) - (height / 2); |
|
63 left = (screen.width / 2) - (width / 2); |
|
64 settings = "width=" + width + ",height=" + height + ",top=" + top + ",left=" + left; |
|
65 log('Opening popup:', url); |
|
66 if (typeof globalOptions.onPopupOpen === "function") { |
|
67 globalOptions.onPopupOpen(url); |
|
68 } |
|
69 return window.open(url, '', settings); |
|
70 }; |
|
71 |
|
72 parseQueryString = function(queryString) { |
|
73 var item, k, result, v, _i, _len, _ref, _ref1; |
|
74 |
|
75 result = {}; |
|
76 _ref = queryString.split('&'); |
|
77 for (_i = 0, _len = _ref.length; _i < _len; _i++) { |
|
78 item = _ref[_i]; |
|
79 _ref1 = item.split('='), k = _ref1[0], v = _ref1[1]; |
|
80 v = decodeURIComponent(v); |
|
81 if (result.hasOwnProperty(k)) { |
|
82 if (Array.isArray(result[k])) { |
|
83 result[k].push(v); |
|
84 } else { |
|
85 result[k] = [result[k], v]; |
|
86 } |
|
87 } else { |
|
88 result[k] = v; |
|
89 } |
|
90 } |
|
91 return result; |
|
92 }; |
|
93 |
|
94 parseUrl = function(url) { |
|
95 var qs, questionmarkIndex, u; |
|
96 |
|
97 log('parseUrl', url); |
|
98 questionmarkIndex = url.indexOf('?'); |
|
99 if (questionmarkIndex >= 0) { |
|
100 u = url.substring(0, questionmarkIndex); |
|
101 qs = url.substring(questionmarkIndex + 1); |
|
102 } else { |
|
103 u = url; |
|
104 } |
|
105 return { |
|
106 url: u, |
|
107 query: qs, |
|
108 params: qs ? parseQueryString(qs) : void 0 |
|
109 }; |
|
110 }; |
|
111 |
|
112 deserializeCredentials = function(credentials) { |
|
113 var sc, subtype, type, typeId, _ref; |
|
114 |
|
115 sc = decodeURIComponent(credentials).split('\n'); |
|
116 typeId = sc[1]; |
|
117 _ref = typeId.split('-'), type = _ref[0], subtype = _ref[1]; |
|
118 return { |
|
119 id: parseInt(sc[0]), |
|
120 typeId: typeId, |
|
121 type: parseInt(type), |
|
122 subtype: parseInt(subtype), |
|
123 rest: sc.slice(2) |
|
124 }; |
|
125 }; |
|
126 |
|
127 getProviderClass = function(credentials) { |
|
128 var subtype, type, _ref; |
|
129 |
|
130 _ref = deserializeCredentials(credentials), type = _ref.type, subtype = _ref.subtype; |
|
131 if (type === 1) { |
|
132 if (subtype === 2) { |
|
133 return Flickr; |
|
134 } else { |
|
135 return Oauth1Provider; |
|
136 } |
|
137 } else if (type === 2) { |
|
138 if (subtype === 6) { |
|
139 return Foursquare; |
|
140 } else if (subtype === 9) { |
|
141 return LinkedIn; |
|
142 } else if (subtype === 14) { |
|
143 return WindowsLive; |
|
144 } else if (subtype === 12 || subtype === 15) { |
|
145 return BaseProvider; |
|
146 } else { |
|
147 return Oauth2Provider; |
|
148 } |
|
149 } else { |
|
150 return BaseProvider; |
|
151 } |
|
152 }; |
|
153 |
|
154 format = function(template, substitute) { |
|
155 return template.replace(/{([^}]*)}/g, function(match, tag) { |
|
156 var level, target, _i, _len, _ref; |
|
157 |
|
158 target = substitute; |
|
159 _ref = tag.split('.'); |
|
160 for (_i = 0, _len = _ref.length; _i < _len; _i++) { |
|
161 level = _ref[_i]; |
|
162 target = target[level]; |
|
163 } |
|
164 return target; |
|
165 }); |
|
166 }; |
|
167 |
|
168 window.authomatic = new (Authomatic = (function() { |
|
169 function Authomatic() {} |
|
170 |
|
171 Authomatic.prototype.setup = function(options) { |
|
172 $.extend(globalOptions, options); |
|
173 return log('Setting up authomatic to:', globalOptions); |
|
174 }; |
|
175 |
|
176 Authomatic.prototype.popupInit = function() { |
|
177 $(globalOptions.popupLinkSelector).click(function(e) { |
|
178 e.preventDefault(); |
|
179 return openWindow($(this).attr('href')); |
|
180 }); |
|
181 return $(globalOptions.popupFormSelector).submit(function(e) { |
|
182 var $form, url; |
|
183 |
|
184 e.preventDefault(); |
|
185 $form = $(this); |
|
186 url = $form.attr('action') + '?' + $form.serialize(); |
|
187 if (globalOptions.popupFormValidator($form)) { |
|
188 return openWindow(url); |
|
189 } else { |
|
190 return typeof globalOptions.onPopupInvalid === "function" ? globalOptions.onPopupInvalid($form) : void 0; |
|
191 } |
|
192 }); |
|
193 }; |
|
194 |
|
195 Authomatic.prototype.loginComplete = function(result, closer) { |
|
196 var result_copy; |
|
197 |
|
198 result_copy = $.extend(true, {}, result); |
|
199 log('Login procedure complete', result_copy); |
|
200 closer(); |
|
201 return globalOptions.onLoginComplete(result_copy); |
|
202 }; |
|
203 |
|
204 Authomatic.prototype.access = function(credentials, url, options) { |
|
205 var Provider, localEvents, provider, updatedOptions; |
|
206 |
|
207 if (options == null) { |
|
208 options = {}; |
|
209 } |
|
210 localEvents = { |
|
211 onBackendStart: null, |
|
212 onBackendComplete: null, |
|
213 onAccessSuccess: null, |
|
214 onAccessComplete: null |
|
215 }; |
|
216 updatedOptions = {}; |
|
217 $.extend(updatedOptions, globalOptions, localEvents, options); |
|
218 url = format(url, updatedOptions.substitute); |
|
219 log('access options', updatedOptions, globalOptions); |
|
220 if (updatedOptions.forceBackend) { |
|
221 Provider = BaseProvider; |
|
222 } else { |
|
223 Provider = getProviderClass(credentials); |
|
224 } |
|
225 provider = new Provider(options.backend, credentials, url, updatedOptions); |
|
226 log('Instantiating provider:', provider); |
|
227 return provider.access(); |
|
228 }; |
|
229 |
|
230 return Authomatic; |
|
231 |
|
232 })()); |
|
233 |
|
234 BaseProvider = (function() { |
|
235 BaseProvider.prototype._x_jsonpCallbackParamName = 'callback'; |
|
236 |
|
237 function BaseProvider(backend, credentials, url, options) { |
|
238 var parsedUrl; |
|
239 |
|
240 this.backend = backend; |
|
241 this.credentials = credentials; |
|
242 this.options = options; |
|
243 this.access = __bind(this.access, this); |
|
244 this.contactProvider = __bind(this.contactProvider, this); |
|
245 this.contactBackend = __bind(this.contactBackend, this); |
|
246 this.backendRequestType = 'auto'; |
|
247 this.jsonpRequest = false; |
|
248 this.jsonpCallbackName = "" + globalOptions.jsonpCallbackPrefix + jsonPCallbackCounter; |
|
249 this.deserializedCredentials = deserializeCredentials(this.credentials); |
|
250 this.providerID = this.deserializedCredentials.id; |
|
251 this.providerType = this.deserializedCredentials.type; |
|
252 this.credentialsRest = this.deserializedCredentials.rest; |
|
253 parsedUrl = parseUrl(url); |
|
254 this.url = parsedUrl.url; |
|
255 this.params = {}; |
|
256 $.extend(this.params, parsedUrl.params, this.options.params); |
|
257 } |
|
258 |
|
259 BaseProvider.prototype.contactBackend = function(callback) { |
|
260 var data, _base; |
|
261 |
|
262 if (this.jsonpRequest && this.options.method === !'GET') { |
|
263 this.backendRequestType = 'fetch'; |
|
264 } |
|
265 data = { |
|
266 type: this.backendRequestType, |
|
267 credentials: this.credentials, |
|
268 url: this.url, |
|
269 method: this.options.method, |
|
270 body: this.options.body, |
|
271 params: JSON.stringify(this.params), |
|
272 headers: JSON.stringify(this.options.headers) |
|
273 }; |
|
274 if (typeof globalOptions.onBackendStart === "function") { |
|
275 globalOptions.onBackendStart(data); |
|
276 } |
|
277 if (typeof (_base = this.options).onBackendStart === "function") { |
|
278 _base.onBackendStart(data); |
|
279 } |
|
280 log("Contacting backend at " + this.options.backend + ".", data); |
|
281 return $.get(this.options.backend, data, callback); |
|
282 }; |
|
283 |
|
284 BaseProvider.prototype.contactProvider = function(requestElements) { |
|
285 var body, headers, jsonpOptions, method, options, params, url, |
|
286 _this = this; |
|
287 |
|
288 url = requestElements.url, method = requestElements.method, params = requestElements.params, headers = requestElements.headers, body = requestElements.body; |
|
289 options = { |
|
290 type: method, |
|
291 data: params, |
|
292 headers: headers, |
|
293 complete: [ |
|
294 (function(jqXHR, textStatus) { |
|
295 return log('Request complete.', textStatus, jqXHR); |
|
296 }), globalOptions.onAccessComplete, this.options.onAccessComplete |
|
297 ], |
|
298 success: [ |
|
299 (function(data) { |
|
300 return log('Request successful.', data); |
|
301 }), globalOptions.onAccessSuccess, this.options.onAccessSuccess |
|
302 ], |
|
303 error: function(jqXHR, textStatus, errorThrown) { |
|
304 if (jqXHR.state() === 'rejected') { |
|
305 if (_this.options.method === 'GET') { |
|
306 log('Cross domain request failed! trying JSONP request.'); |
|
307 _this.jsonpRequest = true; |
|
308 } else { |
|
309 _this.backendRequestType = 'fetch'; |
|
310 } |
|
311 return _this.access(); |
|
312 } |
|
313 } |
|
314 }; |
|
315 if (this.jsonpRequest) { |
|
316 jsonpOptions = { |
|
317 jsonpCallback: this.jsonpCallbackName, |
|
318 jsonp: this._x_jsonpCallbackParamName, |
|
319 cache: true, |
|
320 dataType: 'jsonp', |
|
321 error: function(jqXHR, textStatus, errorThrown) { |
|
322 return log('JSONP failed! State:', jqXHR.state()); |
|
323 } |
|
324 }; |
|
325 $.extend(options, jsonpOptions); |
|
326 log("Contacting provider with JSONP request.", url, options); |
|
327 } else { |
|
328 log("Contacting provider with cross domain request", url, options); |
|
329 } |
|
330 return $.ajax(url, options); |
|
331 }; |
|
332 |
|
333 BaseProvider.prototype.access = function() { |
|
334 var callback, |
|
335 _this = this; |
|
336 |
|
337 callback = function(data, textStatus, jqXHR) { |
|
338 var responseTo, _base, _base1, _base2; |
|
339 |
|
340 if (typeof globalOptions.onBackendComplete === "function") { |
|
341 globalOptions.onBackendComplete(data, textStatus, jqXHR); |
|
342 } |
|
343 if (typeof (_base = _this.options).onBackendComplete === "function") { |
|
344 _base.onBackendComplete(data, textStatus, jqXHR); |
|
345 } |
|
346 responseTo = jqXHR != null ? jqXHR.getResponseHeader('Authomatic-Response-To') : void 0; |
|
347 if (responseTo === 'fetch') { |
|
348 log("Fetch data returned from backend.", jqXHR.getResponseHeader('content-type'), data); |
|
349 if (typeof globalOptions.onAccessSuccess === "function") { |
|
350 globalOptions.onAccessSuccess(data); |
|
351 } |
|
352 if (typeof (_base1 = _this.options).onAccessSuccess === "function") { |
|
353 _base1.onAccessSuccess(data); |
|
354 } |
|
355 if (typeof globalOptions.onAccessComplete === "function") { |
|
356 globalOptions.onAccessComplete(jqXHR, textStatus); |
|
357 } |
|
358 return typeof (_base2 = _this.options).onAccessComplete === "function" ? _base2.onAccessComplete(jqXHR, textStatus) : void 0; |
|
359 } else if (responseTo === 'elements') { |
|
360 log("Request elements data returned from backend.", data); |
|
361 return _this.contactProvider(data); |
|
362 } |
|
363 }; |
|
364 if (this.jsonpRequest) { |
|
365 jsonPCallbackCounter += 1; |
|
366 } |
|
367 return this.contactBackend(callback); |
|
368 }; |
|
369 |
|
370 return BaseProvider; |
|
371 |
|
372 })(); |
|
373 |
|
374 Oauth1Provider = (function(_super) { |
|
375 __extends(Oauth1Provider, _super); |
|
376 |
|
377 function Oauth1Provider() { |
|
378 this.contactProvider = __bind(this.contactProvider, this); |
|
379 this.access = __bind(this.access, this); _ref = Oauth1Provider.__super__.constructor.apply(this, arguments); |
|
380 return _ref; |
|
381 } |
|
382 |
|
383 Oauth1Provider.prototype.access = function() { |
|
384 this.jsonpRequest = true; |
|
385 this.params[this._x_jsonpCallbackParamName] = this.jsonpCallbackName; |
|
386 return Oauth1Provider.__super__.access.call(this); |
|
387 }; |
|
388 |
|
389 Oauth1Provider.prototype.contactProvider = function(requestElements) { |
|
390 delete requestElements.params.callback; |
|
391 return Oauth1Provider.__super__.contactProvider.call(this, requestElements); |
|
392 }; |
|
393 |
|
394 return Oauth1Provider; |
|
395 |
|
396 })(BaseProvider); |
|
397 |
|
398 Flickr = (function(_super) { |
|
399 __extends(Flickr, _super); |
|
400 |
|
401 function Flickr() { |
|
402 _ref1 = Flickr.__super__.constructor.apply(this, arguments); |
|
403 return _ref1; |
|
404 } |
|
405 |
|
406 Flickr.prototype._x_jsonpCallbackParamName = 'jsoncallback'; |
|
407 |
|
408 return Flickr; |
|
409 |
|
410 })(Oauth1Provider); |
|
411 |
|
412 Oauth2Provider = (function(_super) { |
|
413 __extends(Oauth2Provider, _super); |
|
414 |
|
415 Oauth2Provider.prototype._x_accessToken = 'access_token'; |
|
416 |
|
417 Oauth2Provider.prototype._x_bearer = 'Bearer'; |
|
418 |
|
419 function Oauth2Provider() { |
|
420 var args, _ref2; |
|
421 |
|
422 args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; |
|
423 this.access = __bind(this.access, this); |
|
424 this.handleTokenType = __bind(this.handleTokenType, this); |
|
425 Oauth2Provider.__super__.constructor.apply(this, args); |
|
426 _ref2 = this.credentialsRest, this.accessToken = _ref2[0], this.refreshToken = _ref2[1], this.expirationTime = _ref2[2], this.tokenType = _ref2[3]; |
|
427 this.handleTokenType(); |
|
428 } |
|
429 |
|
430 Oauth2Provider.prototype.handleTokenType = function() { |
|
431 if (this.tokenType === '1') { |
|
432 return this.options.headers['Authorization'] = "" + this._x_bearer + " " + this.accessToken; |
|
433 } else { |
|
434 return this.params[this._x_accessToken] = this.accessToken; |
|
435 } |
|
436 }; |
|
437 |
|
438 Oauth2Provider.prototype.access = function() { |
|
439 var requestElements; |
|
440 |
|
441 if (this.backendRequestType === 'fetch') { |
|
442 return Oauth2Provider.__super__.access.call(this); |
|
443 } else { |
|
444 requestElements = { |
|
445 url: this.url, |
|
446 method: this.options.method, |
|
447 params: this.params, |
|
448 headers: this.options.headers, |
|
449 body: this.options.body |
|
450 }; |
|
451 return this.contactProvider(requestElements); |
|
452 } |
|
453 }; |
|
454 |
|
455 return Oauth2Provider; |
|
456 |
|
457 })(BaseProvider); |
|
458 |
|
459 Foursquare = (function(_super) { |
|
460 __extends(Foursquare, _super); |
|
461 |
|
462 function Foursquare() { |
|
463 _ref2 = Foursquare.__super__.constructor.apply(this, arguments); |
|
464 return _ref2; |
|
465 } |
|
466 |
|
467 Foursquare.prototype._x_accessToken = 'oauth_token'; |
|
468 |
|
469 return Foursquare; |
|
470 |
|
471 })(Oauth2Provider); |
|
472 |
|
473 Google = (function(_super) { |
|
474 __extends(Google, _super); |
|
475 |
|
476 function Google() { |
|
477 _ref3 = Google.__super__.constructor.apply(this, arguments); |
|
478 return _ref3; |
|
479 } |
|
480 |
|
481 Google.prototype._x_bearer = 'OAuth'; |
|
482 |
|
483 return Google; |
|
484 |
|
485 })(Oauth2Provider); |
|
486 |
|
487 LinkedIn = (function(_super) { |
|
488 __extends(LinkedIn, _super); |
|
489 |
|
490 function LinkedIn() { |
|
491 _ref4 = LinkedIn.__super__.constructor.apply(this, arguments); |
|
492 return _ref4; |
|
493 } |
|
494 |
|
495 LinkedIn.prototype._x_accessToken = 'oauth2_access_token'; |
|
496 |
|
497 return LinkedIn; |
|
498 |
|
499 })(Oauth2Provider); |
|
500 |
|
501 WindowsLive = (function(_super) { |
|
502 __extends(WindowsLive, _super); |
|
503 |
|
504 function WindowsLive() { |
|
505 this.handleTokenType = __bind(this.handleTokenType, this); _ref5 = WindowsLive.__super__.constructor.apply(this, arguments); |
|
506 return _ref5; |
|
507 } |
|
508 |
|
509 WindowsLive.prototype.handleTokenType = function() { |
|
510 if (this.tokenType === '1') { |
|
511 this.options.headers['Authorization'] = "" + this._x_bearer + " " + this.accessToken; |
|
512 } |
|
513 return this.params[this._x_accessToken] = this.accessToken; |
|
514 }; |
|
515 |
|
516 return WindowsLive; |
|
517 |
|
518 })(Oauth2Provider); |
|
519 |
|
520 }).call(this); |
|
521 |
|
522 /* |
|
523 //@ sourceMappingURL=authomatic.map |
|
524 */ |