UNPKG

alloy

Version:

TiDev Titanium MVC Framework

648 lines (621 loc) 29 kB
/** * @class Alloy.builtins.social * A collection of useful social media provider utilities. Currently, this module only supports * Twitter and the following features: * * - Logging into Twitter and authorizing the application through the OAuth protocol. * - Posting tweets to the user's Twitter account. * * To use the social builtin library, require it with the `alloy` root * directory in your `require` call. For example: * * var social = require('/alloy/social').create({ * consumerSecret: 'consumer-secret', * consumerKey: 'consumer-key' * }); * * ## Login and Authorization * * To use a social media provider, a user must log in and authorize the application to perform * certain actions, such as accessing profile information or posting messages. * * Call `authorize` to prompt the user to login and authorize the application. For Twitter, a * dialog box will appear asking the user for their permission and login credentials. * * Before calling `authorize`, the application will need a consumer key and secret provided by the * social media service provider for the OAuth protocol, used when calling `create`. * For Twitter, these are provided when registering an application: * [https://dev.twitter.com/apps/new](https://dev.twitter.com/apps/new) * * ## Example * * This example authorizes the application, posts a message to the user's Twitter account, then * deauthorizes the application. * * // If not authorized, get authorization from the user * if(!social.isAuthorized()) { * social.authorize(); * } * * // Post a message * // Setup both callbacks for confirmation * // Note: share() automatically calls authorize() so an explicit call as above is unnecessary * social.share({ * message: "Salut, Monde!", * success: function(e) {alert('Success!')}, * error: function(e) {alert('Error!')} * }); * * // Deauthorize the application * social.deauthorize(); */ function hex_sha1(s) { return binb2hex(core_sha1(str2binb(s), s.length * chrsz)); } function b64_sha1(s) { return binb2b64(core_sha1(str2binb(s), s.length * chrsz)); } function str_sha1(s) { return binb2str(core_sha1(str2binb(s), s.length * chrsz)); } function hex_hmac_sha1(key, data) { return binb2hex(core_hmac_sha1(key, data)); } function b64_hmac_sha1(key, data) { return binb2b64(core_hmac_sha1(key, data)); } function str_hmac_sha1(key, data) { return binb2str(core_hmac_sha1(key, data)); } function sha1_vm_test() { return hex_sha1('abc') == 'a9993e364706816aba3e25717850c26c9cd0d89d'; } function core_sha1(x, len) { x[len >> 5] |= 128 << 24 - len % 32, x[(len + 64 >> 9 << 4) + 15] = len; var w = Array(80), a = 1732584193, b = -271733879, c = -1732584194, d = 271733878, e = -1009589776; for (var i = 0; i < x.length; i += 16) { var olda = a, oldb = b, oldc = c, oldd = d, olde = e; for (var j = 0; j < 80; j++) { j < 16 ? w[j] = x[i + j] : w[j] = rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1); var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), safe_add(safe_add(e, w[j]), sha1_kt(j))); e = d, d = c, c = rol(b, 30), b = a, a = t; } a = safe_add(a, olda), b = safe_add(b, oldb), c = safe_add(c, oldc), d = safe_add(d, oldd), e = safe_add(e, olde); } return Array(a, b, c, d, e); } function sha1_ft(t, b, c, d) { return t < 20 ? b & c | ~b & d : t < 40 ? b ^ c ^ d : t < 60 ? b & c | b & d | c & d : b ^ c ^ d; } function sha1_kt(t) { return t < 20 ? 1518500249 : t < 40 ? 1859775393 : t < 60 ? -1894007588 : -899497514; } function core_hmac_sha1(key, data) { var bkey = str2binb(key); bkey.length > 16 && (bkey = core_sha1(bkey, key.length * chrsz)); var ipad = Array(16), opad = Array(16); for (var i = 0; i < 16; i++) ipad[i] = bkey[i] ^ 909522486, opad[i] = bkey[i] ^ 1549556828; var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz); return core_sha1(opad.concat(hash), 672); } function safe_add(x, y) { var lsw = (x & 65535) + (y & 65535), msw = (x >> 16) + (y >> 16) + (lsw >> 16); return msw << 16 | lsw & 65535; } function rol(num, cnt) { return num << cnt | num >>> 32 - cnt; } function str2binb(str) { var bin = Array(), mask = (1 << chrsz) - 1; for (var i = 0; i < str.length * chrsz; i += chrsz) bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << 32 - chrsz - i % 32; return bin; } function binb2str(bin) { var str = '', mask = (1 << chrsz) - 1; for (var i = 0; i < bin.length * 32; i += chrsz) str += String.fromCharCode(bin[i >> 5] >>> 32 - chrsz - i % 32 & mask); return str; } function binb2hex(binarray) { var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef', str = ''; for (var i = 0; i < binarray.length * 4; i++) str += hex_tab.charAt(binarray[i >> 2] >> (3 - i % 4) * 8 + 4 & 15) + hex_tab.charAt(binarray[i >> 2] >> (3 - i % 4) * 8 & 15); return str; } function binb2b64(binarray) { var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', str = ''; for (var i = 0; i < binarray.length * 4; i += 3) { var triplet = (binarray[i >> 2] >> 8 * (3 - i % 4) & 255) << 16 | (binarray[i + 1 >> 2] >> 8 * (3 - (i + 1) % 4) & 255) << 8 | binarray[i + 2 >> 2] >> 8 * (3 - (i + 2) % 4) & 255; for (var j = 0; j < 4; j++) i * 8 + j * 6 > binarray.length * 32 ? str += b64pad : str += tab.charAt(triplet >> 6 * (3 - j) & 63); } return str; } var hexcase = 0, b64pad = '', chrsz = 8, OAuth; OAuth == null && (OAuth = {}), OAuth.setProperties = function(into, from) { if (into != null && from != null) for (var key in from) into[key] = from[key]; return into; }, OAuth.setProperties(OAuth, { percentEncode: function(s) { if (s == null) return ''; if (s instanceof Array) { var e = ''; for (var i = 0; i < s.length; ++s) e != '' && (e += '&'), e += OAuth.percentEncode(s[i]); return e; } return s = encodeURIComponent(s), s = s.replace(/\!/g, '%21'), s = s.replace(/\*/g, '%2A'), s = s.replace(/\'/g, '%27'), s = s.replace(/\(/g, '%28'), s = s.replace(/\)/g, '%29'), s; }, decodePercent: function(s) { return s != null && (s = s.replace(/\+/g, ' ')), decodeURIComponent(s); }, getParameterList: function(parameters) { if (parameters == null) return []; if (typeof parameters != 'object') return OAuth.decodeForm(parameters + ''); if (parameters instanceof Array) return parameters; var list = []; for (var p in parameters) list.push([ p, parameters[p] ]); return list; }, getParameterMap: function(parameters) { if (parameters == null) return {}; if (typeof parameters != 'object') return OAuth.getParameterMap(OAuth.decodeForm(parameters + '')); if (parameters instanceof Array) { var map = {}; for (var p = 0; p < parameters.length; ++p) { var key = parameters[p][0]; map[key] === undefined && (map[key] = parameters[p][1]); } return map; } return parameters; }, getParameter: function(parameters, name) { if (parameters instanceof Array) { for (var p = 0; p < parameters.length; ++p) if (parameters[p][0] == name) return parameters[p][1]; return null; } return OAuth.getParameterMap(parameters)[name]; }, formEncode: function(parameters) { var form = '', list = OAuth.getParameterList(parameters); for (var p = 0; p < list.length; ++p) { var value = list[p][1]; value == null && (value = ''), form != '' && (form += '&'), form += OAuth.percentEncode(list[p][0]) + '=' + OAuth.percentEncode(value); } return form; }, decodeForm: function(form) { var list = [], nvps = form.split('&'); for (var n = 0; n < nvps.length; ++n) { var nvp = nvps[n]; if (nvp == '') continue; var equals = nvp.indexOf('='), name, value; equals < 0 ? (name = OAuth.decodePercent(nvp), value = null) : (name = OAuth.decodePercent(nvp.substring(0, equals)), value = OAuth.decodePercent(nvp.substring(equals + 1))), list.push([ name, value ]); } return list; }, setParameter: function(message, name, value) { var parameters = message.parameters; if (parameters instanceof Array) { for (var p = 0; p < parameters.length; ++p) parameters[p][0] == name && (value === undefined ? parameters.splice(p, 1) : (parameters[p][1] = value, value = undefined)); value !== undefined && parameters.push([ name, value ]); } else parameters = OAuth.getParameterMap(parameters), parameters[name] = value, message.parameters = parameters; }, setParameters: function(message, parameters) { var list = OAuth.getParameterList(parameters); for (var i = 0; i < list.length; ++i) OAuth.setParameter(message, list[i][0], list[i][1]); }, completeRequest: function(message, accessor) { message.method == null && (message.method = 'GET'); var map = OAuth.getParameterMap(message.parameters); map.oauth_consumer_key == null && OAuth.setParameter(message, 'oauth_consumer_key', accessor.consumerKey || ''), map.oauth_token == null && accessor.token != null && OAuth.setParameter(message, 'oauth_token', accessor.token), map.oauth_version == null && OAuth.setParameter(message, 'oauth_version', '1.0'), map.oauth_timestamp == null && OAuth.setParameter(message, 'oauth_timestamp', OAuth.timestamp()), map.oauth_nonce == null && OAuth.setParameter(message, 'oauth_nonce', OAuth.nonce(6)), OAuth.SignatureMethod.sign(message, accessor); }, setTimestampAndNonce: function(message) { OAuth.setParameter(message, 'oauth_timestamp', OAuth.timestamp()), OAuth.setParameter(message, 'oauth_nonce', OAuth.nonce(6)); }, addToURL: function(url, parameters) { newURL = url; if (parameters != null) { var toAdd = OAuth.formEncode(parameters); if (toAdd.length > 0) { var q = url.indexOf('?'); q < 0 ? newURL += '?' : newURL += '&', newURL += toAdd; } } return newURL; }, getAuthorizationHeader: function(realm, parameters) { var header = 'OAuth realm="' + OAuth.percentEncode(realm) + '"', list = OAuth.getParameterList(parameters); for (var p = 0; p < list.length; ++p) { var parameter = list[p], name = parameter[0]; name.indexOf('oauth_') == 0 && (header += ',' + OAuth.percentEncode(name) + '="' + OAuth.percentEncode(parameter[1]) + '"'); } return header; }, correctTimestampFromSrc: function(parameterName) { parameterName = parameterName || 'oauth_timestamp'; var scripts = document.getElementsByTagName('script'); if (scripts == null || !scripts.length) return; var src = scripts[scripts.length - 1].src; if (!src) return; var q = src.indexOf('?'); if (q < 0) return; parameters = OAuth.getParameterMap(OAuth.decodeForm(src.substring(q + 1))); var t = parameters[parameterName]; if (t == null) return; OAuth.correctTimestamp(t); }, correctTimestamp: function(timestamp) { OAuth.timeCorrectionMsec = timestamp * 1e3 - (new Date).getTime(); }, timeCorrectionMsec: 0, timestamp: function() { var t = (new Date).getTime() + OAuth.timeCorrectionMsec; return '' + Math.floor(t / 1e3); }, nonce: function(length) { var chars = OAuth.nonce.CHARS, result = ''; for (var i = 0; i < length; ++i) { var rnum = Math.floor(Math.random() * chars.length); result += chars.substring(rnum, rnum + 1); } return result; } }), OAuth.nonce.CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz', OAuth.declareClass = function(parent, name, newConstructor) { var previous = parent[name]; parent[name] = newConstructor; if (newConstructor != null && previous != null) for (var key in previous) key != 'prototype' && (newConstructor[key] = previous[key]); return newConstructor; }, OAuth.declareClass(OAuth, 'SignatureMethod', function() {}), OAuth.setProperties(OAuth.SignatureMethod.prototype, { sign: function(message) { var baseString = OAuth.SignatureMethod.getBaseString(message), signature = this.getSignature(baseString); return OAuth.setParameter(message, 'oauth_signature', signature), signature; }, initialize: function(name, accessor) { var consumerSecret; accessor.accessorSecret != null && name.length > 9 && name.substring(name.length - 9) == '-Accessor' ? consumerSecret = accessor.accessorSecret : consumerSecret = accessor.consumerSecret, this.key = OAuth.percentEncode(consumerSecret) + '&' + OAuth.percentEncode(accessor.tokenSecret); } }), OAuth.setProperties(OAuth.SignatureMethod, { sign: function(message, accessor) { var name = OAuth.getParameterMap(message.parameters).oauth_signature_method; if (name == null || name == '') name = 'HMAC-SHA1', OAuth.setParameter(message, 'oauth_signature_method', name); OAuth.SignatureMethod.newMethod(name, accessor).sign(message); }, newMethod: function(name, accessor) { var impl = OAuth.SignatureMethod.REGISTERED[name]; if (impl != null) { var method = new impl; return method.initialize(name, accessor), method; } var err = new Error('signature_method_rejected'), acceptable = ''; for (var r in OAuth.SignatureMethod.REGISTERED) acceptable != '' && (acceptable += '&'), acceptable += OAuth.percentEncode(r); throw err.oauth_acceptable_signature_methods = acceptable, err; }, REGISTERED: {}, registerMethodClass: function(names, classConstructor) { for (var n = 0; n < names.length; ++n) OAuth.SignatureMethod.REGISTERED[names[n]] = classConstructor; }, makeSubclass: function(getSignatureFunction) { var superClass = OAuth.SignatureMethod, subClass = function() { superClass.call(this); }; return subClass.prototype = new superClass, subClass.prototype.getSignature = getSignatureFunction, subClass.prototype.constructor = subClass, subClass; }, getBaseString: function(message) { var URL = message.action, q = URL.indexOf('?'), parameters; if (q < 0) parameters = message.parameters; else { parameters = OAuth.decodeForm(URL.substring(q + 1)); var toAdd = OAuth.getParameterList(message.parameters); for (var a = 0; a < toAdd.length; ++a) parameters.push(toAdd[a]); } return OAuth.percentEncode(message.method.toUpperCase()) + '&' + OAuth.percentEncode(OAuth.SignatureMethod.normalizeUrl(URL)) + '&' + OAuth.percentEncode(OAuth.SignatureMethod.normalizeParameters(parameters)); }, normalizeUrl: function(url) { var uri = OAuth.SignatureMethod.parseUri(url), scheme = uri.protocol.toLowerCase(), authority = uri.authority.toLowerCase(), dropPort = scheme == 'http' && uri.port == 80 || scheme == 'https' && uri.port == 443; if (dropPort) { var index = authority.lastIndexOf(':'); index >= 0 && (authority = authority.substring(0, index)); } var path = uri.path; return path || (path = '/'), scheme + '://' + authority + path; }, parseUri: function(str) { var o = { key: [ 'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor' ], parser: { strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/ } }, m = o.parser.strict.exec(str), uri = {}, i = 14; while (i--) uri[o.key[i]] = m[i] || ''; return uri; }, normalizeParameters: function(parameters) { if (parameters == null) return ''; var list = OAuth.getParameterList(parameters), sortable = []; for (var p = 0; p < list.length; ++p) { var nvp = list[p]; nvp[0] != 'oauth_signature' && sortable.push([ OAuth.percentEncode(nvp[0]) + ' ' + OAuth.percentEncode(nvp[1]), nvp ]); } sortable.sort(function(a, b) { return a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0; }); var sorted = []; for (var s = 0; s < sortable.length; ++s) sorted.push(sortable[s][1]); return OAuth.formEncode(sorted); } }), OAuth.SignatureMethod.registerMethodClass([ 'PLAINTEXT', 'PLAINTEXT-Accessor' ], OAuth.SignatureMethod.makeSubclass(function(baseString) { return this.key; })), OAuth.SignatureMethod.registerMethodClass([ 'HMAC-SHA1', 'HMAC-SHA1-Accessor' ], OAuth.SignatureMethod.makeSubclass(function(baseString) { b64pad = '='; var signature = b64_hmac_sha1(this.key, baseString); return signature; })); try { OAuth.correctTimestampFromSrc(); } catch (e) { //do nothing } var OAuthAdapter = function(pConsumerSecret, pConsumerKey, pSignatureMethod) { function showLoading() { if (loading) return; loading = !0, loadingView && (loadingView.value = 0), estimateID = firstLoad ? "tokenRequest" : "pageLoad", estimates[estimateID] || (estimates[estimateID] = firstLoad ? 2e3 : 1e3), firstLoad = !1, startTime = (new Date).getTime(), intervalID = setInterval(updateProgress, 30), webView && webView.hide(), loadingView && loadingView.show(), loadingContainer && loadingContainer.show(); } function updateProgress() { loadingView && (loadingView.value = ((new Date).getTime() - startTime) / estimates[estimateID]); } function authorizeUICallback(e) { var response = e.source.evalJS('(p = document.getElementById("oauth_pin")) && p.innerHTML;'); response ? (pin = response.split("<code>")[1].split("</code>")[0], destroyAuthorizeUI(), receivePinCallback()) : (loadingView && loadingView.hide(), loadingContainer && loadingContainer.hide(), webView && webView.show()), loading = !1, clearInterval(intervalID), estimates[estimateID] = (new Date).getTime() - startTime, Ti.App.Properties.setString("Social-LoadingEstimates", JSON.stringify(estimates)); } var consumerSecret = pConsumerSecret, consumerKey = pConsumerKey, signatureMethod = pSignatureMethod, pin = null, requestToken = null, requestTokenSecret = null, accessToken = null, accessTokenSecret = null, accessor = { consumerSecret: consumerSecret, tokenSecret: "" }, window = null, view = null, webView = null, loadingView = null, loadingContainer = null, receivePinCallback = null, accessTokenStore = {}; this.loadAccessToken = function(pService) { var token; if (accessTokenStore[pService]) token = accessTokenStore[pService]; else { var raw = Ti.App.Properties.getString("Social.js-AccessToken-" + pService, ""); if (!raw) return; try { token = accessTokenStore[pService] = JSON.parse(raw); } catch (err) { Ti.API.error("Failed to parse stored access token for " + pService + "!"), Ti.API.error(err); return; } } token.accessToken && (accessToken = token.accessToken), token.accessTokenSecret && (accessTokenSecret = token.accessTokenSecret); }, this.saveAccessToken = function(pService) { accessTokenStore[pService] = { accessToken: accessToken, accessTokenSecret: accessTokenSecret }, Ti.App.Properties.setString("Social.js-AccessToken-" + pService, JSON.stringify(accessTokenStore[pService])); }, this.clearAccessToken = function(pService) { delete accessTokenStore[pService], Ti.App.Properties.setString("Social.js-AccessToken-" + pService, null), accessToken = null, accessTokenSecret = null; }, this.isAuthorized = function() { return accessToken != null && accessTokenSecret != null; }; var createMessage = function(pUrl) { var message = { action: pUrl, method: "POST", parameters: [] }; return message.parameters.push([ "oauth_consumer_key", consumerKey ]), message.parameters.push([ "oauth_signature_method", signatureMethod ]), message; }; this.getPin = function() { return pin; }, this.getRequestToken = function(pUrl, callback) { accessor.tokenSecret = ""; var message = createMessage(pUrl); OAuth.setTimestampAndNonce(message), OAuth.SignatureMethod.sign(message, accessor); var done = !1, client = Ti.Network.createHTTPClient({ onload: function() { var responseParams = OAuth.getParameterMap(this.responseText); requestToken = responseParams.oauth_token, requestTokenSecret = responseParams.oauth_token_secret, callback({ success: !0, token: this.responseText }), done = !0; }, onerror: function() { Ti.API.error("Social.js: FAILED to getRequestToken!"), Ti.API.error(this.responseText), callback({ success: !1 }), done = !0; } }); client.open("POST", pUrl), client.send(OAuth.getParameterMap(message.parameters)); }; var destroyAuthorizeUI = function() { if (window == null) return; try { webView.removeEventListener("load", authorizeUICallback), webView.removeEventListener("beforeload", showLoading), loadingView.hide(), window.close(), loading = null, webView = null, loadingView = null, loading = !1, firstLoad = !0, view = null, window = null; } catch (ex) { Ti.API.debug("Cannot destroy the authorize UI. Ignoring."); } }, firstLoad = !0, loading = !1, estimates = JSON.parse(Ti.App.Properties.getString("Social-LoadingEstimates", "{}")), estimateID, startTime, intervalID = 0; this.showLoadingUI = function() { var animation = require('/alloy/animation'); var isIOS7 = OS_IOS && parseInt(Ti.Platform.version, 10) > 6 ? true : false window = Ti.UI.createWindow({ backgroundColor: "transparent", zIndex: 1e3, opacity: 0, navBarHidden: true }), view = Ti.UI.createView({ top: isIOS7 ? "30dp" : "10dp", right: "10dp", bottom: "10dp", left: "10dp", backgroundColor: "#52D3FE", border: 10, borderColor: "#52D3FE", borderRadius: 10, borderWidth: 4, zIndex: -1 }); var closeLabelContainer = Ti.UI.createView({ top: isIOS7 ? "20dp" : "0dp", right: 0, height: "30dp", width: "32dp" }), closeLabel = Ti.UI.createButton({ font: { fontSize: "12sp", fontWeight: "bold" }, backgroundColor: "#52D3FE", borderColor: "#52D3FE", color: "#fff", style: 0, borderRadius: 6, title: "X", top: "3dp", right: "3dp", width: "25dp", height: "25dp" }); closeLabelContainer.addEventListener("click", destroyAuthorizeUI), window.open(); loadingContainer = Ti.UI.createView({ backgroundColor: "#fff" }), loadingView = Ti.UI.createProgressBar({ min: 0, max: 1, value: .5, message: "Loading, please wait.", backgroundColor: "#fff", font: { fontSize: "14sp", fontWeight: "bold" }, style: 0 }), view.add(loadingContainer), loadingContainer.add(loadingView), loadingView.show(), closeLabelContainer.add(closeLabel), window.add(view), window.add(closeLabelContainer); animation.popIn(window); showLoading(); }, this.showAuthorizeUI = function(pUrl, pReceivePinCallback) { receivePinCallback = pReceivePinCallback; webView = Ti.UI.createWebView({ url: pUrl, autoDetect: [ Ti.UI.AUTODETECT_NONE ] }), webView.addEventListener("beforeload", showLoading), webView.addEventListener("load", authorizeUICallback), view.add(webView); }, this.getAccessToken = function(pUrl, callback) { accessor.tokenSecret = requestTokenSecret; var message = createMessage(pUrl); message.parameters.push([ "oauth_token", requestToken ]), message.parameters.push([ "oauth_verifier", pin ]), OAuth.setTimestampAndNonce(message), OAuth.SignatureMethod.sign(message, accessor); var parameterMap = OAuth.getParameterMap(message.parameters), client = Ti.Network.createHTTPClient({ onload: function() { var responseParams = OAuth.getParameterMap(this.responseText); var userid = responseParams.user_id; var username = responseParams.screen_name; accessToken = responseParams.oauth_token, accessTokenSecret = responseParams.oauth_token_secret, callback({ success: !0, username:username, userid:userid }); }, onerror: function() { Ti.API.error('Social.js: FAILED to getAccessToken!'), Ti.API.error(this.responseText), callback({ success: !1 }); } }); client.open('POST', pUrl), client.send(parameterMap); }, this.send = function(options, callback) { var pUrl = options.url, pParameters = options.parameters, pTitle = options.title, pSuccessMessage = options.onSuccess, pErrorMessage = options.onError; if (accessToken == null || accessTokenSecret == null) { Ti.API.debug("The send status cannot be processed as the client doesn't have an access token. Authorize before trying to send."); return; } accessor.tokenSecret = accessTokenSecret; var message = createMessage(pUrl); message.parameters.push([ 'oauth_token', accessToken ]); for (p in pParameters) message.parameters.push(pParameters[p]); OAuth.setTimestampAndNonce(message), OAuth.SignatureMethod.sign(message, accessor); var parameterMap = OAuth.getParameterMap(message.parameters), client = Ti.Network.createHTTPClient({ onload: function() { client.status == 200 ? pSuccessMessage && pSuccessMessage(this.responseText) : pErrorMessage && pErrorMessage(this.responseText); }, onerror: function() { Ti.API.error('Social.js: FAILED to send a request!'), pErrorMessage && pErrorMessage(this.responseText); } }); client.open('POST', pUrl), client.send(parameterMap); }; }, supportedSites = { twitter: { accessToken: 'https://api.twitter.com/oauth/access_token', requestToken: 'https://api.twitter.com/oauth/request_token', authorize: 'https://api.twitter.com/oauth/authorize?', update: 'https://api.twitter.com/1.1/statuses/update.json' } }; /** * @method create * Initializes an OAuth session to the service provider. * If a previous access token exists, it will be loaded. * @param {...*} settings OAuth session settings. * @param {String} [settings.site='twitter'] Site to access. Only 'twitter' is working. * @param {String} settings.consumerSecret Shared secret used to authenticate the key. * @param {String} settings.consumerKey Key used to identify the client to the service provider. * @return {Object} Instance of social to make subsequent API calls. */ exports.create = function(settings) { var site = (settings.site || 'twitter').toLowerCase(), adapter = new OAuthAdapter(settings.consumerSecret, settings.consumerKey, 'HMAC-SHA1'); adapter.loadAccessToken(site); var urls = supportedSites[site]; return urls == null ? (alert('The Social.js module does not support ' + site + ' yet!'), null) : { /** * @method isAuthorized * Returns 'true' if the client is authorized by the service provider. * @return {Boolean} Returns 'true' if authorized else 'false'. */ isAuthorized: function() { return adapter.isAuthorized(); }, /** * @method deauthorize * Deauthorizes the client and clears the access token. */ deauthorize: function() { adapter.clearAccessToken(site); }, /** * @method authorize * Authorizes the client to the service provider to access user data. * If successful, the client will receive an access token, which will be saved for future * usage. * Call this function after opening the parent view or else the authorize UI window will * appear in the background behind the view and unusable to the user. * @param {Function} [callback] Callback function executed after successfully retrieving * an access token. */ authorize: function(callback) { function receivePin() { adapter.getAccessToken(urls.accessToken, function(evt) { evt.success ? (adapter.saveAccessToken(site), callback && callback({username:evt.username, userid:evt.userid})) : alert('Twitter did not give us an access token!'); }); } if (!adapter.isAuthorized()) { adapter.showLoadingUI(), adapter.getRequestToken(urls.requestToken, function(evt) { evt.success ? adapter.showAuthorizeUI(urls.authorize + evt.token, receivePin) : alert('Twitter did not give us a request token!'); }); } else callback && callback(); }, /** * @method share * Sends an update to the service provider. Implicitly calls authorize() to authorize your app. * @param {...*} options Update parameters. * @param {String} options.message Message to send. * @param {Function} [options.success] Callback function executed after a successful update. * @param {Function} [options.error] Callback function executed after a failed update. */ share: function(options) { this.authorize(function() { adapter.send({ url: urls.update, parameters: [ [ 'status', options.message ] ], title: 'Twitter', onSuccess: options.success, onError: options.error }); }); } }; };