1 /**
  2  * A library for performing authentication.
  3  * Currently supports both Basic and oAuth.
  4  */
  5 /**
  6  * @constant 
  7  */
  8 var SPAZCORE_AUTHTYPE_BASIC  = 'basic';
  9 /**
 10  * @constant 
 11  */
 12 var SPAZCORE_AUTHTYPE_OAUTH  = 'oauth';
 13 
 14 /**
 15  * @constant 
 16  */
 17 var SPAZAUTH_SERVICES = {};
 18 
 19 SPAZAUTH_SERVICES[SPAZCORE_ACCOUNT_STATUSNET] = {
 20 	'authType': SPAZCORE_AUTHTYPE_BASIC
 21 };
 22 SPAZAUTH_SERVICES[SPAZCORE_ACCOUNT_TUMBLR_TWITTER] = {
 23 	'authType': SPAZCORE_AUTHTYPE_BASIC
 24 };
 25 SPAZAUTH_SERVICES[SPAZCORE_ACCOUNT_WORDPRESS_TWITTER] = {
 26 	'authType': SPAZCORE_AUTHTYPE_BASIC
 27 };
 28 SPAZAUTH_SERVICES[SPAZCORE_ACCOUNT_IDENTICA] = {
 29     'authType': SPAZCORE_AUTHTYPE_BASIC
 30 };
 31 SPAZAUTH_SERVICES[SPAZCORE_ACCOUNT_CUSTOM] = {
 32     'authType': SPAZCORE_AUTHTYPE_BASIC
 33 };
 34 SPAZAUTH_SERVICES['default'] = {
 35 	'authType': SPAZCORE_AUTHTYPE_BASIC
 36 };
 37 
 38 /**
 39  * Construct a new authentication object.
 40  *
 41  * @param {string} service name of the service to authenticate (ex: twitter, identica)
 42  * @class SpazAuth
 43  * @constructor
 44  */
 45 function SpazAuth(service) {
 46     var serviceInfo = SPAZAUTH_SERVICES[service];
 47     if (serviceInfo == undefined) {
 48         sch.error("Invalid authentication service: " + service);
 49         return null;
 50     }
 51 
 52     switch (serviceInfo.authType) {
 53         case SPAZCORE_AUTHTYPE_OAUTH:
 54             return new SpazOAuth(service, serviceInfo);
 55         case SPAZCORE_AUTHTYPE_BASIC:
 56             return new SpazBasicAuth();
 57         default:
 58             return new SpazBasicAuth();
 59     }
 60 };
 61 
 62 /**
 63  * use this to add services that aren't in by default (like, say, stuff with secrets)
 64  */
 65 SpazAuth.addService = function(label, opts) {
 66     SPAZAUTH_SERVICES[label] = opts;
 67 };
 68 
 69 
 70 
 71 /**
 72  * Construct a new basic authentication object.
 73  *
 74  * @class SpazBasicAuth
 75  * @constructor
 76  */
 77 function SpazBasicAuth() {
 78 };
 79 
 80 /**
 81  * Set username and password of account to access service.
 82  *
 83  * @param {string} username
 84  * @param {string} password
 85  * @param {function} [onComplete] a callback to fire when complete. Currently just passed TRUE all the time; for compatibility with oAuth need for callbacks
 86  * @return {Boolean} true. ALWAYS returns true!
 87  */
 88 SpazBasicAuth.prototype.authorize = function(username, password, onComplete) {
 89     this.username = username;
 90     this.password = password;
 91     this.authHeader = "Basic " + sc.helpers.Base64.encode(username + ":" + password);
 92     
 93     if (onComplete) {
 94         onComplete.call(this, true);
 95     }
 96 	return true;
 97 };
 98 
 99 
100 /**
101  * Returns the authentication header
102  * @returns {string} Authentication header value
103  */
104 SpazBasicAuth.prototype.signRequest = function() {
105     return this.authHeader;
106 };
107 
108 /**
109   * Load basic auth credentials from a serialized string
110   *
111   * @param {string} pickle the serialized data string returned by save()
112   * @returns {boolean} true if successfully loaded
113   */
114 SpazBasicAuth.prototype.load = function(pickle) {
115     var credentials = pickle.split(':', 2);
116     if (credentials.length != 2) {
117         sch.error("Invalid basic auth pickle: " + pickle);
118         return false;
119     }
120 
121     this.authorize(credentials[0], credentials[1]);
122     return true;
123 };
124 
125 /**
126   * Save basic auth credentials into a serialized string
127   *
128   * @returns {string} serialized string
129   */
130 SpazBasicAuth.prototype.save = function() {
131     return this.username + ":" + this.password;
132 };
133 
134 
135 SpazBasicAuth.prototype.getUsername = function() {
136 	return this.username;
137 };
138 
139 SpazBasicAuth.prototype.getPassword = function() {
140 	return this.password;
141 };
142 
143 
144 /**
145  * Construct a new OAuth authentication object.
146  *
147  * @param {string} realm
148  * @param {object} options
149  * @class SpazOAuth
150  * @constructor
151  */
152 function SpazOAuth(realm, options) {
153     this.realm = realm;
154     this.opts = options;
155 };
156 
157 /**
158  * Authorize access to the service by fetching an OAuth access token.
159  * 
160  * @param {string} username
161  * @param {string} password
162  * @param {function} [onComplete] a callback to fire on complete. If this is set, the request is asynchronous
163  * @returns {boolean} true if authorization successful, otherwise false
164  */
165 SpazOAuth.prototype.authorize = function(username, password, onComplete) {
166 	
167 	var that = this;
168 	
169 	var async_mode = false;
170 	
171     this.username = username;
172 
173     // Fill in xAuth parameters
174     var parameters = {
175         'x_auth_username': username,
176         'x_auth_password': password,
177         'x_auth_mode': 'client_auth'
178     };
179 
180     // Sign the request
181     OAuth.completeRequest({
182         method: 'post',
183         action: this.opts.accessURL,
184         parameters: parameters
185     }, this.opts);
186 
187 	if (onComplete) {
188 		async_mode = true;
189 	}
190 
191     // Perform request to fetch access token
192     var accessToken = null;
193 	jQuery.ajax({
194 		async: async_mode,
195 		type: 'post',
196 		url: this.opts.accessURL,
197 		data: parameters,
198 		dataType: 'text',
199 		success: function(data, textStatus, xhr) {
200 
201 			sch.error(xhr);
202 
203 			sch.error("xhr.responseText:" + xhr.responseText);
204 			sch.error("xhr.responseXML:" + xhr.responseXML);
205 			sch.error('getAllResponseHeaders:n' + xhr.getAllResponseHeaders());
206 
207 
208 			sch.error("OAuth Data return");
209 			sch.error(sch.enJSON(data));
210 
211 			var results = OAuth.decodeForm(data);
212 			sch.error("results");
213 			sch.error(sch.enJSON(results));
214 			accessToken = {};
215 			accessToken.key = OAuth.getParameter(results, 'oauth_token');
216 			accessToken.secret = OAuth.getParameter(results, 'oauth_token_secret');
217 			
218 			that.setAccessToken(accessToken.key, accessToken.secret);
219 			
220 			if (onComplete) {
221 				onComplete.call(this, true, accessToken);
222 			}
223 
224 		},
225 		error: function(req, textStatus, error) {
226 			sch.error("Failed to fetch oAuth access token: " + req.responseText);
227 
228 			if (onComplete) {
229 				onComplete.call(this, false);
230 			}
231 			
232 		},
233 		complete: function(xhr, textStatus) {
234 			sch.error('COMPLETE:');
235 			sch.error("xhr.responseText:" + xhr.responseText);
236 			sch.error("xhr.responseXML:" + xhr.responseXML);
237 			sch.error('getAllResponseHeaders:n' + xhr.getAllResponseHeaders());
238 
239 		},
240 		beforeSend: function(xhr) {
241 			xhr.setRequestHeader('Accept-Encoding', 'none');
242 
243 		}
244 
245 	});
246 	
247 	if (async_mode !== true) {
248 		if (accessToken != null) {
249 			return true;
250 	    } else {
251 			return false;
252 		}
253 	} else {
254 		return null;
255 	}
256 	// var request = new Ajax.Request(this.opts.accessURL, {
257 	// 	'asynchronous':true,
258 	// 	'method':'post',
259 	// 	'parameters':parameters,
260 	// 	'onSuccess': function(xhr, foo) {
261 	// 		sch.error('onSuccess=====================================================');
262 	// 		var data = xhr.responseText;
263 	// 		sch.error('foo');
264 	// 		sch.error(foo);
265 	// 		sch.error(xhr);
266 	// 	
267 	// 		sch.error("xhr.responseText:"+xhr.responseText);
268 	// 		sch.error("xhr.responseXML:"+xhr.responseXML);
269 	// 		sch.error('getAllResponseHeaders:\n'+xhr.getAllResponseHeaders());		
270 	// 	
271 	// 		sch.error("OAuth Data return");
272 	// 		sch.error(data);
273 	// 	
274 	//             var results = OAuth.decodeForm(data);
275 	// 		sch.error("results");
276 	// 		sch.error(sch.enJSON(results));
277 	//             accessToken = {};
278 	//             accessToken.key = OAuth.getParameter(results, 'oauth_token');
279 	//             accessToken.secret = OAuth.getParameter(results, 'oauth_token_secret');
280 	// 		sch.error('==============================================================');
281 	// 		if (accessToken != null) {
282 	// 			that.setAccessToken(accessToken.key, accessToken.secret);
283 	// 			onComplete(true);
284 	// 	    } else {
285 	// 			onComplete(false);
286 	// 		}
287 	// 	},
288 	// 	'onFailure': function(xhr) {
289 	// 		sch.error('onFailure=====================================================');
290 	// 		sch.error("xhr.responseText:"+xhr.responseText);
291 	// 		sch.error('getAllResponseHeaders:\n'+xhr.getAllResponseHeaders());
292 	// 		sch.error('==============================================================');
293 	// 		onComplete(false);
294 	// 	}
295 	// });
296 };
297 
298 
299 /**
300   * Set the access token
301   *
302   * @param {string} key
303   * @param {string} secret
304   */
305 SpazOAuth.prototype.setAccessToken = function(key, secret) {
306     this.accessToken = {key: key, secret: secret};
307     this.signingCredentials = {
308         consumerKey: this.opts.consumerKey,
309         consumerSecret: this.opts.consumerSecret,
310         token: key,
311         tokenSecret: secret
312     };
313 };
314 
315 /**
316  * Sign a HTTP request and return oAuth header
317  *
318  * @param {string} method HTTP method of the request
319  * @param {string} url the URL of the request
320  * @param {object} parameters map of all parameters in the request
321  * @returns {string} Authorization header value
322  */
323 SpazOAuth.prototype.signRequest = function(method, url, parameters) {
324     // We need to copy parameters because OAuth.js modifies it.
325     var param = jQuery.extend({}, parameters);
326 
327     OAuth.completeRequest({
328         method: method,
329         action: url,
330         parameters: param
331     }, this.signingCredentials);
332 
333     return OAuth.getAuthorizationHeader(this.realm, param);
334 };
335 
336 /**
337   * Load OAuth credentials from a serialized string
338   *
339   * @param {string} pickle the serialized string returned by save()
340   * @returns {boolean} true if successfully loaded
341   */
342 SpazOAuth.prototype.load = function(pickle) {
343     var credentials = pickle.split(':', 3);
344     if (credentials.length != 3) {
345         sch.error("Invalid oauth pickle: " + pickle);
346         return false;
347     }
348 
349     this.username = credentials[0];
350     this.setAccessToken(credentials[1], credentials[2]);
351     return true;
352 };
353 
354 /**
355   * Save OAuth credentials to a serialized string
356   *
357   * @returns {string} serialized string
358   */
359 SpazOAuth.prototype.save = function() {
360     return this.username + ":" + this.accessToken.key + ":" + this.accessToken.secret;
361 };
362 
363