From 92ea5b9f693f15986031e8d5af1eb1acab6d6b6c Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Mon, 22 Jun 2015 23:28:27 -0300 Subject: [PATCH 01/47] Update openfb.js --- openfb.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openfb.js b/openfb.js index 864983c..85035a8 100644 --- a/openfb.js +++ b/openfb.js @@ -156,7 +156,7 @@ var openFB = (function () { startTime = new Date().getTime(); loginWindow = window.open(loginURL + '?client_id=' + fbAppId + '&redirect_uri=' + redirectURL + - '&response_type=token&scope=' + scope, '_blank', 'location=no,clearcache=yes'); + '&response_type=token,signed_request,code&scope=' + scope, '_blank', 'location=no,clearcache=yes'); // If the app is running in Cordova, listen to URL changes in the InAppBrowser until we get a URL with an access_token or an error if (runningInCordova) { @@ -180,11 +180,11 @@ var openFB = (function () { obj; loginProcessed = true; - if (url.indexOf("access_token=") > 0) { + if (url.indexOf('access_token=') > 0) { queryString = url.substr(url.indexOf('#') + 1); obj = parseQueryString(queryString); tokenStore.fbAccessToken = obj['access_token']; - if (loginCallback) loginCallback({status: 'connected', authResponse: {accessToken: obj['access_token']}}); + if (loginCallback) loginCallback({status: 'connected', authResponse: {accessToken:obj['access_token'], expiresIn:obj['expires_in'], signedRequest:obj['signed_request']}}); } else if (url.indexOf("error=") > 0) { queryString = url.substring(url.indexOf('?') + 1, url.indexOf('#')); obj = parseQueryString(queryString); From 9f517cc0f4ea13045b7bd72d337c080cff8d5a70 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Mon, 22 Jun 2015 23:36:14 -0300 Subject: [PATCH 02/47] Update openfb.js --- openfb.js | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/openfb.js b/openfb.js index 85035a8..79f6f19 100644 --- a/openfb.js +++ b/openfb.js @@ -40,7 +40,10 @@ var openFB = (function () { runningInCordova, // Used in the exit event handler to identify if the login has already been processed elsewhere (in the oauthCallback function) - loginProcessed; + loginProcessed, + + // The current authResponse object if available, null otherwise + authResponse = null; // MAKE SURE YOU INCLUDE IN YOUR index.html, OTHERWISE runningInCordova will always by false. // You don't need to (and should not) add the actual cordova.js file to your file system: it will be added automatically @@ -95,7 +98,7 @@ var openFB = (function () { loginStatus = {}; if (token) { loginStatus.status = 'connected'; - loginStatus.authResponse = {accessToken: token}; + loginStatus.authResponse = {accessToken:token}; } else { loginStatus.status = 'unknown'; } @@ -119,13 +122,13 @@ var openFB = (function () { redirectURL = runningInCordova ? cordovaOAuthRedirectURL : oauthRedirectURL; if (!fbAppId) { - return callback({status: 'unknown', error: 'Facebook App Id not set.'}); + return callback({ status:'unknown', error:'Facebook App Id not set.' }); } // Inappbrowser load start handler: Used when running in Cordova only function loginWindow_loadStartHandler(event) { var url = event.url; - if (url.indexOf("access_token=") > 0 || url.indexOf("error=") > 0) { + if (url.indexOf('access_token=') > 0 || url.indexOf('error=') > 0) { // When we get the access token fast, the login window (inappbrowser) is still opening with animation // in the Cordova app, and trying to close it while it's animating generates an exception. Wait a little... var timeout = 600 - (new Date().getTime() - startTime); @@ -140,7 +143,7 @@ var openFB = (function () { function loginWindow_exitHandler() { console.log('exit and remove listeners'); // Handle the situation where the user closes the login window manually before completing the login process - if (loginCallback && !loginProcessed) loginCallback({status: 'user_cancelled'}); + if (loginCallback && !loginProcessed) loginCallback({status:'user_cancelled'}); loginWindow.removeEventListener('loadstop', loginWindow_loadStopHandler); loginWindow.removeEventListener('exit', loginWindow_exitHandler); loginWindow = null; @@ -178,19 +181,20 @@ var openFB = (function () { // Parse the OAuth data received from Facebook var queryString, obj; - + loginProcessed = true; if (url.indexOf('access_token=') > 0) { queryString = url.substr(url.indexOf('#') + 1); obj = parseQueryString(queryString); tokenStore.fbAccessToken = obj['access_token']; - if (loginCallback) loginCallback({status: 'connected', authResponse: {accessToken:obj['access_token'], expiresIn:obj['expires_in'], signedRequest:obj['signed_request']}}); - } else if (url.indexOf("error=") > 0) { + authResponse = { accessToken:obj['access_token'], expiresIn:obj['expires_in'], signedRequest:obj['signed_request'], userID:null }; + if (loginCallback) loginCallback({ status:'connected', authResponse:authResponse }); + } else if (url.indexOf('error=') > 0) { queryString = url.substring(url.indexOf('?') + 1, url.indexOf('#')); obj = parseQueryString(queryString); - if (loginCallback) loginCallback({status: 'not_authorized', error: obj.error}); + if (loginCallback) loginCallback({status:'not_authorized', error: obj.error}); } else { - if (loginCallback) loginCallback({status: 'not_authorized'}); + if (loginCallback) loginCallback({status:'not_authorized'}); } } From 4613b6c260e2cc41e5a389efb9eb7ea1ffb69f66 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Mon, 22 Jun 2015 23:42:22 -0300 Subject: [PATCH 03/47] Update openfb.js --- openfb.js | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/openfb.js b/openfb.js index 79f6f19..ea0c215 100644 --- a/openfb.js +++ b/openfb.js @@ -98,7 +98,7 @@ var openFB = (function () { loginStatus = {}; if (token) { loginStatus.status = 'connected'; - loginStatus.authResponse = {accessToken:token}; + loginStatus.authResponse = authResponse; } else { loginStatus.status = 'unknown'; } @@ -187,7 +187,7 @@ var openFB = (function () { queryString = url.substr(url.indexOf('#') + 1); obj = parseQueryString(queryString); tokenStore.fbAccessToken = obj['access_token']; - authResponse = { accessToken:obj['access_token'], expiresIn:obj['expires_in'], signedRequest:obj['signed_request'], userID:null }; + authResponse = { accessToken:obj['access_token'], expiresIn:obj['expires_in'], signedRequest:obj['signed_request'], userID:decodeSignedRequest(obj['signed_request']).user_id }; if (loginCallback) loginCallback({ status:'connected', authResponse:authResponse }); } else if (url.indexOf('error=') > 0) { queryString = url.substring(url.indexOf('?') + 1, url.indexOf('#')); @@ -295,6 +295,51 @@ var openFB = (function () { } return parts.join("&"); } + + function base64Decode(data){ + var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, dec = '', tmp_arr = []; + if(!data){ + return data; + } + data += ''; + do{ // Unpack four hexets into three octets using index points in b64 + h1 = b64.indexOf(data.charAt(i++)); + h2 = b64.indexOf(data.charAt(i++)); + h3 = b64.indexOf(data.charAt(i++)); + h4 = b64.indexOf(data.charAt(i++)); + bits = h1 << 18 | h2 << 12 | h3 << 6 | h4; + o1 = bits >> 16 & 0xff; + o2 = bits >> 8 & 0xff; + o3 = bits & 0xff; + if(h3 == 64){ + tmp_arr[ac++] = String.fromCharCode(o1); + }else if (h4 == 64){ + tmp_arr[ac++] = String.fromCharCode(o1, o2); + }else{ + tmp_arr[ac++] = String.fromCharCode(o1, o2, o3); + } + } while(i < data.length); + dec = tmp_arr.join(''); + dec = this.utf8Decode(dec); + return dec; + } + + function decodeSignedRequest(signedRequest){ + signedRequest = signedRequest.split('.'); + var encodedSig = signedRequest[0]; + var payload = signedRequest[1]; + var sig = base64Decode(encodedSig); + payload = base64Decode(payload); + // Removing null character \0 from the JSON data + payload = payload.replace(/\0/g, ''); + var data = JSON.parse(payload); + if(data.algorithm.toUpperCase() != 'HMAC-SHA256'){ + return 'Unknown algorithm. Expected HMAC-SHA256'; + } + // TODO: Check signature! + return data; + } // The public API return { From de4bc6f68240b9c38ef2d2265d63d94f48f4d714 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Mon, 22 Jun 2015 23:43:39 -0300 Subject: [PATCH 04/47] Update openfb.js --- openfb.js | 596 +++++++++++++++++++++++++++--------------------------- 1 file changed, 298 insertions(+), 298 deletions(-) diff --git a/openfb.js b/openfb.js index ea0c215..ce692b2 100644 --- a/openfb.js +++ b/openfb.js @@ -9,294 +9,294 @@ */ var openFB = (function () { - var loginURL = 'https://www.facebook.com/dialog/oauth', - - logoutURL = 'https://www.facebook.com/logout.php', - - // By default we store fbtoken in sessionStorage. This can be overridden in init() - tokenStore = window.sessionStorage, - - // The Facebook App Id. Required. Set using init(). - fbAppId, - - context = window.location.pathname.substring(0, window.location.pathname.lastIndexOf("/")), - - baseURL = location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : '') + context, - - // Default OAuth redirect URL. Can be overriden in init() - oauthRedirectURL = baseURL + '/oauthcallback.html', - - // Default Cordova OAuth redirect URL. Can be overriden in init() - cordovaOAuthRedirectURL = "https://www.facebook.com/connect/login_success.html", - - // Default Logout redirect URL. Can be overriden in init() - logoutRedirectURL = baseURL + '/logoutcallback.html', - - // Because the OAuth login spans multiple processes, we need to keep the login callback function as a variable - // inside the module instead of keeping it local within the login function. - loginCallback, - - // Indicates if the app is running inside Cordova - runningInCordova, - - // Used in the exit event handler to identify if the login has already been processed elsewhere (in the oauthCallback function) - loginProcessed, - - // The current authResponse object if available, null otherwise - authResponse = null; - - // MAKE SURE YOU INCLUDE IN YOUR index.html, OTHERWISE runningInCordova will always by false. - // You don't need to (and should not) add the actual cordova.js file to your file system: it will be added automatically - // by the Cordova build process - document.addEventListener("deviceready", function () { - runningInCordova = true; - }, false); - - /** - * Initialize the OpenFB module. You must use this function and initialize the module with an appId before you can - * use any other function. - * @param params - init paramters - * appId: (Required) The id of the Facebook app, - * tokenStore: (optional) The store used to save the Facebook token. If not provided, we use sessionStorage. - * loginURL: (optional) The OAuth login URL. Defaults to https://www.facebook.com/dialog/oauth. - * logoutURL: (optional) The logout URL. Defaults to https://www.facebook.com/logout.php. - * oauthRedirectURL: (optional) The OAuth redirect URL. Defaults to [baseURL]/oauthcallback.html. - * cordovaOAuthRedirectURL: (optional) The OAuth redirect URL. Defaults to https://www.facebook.com/connect/login_success.html. - * logoutRedirectURL: (optional) The logout redirect URL. Defaults to [baseURL]/logoutcallback.html. - * accessToken: (optional) An already authenticated access token. - */ - function init(params) { - - if (params.appId) { - fbAppId = params.appId; - } else { - throw 'appId parameter not set in init()'; - } - - if (params.tokenStore) { - tokenStore = params.tokenStore; - } - - if (params.accessToken) { - tokenStore.fbAccessToken = params.accessToken; - } - - loginURL = params.loginURL || loginURL; - logoutURL = params.logoutURL || logoutURL; - oauthRedirectURL = params.oauthRedirectURL || oauthRedirectURL; - cordovaOAuthRedirectURL = params.cordovaOAuthRedirectURL || cordovaOAuthRedirectURL; - logoutRedirectURL = params.logoutRedirectURL || logoutRedirectURL; - - } - - /** - * Checks if the user has logged in with openFB and currently has a session api token. - * @param callback the function that receives the loginstatus - */ - function getLoginStatus(callback) { - var token = tokenStore.fbAccessToken, - loginStatus = {}; - if (token) { - loginStatus.status = 'connected'; - loginStatus.authResponse = authResponse; - } else { - loginStatus.status = 'unknown'; - } - if (callback) callback(loginStatus); - } - - /** - * Login to Facebook using OAuth. If running in a Browser, the OAuth workflow happens in a a popup window. - * If running in Cordova container, it happens using the In-App Browser. Don't forget to install the In-App Browser - * plugin in your Cordova project: cordova plugins add org.apache.cordova.inappbrowser. - * - * @param callback - Callback function to invoke when the login process succeeds - * @param options - options.scope: The set of Facebook permissions requested - * @returns {*} - */ - function login(callback, options) { - - var loginWindow, - startTime, - scope = '', - redirectURL = runningInCordova ? cordovaOAuthRedirectURL : oauthRedirectURL; - - if (!fbAppId) { - return callback({ status:'unknown', error:'Facebook App Id not set.' }); - } - - // Inappbrowser load start handler: Used when running in Cordova only - function loginWindow_loadStartHandler(event) { - var url = event.url; - if (url.indexOf('access_token=') > 0 || url.indexOf('error=') > 0) { - // When we get the access token fast, the login window (inappbrowser) is still opening with animation - // in the Cordova app, and trying to close it while it's animating generates an exception. Wait a little... - var timeout = 600 - (new Date().getTime() - startTime); - setTimeout(function () { - loginWindow.close(); - }, timeout > 0 ? timeout : 0); - oauthCallback(url); - } - } - - // Inappbrowser exit handler: Used when running in Cordova only - function loginWindow_exitHandler() { - console.log('exit and remove listeners'); - // Handle the situation where the user closes the login window manually before completing the login process - if (loginCallback && !loginProcessed) loginCallback({status:'user_cancelled'}); - loginWindow.removeEventListener('loadstop', loginWindow_loadStopHandler); - loginWindow.removeEventListener('exit', loginWindow_exitHandler); - loginWindow = null; - console.log('done removing listeners'); - } - - if (options && options.scope) { - scope = options.scope; - } - - loginCallback = callback; - loginProcessed = false; - - startTime = new Date().getTime(); - loginWindow = window.open(loginURL + '?client_id=' + fbAppId + '&redirect_uri=' + redirectURL + - '&response_type=token,signed_request,code&scope=' + scope, '_blank', 'location=no,clearcache=yes'); - - // If the app is running in Cordova, listen to URL changes in the InAppBrowser until we get a URL with an access_token or an error - if (runningInCordova) { - loginWindow.addEventListener('loadstart', loginWindow_loadStartHandler); - loginWindow.addEventListener('exit', loginWindow_exitHandler); - } - // Note: if the app is running in the browser the loginWindow dialog will call back by invoking the - // oauthCallback() function. See oauthcallback.html for details. - - } - - /** - * Called either by oauthcallback.html (when the app is running the browser) or by the loginWindow loadstart event - * handler defined in the login() function (when the app is running in the Cordova/PhoneGap container). - * @param url - The oautchRedictURL called by Facebook with the access_token in the querystring at the ned of the - * OAuth workflow. - */ - function oauthCallback(url) { - // Parse the OAuth data received from Facebook - var queryString, - obj; - - loginProcessed = true; - if (url.indexOf('access_token=') > 0) { - queryString = url.substr(url.indexOf('#') + 1); - obj = parseQueryString(queryString); - tokenStore.fbAccessToken = obj['access_token']; - authResponse = { accessToken:obj['access_token'], expiresIn:obj['expires_in'], signedRequest:obj['signed_request'], userID:decodeSignedRequest(obj['signed_request']).user_id }; - if (loginCallback) loginCallback({ status:'connected', authResponse:authResponse }); - } else if (url.indexOf('error=') > 0) { - queryString = url.substring(url.indexOf('?') + 1, url.indexOf('#')); - obj = parseQueryString(queryString); - if (loginCallback) loginCallback({status:'not_authorized', error: obj.error}); - } else { - if (loginCallback) loginCallback({status:'not_authorized'}); - } - } - - /** - * Logout from Facebook, and remove the token. - * IMPORTANT: For the Facebook logout to work, the logoutRedirectURL must be on the domain specified in "Site URL" in your Facebook App Settings - * - */ - function logout(callback) { - var logoutWindow, - token = tokenStore.fbAccessToken; - - /* Remove token. Will fail silently if does not exist */ - tokenStore.removeItem('fbtoken'); - - if (token) { - logoutWindow = window.open(logoutURL + '?access_token=' + token + '&next=' + logoutRedirectURL, '_blank', 'location=no,clearcache=yes'); - if (runningInCordova) { - setTimeout(function() { - logoutWindow.close(); - }, 700); - } - } - - if (callback) { - callback(); - } - - } - - /** - * Lets you make any Facebook Graph API request. - * @param obj - Request configuration object. Can include: - * method: HTTP method: GET, POST, etc. Optional - Default is 'GET' - * path: path in the Facebook graph: /me, /me.friends, etc. - Required - * params: queryString parameters as a map - Optional - * success: callback function when operation succeeds - Optional - * error: callback function when operation fails - Optional - */ - function api(obj) { - - var method = obj.method || 'GET', - params = obj.params || {}, - xhr = new XMLHttpRequest(), - url; - - params['access_token'] = tokenStore.fbAccessToken; - - url = 'https://graph.facebook.com' + obj.path + '?' + toQueryString(params); - - xhr.onreadystatechange = function () { - if (xhr.readyState === 4) { - if (xhr.status === 200) { - if (obj.success) obj.success(JSON.parse(xhr.responseText)); - } else { - var error = xhr.responseText ? JSON.parse(xhr.responseText).error : {message: 'An error has occurred'}; - if (obj.error) obj.error(error); - } - } - }; - - xhr.open(method, url, true); - xhr.send(); - } - - /** - * Helper function to de-authorize the app - * @param success - * @param error - * @returns {*} - */ - function revokePermissions(success, error) { - return api({method: 'DELETE', - path: '/me/permissions', - success: function () { - success(); - }, - error: error}); - } - - function parseQueryString(queryString) { - var qs = decodeURIComponent(queryString), - obj = {}, - params = qs.split('&'); - params.forEach(function (param) { - var splitter = param.split('='); - obj[splitter[0]] = splitter[1]; - }); - return obj; - } - - function toQueryString(obj) { - var parts = []; - for (var i in obj) { - if (obj.hasOwnProperty(i)) { - parts.push(encodeURIComponent(i) + "=" + encodeURIComponent(obj[i])); - } - } - return parts.join("&"); - } - - function base64Decode(data){ + var loginURL = 'https://www.facebook.com/dialog/oauth', + + logoutURL = 'https://www.facebook.com/logout.php', + + // By default we store fbtoken in sessionStorage. This can be overridden in init() + tokenStore = window.sessionStorage, + + // The Facebook App Id. Required. Set using init(). + fbAppId, + + context = window.location.pathname.substring(0, window.location.pathname.lastIndexOf("/")), + + baseURL = location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : '') + context, + + // Default OAuth redirect URL. Can be overriden in init() + oauthRedirectURL = baseURL + '/oauthcallback.html', + + // Default Cordova OAuth redirect URL. Can be overriden in init() + cordovaOAuthRedirectURL = "https://www.facebook.com/connect/login_success.html", + + // Default Logout redirect URL. Can be overriden in init() + logoutRedirectURL = baseURL + '/logoutcallback.html', + + // Because the OAuth login spans multiple processes, we need to keep the login callback function as a variable + // inside the module instead of keeping it local within the login function. + loginCallback, + + // Indicates if the app is running inside Cordova + runningInCordova, + + // Used in the exit event handler to identify if the login has already been processed elsewhere (in the oauthCallback function) + loginProcessed, + + // The current authResponse object if available, null otherwise + authResponse = null; + + // MAKE SURE YOU INCLUDE IN YOUR index.html, OTHERWISE runningInCordova will always by false. + // You don't need to (and should not) add the actual cordova.js file to your file system: it will be added automatically + // by the Cordova build process + document.addEventListener("deviceready", function () { + runningInCordova = true; + }, false); + + /** + * Initialize the OpenFB module. You must use this function and initialize the module with an appId before you can + * use any other function. + * @param params - init paramters + * appId: (Required) The id of the Facebook app, + * tokenStore: (optional) The store used to save the Facebook token. If not provided, we use sessionStorage. + * loginURL: (optional) The OAuth login URL. Defaults to https://www.facebook.com/dialog/oauth. + * logoutURL: (optional) The logout URL. Defaults to https://www.facebook.com/logout.php. + * oauthRedirectURL: (optional) The OAuth redirect URL. Defaults to [baseURL]/oauthcallback.html. + * cordovaOAuthRedirectURL: (optional) The OAuth redirect URL. Defaults to https://www.facebook.com/connect/login_success.html. + * logoutRedirectURL: (optional) The logout redirect URL. Defaults to [baseURL]/logoutcallback.html. + * accessToken: (optional) An already authenticated access token. + */ + function init(params) { + + if (params.appId) { + fbAppId = params.appId; + } else { + throw 'appId parameter not set in init()'; + } + + if (params.tokenStore) { + tokenStore = params.tokenStore; + } + + if (params.accessToken) { + tokenStore.fbAccessToken = params.accessToken; + } + + loginURL = params.loginURL || loginURL; + logoutURL = params.logoutURL || logoutURL; + oauthRedirectURL = params.oauthRedirectURL || oauthRedirectURL; + cordovaOAuthRedirectURL = params.cordovaOAuthRedirectURL || cordovaOAuthRedirectURL; + logoutRedirectURL = params.logoutRedirectURL || logoutRedirectURL; + + } + + /** + * Checks if the user has logged in with openFB and currently has a session api token. + * @param callback the function that receives the loginstatus + */ + function getLoginStatus(callback) { + var token = tokenStore.fbAccessToken, + loginStatus = {}; + if (token) { + loginStatus.status = 'connected'; + loginStatus.authResponse = authResponse; + } else { + loginStatus.status = 'unknown'; + } + if (callback) callback(loginStatus); + } + + /** + * Login to Facebook using OAuth. If running in a Browser, the OAuth workflow happens in a a popup window. + * If running in Cordova container, it happens using the In-App Browser. Don't forget to install the In-App Browser + * plugin in your Cordova project: cordova plugins add org.apache.cordova.inappbrowser. + * + * @param callback - Callback function to invoke when the login process succeeds + * @param options - options.scope: The set of Facebook permissions requested + * @returns {*} + */ + function login(callback, options) { + + var loginWindow, + startTime, + scope = '', + redirectURL = runningInCordova ? cordovaOAuthRedirectURL : oauthRedirectURL; + + if (!fbAppId) { + return callback({ status:'unknown', error:'Facebook App Id not set.' }); + } + + // Inappbrowser load start handler: Used when running in Cordova only + function loginWindow_loadStartHandler(event) { + var url = event.url; + if (url.indexOf('access_token=') > 0 || url.indexOf('error=') > 0) { + // When we get the access token fast, the login window (inappbrowser) is still opening with animation + // in the Cordova app, and trying to close it while it's animating generates an exception. Wait a little... + var timeout = 600 - (new Date().getTime() - startTime); + setTimeout(function () { + loginWindow.close(); + }, timeout > 0 ? timeout : 0); + oauthCallback(url); + } + } + + // Inappbrowser exit handler: Used when running in Cordova only + function loginWindow_exitHandler() { + console.log('exit and remove listeners'); + // Handle the situation where the user closes the login window manually before completing the login process + if (loginCallback && !loginProcessed) loginCallback({status:'user_cancelled'}); + loginWindow.removeEventListener('loadstop', loginWindow_loadStopHandler); + loginWindow.removeEventListener('exit', loginWindow_exitHandler); + loginWindow = null; + console.log('done removing listeners'); + } + + if (options && options.scope) { + scope = options.scope; + } + + loginCallback = callback; + loginProcessed = false; + + startTime = new Date().getTime(); + loginWindow = window.open(loginURL + '?client_id=' + fbAppId + '&redirect_uri=' + redirectURL + + '&response_type=token,signed_request,code&scope=' + scope, '_blank', 'location=no,clearcache=yes'); + + // If the app is running in Cordova, listen to URL changes in the InAppBrowser until we get a URL with an access_token or an error + if (runningInCordova) { + loginWindow.addEventListener('loadstart', loginWindow_loadStartHandler); + loginWindow.addEventListener('exit', loginWindow_exitHandler); + } + // Note: if the app is running in the browser the loginWindow dialog will call back by invoking the + // oauthCallback() function. See oauthcallback.html for details. + + } + + /** + * Called either by oauthcallback.html (when the app is running the browser) or by the loginWindow loadstart event + * handler defined in the login() function (when the app is running in the Cordova/PhoneGap container). + * @param url - The oautchRedictURL called by Facebook with the access_token in the querystring at the ned of the + * OAuth workflow. + */ + function oauthCallback(url) { + // Parse the OAuth data received from Facebook + var queryString, + obj; + + loginProcessed = true; + if (url.indexOf('access_token=') > 0) { + queryString = url.substr(url.indexOf('#') + 1); + obj = parseQueryString(queryString); + tokenStore.fbAccessToken = obj['access_token']; + authResponse = { accessToken:obj['access_token'], expiresIn:obj['expires_in'], signedRequest:obj['signed_request'], userID:decodeSignedRequest(obj['signed_request']).user_id }; + if (loginCallback) loginCallback({ status:'connected', authResponse:authResponse }); + } else if (url.indexOf('error=') > 0) { + queryString = url.substring(url.indexOf('?') + 1, url.indexOf('#')); + obj = parseQueryString(queryString); + if (loginCallback) loginCallback({status:'not_authorized', error: obj.error}); + } else { + if (loginCallback) loginCallback({status:'not_authorized'}); + } + } + + /** + * Logout from Facebook, and remove the token. + * IMPORTANT: For the Facebook logout to work, the logoutRedirectURL must be on the domain specified in "Site URL" in your Facebook App Settings + * + */ + function logout(callback) { + var logoutWindow, + token = tokenStore.fbAccessToken; + + /* Remove token. Will fail silently if does not exist */ + tokenStore.removeItem('fbtoken'); + + if (token) { + logoutWindow = window.open(logoutURL + '?access_token=' + token + '&next=' + logoutRedirectURL, '_blank', 'location=no,clearcache=yes'); + if (runningInCordova) { + setTimeout(function() { + logoutWindow.close(); + }, 700); + } + } + + if (callback) { + callback(); + } + + } + + /** + * Lets you make any Facebook Graph API request. + * @param obj - Request configuration object. Can include: + * method: HTTP method: GET, POST, etc. Optional - Default is 'GET' + * path: path in the Facebook graph: /me, /me.friends, etc. - Required + * params: queryString parameters as a map - Optional + * success: callback function when operation succeeds - Optional + * error: callback function when operation fails - Optional + */ + function api(obj) { + + var method = obj.method || 'GET', + params = obj.params || {}, + xhr = new XMLHttpRequest(), + url; + + params['access_token'] = tokenStore.fbAccessToken; + + url = 'https://graph.facebook.com' + obj.path + '?' + toQueryString(params); + + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + if (xhr.status === 200) { + if (obj.success) obj.success(JSON.parse(xhr.responseText)); + } else { + var error = xhr.responseText ? JSON.parse(xhr.responseText).error : {message: 'An error has occurred'}; + if (obj.error) obj.error(error); + } + } + }; + + xhr.open(method, url, true); + xhr.send(); + } + + /** + * Helper function to de-authorize the app + * @param success + * @param error + * @returns {*} + */ + function revokePermissions(success, error) { + return api({method: 'DELETE', + path: '/me/permissions', + success: function () { + success(); + }, + error: error}); + } + + function parseQueryString(queryString) { + var qs = decodeURIComponent(queryString), + obj = {}, + params = qs.split('&'); + params.forEach(function (param) { + var splitter = param.split('='); + obj[splitter[0]] = splitter[1]; + }); + return obj; + } + + function toQueryString(obj) { + var parts = []; + for (var i in obj) { + if (obj.hasOwnProperty(i)) { + parts.push(encodeURIComponent(i) + "=" + encodeURIComponent(obj[i])); + } + } + return parts.join("&"); + } + + function base64Decode(data){ var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, dec = '', tmp_arr = []; if(!data){ @@ -341,15 +341,15 @@ var openFB = (function () { return data; } - // The public API - return { - init: init, - login: login, - logout: logout, - revokePermissions: revokePermissions, - api: api, - oauthCallback: oauthCallback, - getLoginStatus: getLoginStatus - } + // The public API + return { + init: init, + login: login, + logout: logout, + revokePermissions: revokePermissions, + api: api, + oauthCallback: oauthCallback, + getLoginStatus: getLoginStatus + } }()); From 26aba33eb0205915f0c77767ff5a7f91918cad4f Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Mon, 22 Jun 2015 23:46:03 -0300 Subject: [PATCH 05/47] Update openfb.js --- openfb.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openfb.js b/openfb.js index ce692b2..493ad8e 100644 --- a/openfb.js +++ b/openfb.js @@ -197,6 +197,11 @@ var openFB = (function () { if (loginCallback) loginCallback({status:'not_authorized'}); } } + + function getAuthResponse(callback){ + typeof callback === 'function' && callback(authResponse); + return authResponse; + } /** * Logout from Facebook, and remove the token. @@ -346,6 +351,7 @@ var openFB = (function () { init: init, login: login, logout: logout, + getAuthResponse: getAuthResponse, revokePermissions: revokePermissions, api: api, oauthCallback: oauthCallback, From 01fd6f24c61ecdcb71e14df511fcaeb2b2463a3d Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Tue, 23 Jun 2015 00:01:02 -0300 Subject: [PATCH 06/47] Update openfb.js --- openfb.js | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/openfb.js b/openfb.js index 493ad8e..3b04e03 100644 --- a/openfb.js +++ b/openfb.js @@ -13,13 +13,15 @@ var openFB = (function () { logoutURL = 'https://www.facebook.com/logout.php', + authResponse = null, + // By default we store fbtoken in sessionStorage. This can be overridden in init() tokenStore = window.sessionStorage, // The Facebook App Id. Required. Set using init(). fbAppId, - context = window.location.pathname.substring(0, window.location.pathname.lastIndexOf("/")), + context = window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')), baseURL = location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : '') + context, @@ -27,7 +29,7 @@ var openFB = (function () { oauthRedirectURL = baseURL + '/oauthcallback.html', // Default Cordova OAuth redirect URL. Can be overriden in init() - cordovaOAuthRedirectURL = "https://www.facebook.com/connect/login_success.html", + cordovaOAuthRedirectURL = 'https://www.facebook.com/connect/login_success.html', // Default Logout redirect URL. Can be overriden in init() logoutRedirectURL = baseURL + '/logoutcallback.html', @@ -40,15 +42,12 @@ var openFB = (function () { runningInCordova, // Used in the exit event handler to identify if the login has already been processed elsewhere (in the oauthCallback function) - loginProcessed, - - // The current authResponse object if available, null otherwise - authResponse = null; + loginProcessed; // MAKE SURE YOU INCLUDE IN YOUR index.html, OTHERWISE runningInCordova will always by false. // You don't need to (and should not) add the actual cordova.js file to your file system: it will be added automatically // by the Cordova build process - document.addEventListener("deviceready", function () { + document.addEventListener('deviceready', function () { runningInCordova = true; }, false); @@ -295,10 +294,10 @@ var openFB = (function () { var parts = []; for (var i in obj) { if (obj.hasOwnProperty(i)) { - parts.push(encodeURIComponent(i) + "=" + encodeURIComponent(obj[i])); + parts.push(encodeURIComponent(i) + '=' + encodeURIComponent(obj[i])); } } - return parts.join("&"); + return parts.join('&'); } function base64Decode(data){ @@ -357,5 +356,4 @@ var openFB = (function () { oauthCallback: oauthCallback, getLoginStatus: getLoginStatus } - }()); From 5c250f508cb2e6a95ccbb0283a1886b70d0f1cb2 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Tue, 23 Jun 2015 00:04:36 -0300 Subject: [PATCH 07/47] Update openfb.js --- openfb.js | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/openfb.js b/openfb.js index 3b04e03..84f59c3 100644 --- a/openfb.js +++ b/openfb.js @@ -300,6 +300,28 @@ var openFB = (function () { return parts.join('&'); } + function utf8Decode(str_data){ + var tmp_arr = [], i = 0, ac = 0, c1 = 0, c2 = 0, c3 = 0; + str_data += ''; + while (i < str_data.length) { + c1 = str_data.charCodeAt(i); + if(c1 < 128){ + tmp_arr[ac++] = String.fromCharCode(c1); + i++; + }else if (c1 > 191 && c1 < 224){ + c2 = str_data.charCodeAt(i + 1); + tmp_arr[ac++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63)); + i += 2; + }else{ + c2 = str_data.charCodeAt(i + 1); + c3 = str_data.charCodeAt(i + 2); + tmp_arr[ac++] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); + i += 3; + } + } + return tmp_arr.join(''); + } + function base64Decode(data){ var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, dec = '', tmp_arr = []; @@ -325,7 +347,7 @@ var openFB = (function () { } } while(i < data.length); dec = tmp_arr.join(''); - dec = this.utf8Decode(dec); + dec = utf8Decode(dec); return dec; } From 2298f9319274dc3891367c649b78d1801622f059 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Tue, 23 Jun 2015 00:47:33 -0300 Subject: [PATCH 08/47] Update ngopenfb.js --- ngopenfb.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ngopenfb.js b/ngopenfb.js index 4da909b..bbc4fff 100644 --- a/ngopenfb.js +++ b/ngopenfb.js @@ -68,6 +68,10 @@ angular.module('ngOpenFB', []) ); return deferred.promise; } + + function getAuthResponse(callback) { + return $window.openFB.getAuthResponse(callback); + } return { init: init, @@ -75,7 +79,8 @@ angular.module('ngOpenFB', []) logout: logout, revokePermissions: revokePermissions, api: api, - getLoginStatus: getLoginStatus + getLoginStatus: getLoginStatus, + getAuthResponse: getAuthResponse }; - }); \ No newline at end of file + }); From beabe04318d607be048c4d77875738b2100a9924 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Tue, 30 Jun 2015 18:50:30 -0300 Subject: [PATCH 09/47] Update openfb.js --- openfb.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/openfb.js b/openfb.js index 84f59c3..2e7046f 100644 --- a/openfb.js +++ b/openfb.js @@ -39,18 +39,11 @@ var openFB = (function () { loginCallback, // Indicates if the app is running inside Cordova - runningInCordova, + runningInCordova = !/^(http(s)?:\/\/)/g.test(window.document.URL), // Used in the exit event handler to identify if the login has already been processed elsewhere (in the oauthCallback function) loginProcessed; - // MAKE SURE YOU INCLUDE IN YOUR index.html, OTHERWISE runningInCordova will always by false. - // You don't need to (and should not) add the actual cordova.js file to your file system: it will be added automatically - // by the Cordova build process - document.addEventListener('deviceready', function () { - runningInCordova = true; - }, false); - /** * Initialize the OpenFB module. You must use this function and initialize the module with an appId before you can * use any other function. From ca53d2b800afe88571fc8d3b265e1c72d9cabce8 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Wed, 1 Jul 2015 14:37:05 -0300 Subject: [PATCH 10/47] Update logout --- openfb.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/openfb.js b/openfb.js index 2e7046f..411d5e8 100644 --- a/openfb.js +++ b/openfb.js @@ -42,7 +42,10 @@ var openFB = (function () { runningInCordova = !/^(http(s)?:\/\/)/g.test(window.document.URL), // Used in the exit event handler to identify if the login has already been processed elsewhere (in the oauthCallback function) - loginProcessed; + loginProcessed, + + // Used in the exit event handler to identify if the logout has already been processed elsewhere (in the logoutCallback function) + logoutProcessed; /** * Initialize the OpenFB module. You must use this function and initialize the module with an appId before you can @@ -175,6 +178,7 @@ var openFB = (function () { obj; loginProcessed = true; + logoutProcessed = false; if (url.indexOf('access_token=') > 0) { queryString = url.substr(url.indexOf('#') + 1); obj = parseQueryString(queryString); @@ -207,8 +211,9 @@ var openFB = (function () { /* Remove token. Will fail silently if does not exist */ tokenStore.removeItem('fbtoken'); - if (token) { - logoutWindow = window.open(logoutURL + '?access_token=' + token + '&next=' + logoutRedirectURL, '_blank', 'location=no,clearcache=yes'); + if (token && !logoutProcessed) { + logoutProcessed = true; + logoutWindow = window.open(logoutURL + '?confirm=1&access_token=' + token + '&next=' + logoutRedirectURL, '_blank', 'location=no,clearcache=yes'); if (runningInCordova) { setTimeout(function() { logoutWindow.close(); From a91cb8c61fda65188bf87b215e7599762195f9ce Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Wed, 1 Jul 2015 15:06:47 -0300 Subject: [PATCH 11/47] Update logout doc --- openfb.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfb.js b/openfb.js index 411d5e8..059f423 100644 --- a/openfb.js +++ b/openfb.js @@ -202,7 +202,7 @@ var openFB = (function () { /** * Logout from Facebook, and remove the token. * IMPORTANT: For the Facebook logout to work, the logoutRedirectURL must be on the domain specified in "Site URL" in your Facebook App Settings - * + * e.g: https://rawgit.com/ccoenraets/OpenFB/master/logoutcallback.html */ function logout(callback) { var logoutWindow, From e0bd85de68b0f1654a6562f71f64a9ff57c19ad1 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Wed, 1 Jul 2015 17:35:48 -0300 Subject: [PATCH 12/47] keep logged after application has been closed --- openfb.js | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/openfb.js b/openfb.js index 059f423..a020b91 100644 --- a/openfb.js +++ b/openfb.js @@ -58,10 +58,8 @@ var openFB = (function () { * oauthRedirectURL: (optional) The OAuth redirect URL. Defaults to [baseURL]/oauthcallback.html. * cordovaOAuthRedirectURL: (optional) The OAuth redirect URL. Defaults to https://www.facebook.com/connect/login_success.html. * logoutRedirectURL: (optional) The logout redirect URL. Defaults to [baseURL]/logoutcallback.html. - * accessToken: (optional) An already authenticated access token. */ function init(params) { - if (params.appId) { fbAppId = params.appId; } else { @@ -72,8 +70,9 @@ var openFB = (function () { tokenStore = params.tokenStore; } - if (params.accessToken) { - tokenStore.fbAccessToken = params.accessToken; + // keep running after application has been closed + if(window.localStorage.fbAuthResponse){ + authResponse = JSON.parse(window.localStorage.fbAuthResponse); } loginURL = params.loginURL || loginURL; @@ -81,7 +80,6 @@ var openFB = (function () { oauthRedirectURL = params.oauthRedirectURL || oauthRedirectURL; cordovaOAuthRedirectURL = params.cordovaOAuthRedirectURL || cordovaOAuthRedirectURL; logoutRedirectURL = params.logoutRedirectURL || logoutRedirectURL; - } /** @@ -89,7 +87,7 @@ var openFB = (function () { * @param callback the function that receives the loginstatus */ function getLoginStatus(callback) { - var token = tokenStore.fbAccessToken, + var token = authResponse ? authResponse.accessToken : null, loginStatus = {}; if (token) { loginStatus.status = 'connected'; @@ -182,8 +180,9 @@ var openFB = (function () { if (url.indexOf('access_token=') > 0) { queryString = url.substr(url.indexOf('#') + 1); obj = parseQueryString(queryString); - tokenStore.fbAccessToken = obj['access_token']; authResponse = { accessToken:obj['access_token'], expiresIn:obj['expires_in'], signedRequest:obj['signed_request'], userID:decodeSignedRequest(obj['signed_request']).user_id }; + // TODO: Guardar em cookie como `FB` e não em storage, por questões de segurança. + window.localStorage.fbAuthResponse = JSON.stringify(authResponse); if (loginCallback) loginCallback({ status:'connected', authResponse:authResponse }); } else if (url.indexOf('error=') > 0) { queryString = url.substring(url.indexOf('?') + 1, url.indexOf('#')); @@ -202,11 +201,11 @@ var openFB = (function () { /** * Logout from Facebook, and remove the token. * IMPORTANT: For the Facebook logout to work, the logoutRedirectURL must be on the domain specified in "Site URL" in your Facebook App Settings - * e.g: https://rawgit.com/ccoenraets/OpenFB/master/logoutcallback.html + * */ function logout(callback) { var logoutWindow, - token = tokenStore.fbAccessToken; + token = authResponse ? authResponse.accessToken : null; /* Remove token. Will fail silently if does not exist */ tokenStore.removeItem('fbtoken'); @@ -243,7 +242,7 @@ var openFB = (function () { xhr = new XMLHttpRequest(), url; - params['access_token'] = tokenStore.fbAccessToken; + params['access_token'] = authResponse ? authResponse.accessToken : null; url = 'https://graph.facebook.com' + obj.path + '?' + toQueryString(params); From afa96355ff529983af1f9fa6334fcd5c99b68944 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Wed, 1 Jul 2015 18:56:37 -0300 Subject: [PATCH 13/47] access_token validation --- openfb.js | 56 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/openfb.js b/openfb.js index a020b91..78b4ebe 100644 --- a/openfb.js +++ b/openfb.js @@ -18,8 +18,9 @@ var openFB = (function () { // By default we store fbtoken in sessionStorage. This can be overridden in init() tokenStore = window.sessionStorage, - // The Facebook App Id. Required. Set using init(). + // The Facebook App Id and/or Secret. Required. Set using init(). fbAppId, + fbAppSecret, context = window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')), @@ -66,6 +67,12 @@ var openFB = (function () { throw 'appId parameter not set in init()'; } + if (params.appSecret) { + fbAppSecret = params.appSecret; + } else { + throw 'secretId parameter not set in init()'; + } + if (params.tokenStore) { tokenStore = params.tokenStore; } @@ -82,6 +89,21 @@ var openFB = (function () { logoutRedirectURL = params.logoutRedirectURL || logoutRedirectURL; } + /** + * Inspecting access tokens + */ + function debugToken(tokenToInspect, appTokenOrAdminToken, callback){ + graph({ path:'/debug_token', + params: { input_token:tokenToInspect, access_token:appTokenOrAdminToken }, + success:function(response){ + if (callback) callback(response.data||{}); + }, + error:function(error){ + if (callback) callback({}); + } + }); + } + /** * Checks if the user has logged in with openFB and currently has a session api token. * @param callback the function that receives the loginstatus @@ -90,12 +112,20 @@ var openFB = (function () { var token = authResponse ? authResponse.accessToken : null, loginStatus = {}; if (token) { - loginStatus.status = 'connected'; - loginStatus.authResponse = authResponse; + debugToken(token, fbAppId+'|'+fbAppSecret, function(response){ + if(response.is_valid) { + loginStatus.status = 'connected'; + loginStatus.authResponse = authResponse; + } else { + loginStatus.status = 'unknown'; + authResponse = null; + } + if (callback) callback(loginStatus); + }); } else { loginStatus.status = 'unknown'; + if (callback) callback(loginStatus); } - if (callback) callback(loginStatus); } /** @@ -236,16 +266,27 @@ var openFB = (function () { * error: callback function when operation fails - Optional */ function api(obj) { + obj.params = obj.params || {}; + obj.params['access_token'] = authResponse ? authResponse.accessToken : null; + graph(obj); + } + /** + * Graph API + * @param obj - Request configuration object. Can include: + * method: HTTP method: GET, POST, etc. Optional - Default is 'GET' + * path: path in the Facebook graph: /me, /me.friends, etc. - Required + * params: queryString parameters as a map - Optional + * success: callback function when operation succeeds - Optional + * error: callback function when operation fails - Optional + */ + function graph(obj) { var method = obj.method || 'GET', params = obj.params || {}, xhr = new XMLHttpRequest(), url; - params['access_token'] = authResponse ? authResponse.accessToken : null; - url = 'https://graph.facebook.com' + obj.path + '?' + toQueryString(params); - xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status === 200) { @@ -372,6 +413,7 @@ var openFB = (function () { getAuthResponse: getAuthResponse, revokePermissions: revokePermissions, api: api, + graph: graph, oauthCallback: oauthCallback, getLoginStatus: getLoginStatus } From e3b78b514f1a38c7a4fcfcb3a3bab8e1855a2303 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Wed, 1 Jul 2015 19:43:59 -0300 Subject: [PATCH 14/47] optional storage --- openfb.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/openfb.js b/openfb.js index 78b4ebe..0c12cba 100644 --- a/openfb.js +++ b/openfb.js @@ -78,8 +78,8 @@ var openFB = (function () { } // keep running after application has been closed - if(window.localStorage.fbAuthResponse){ - authResponse = JSON.parse(window.localStorage.fbAuthResponse); + if(tokenStore.fbAuthResponse){ + authResponse = JSON.parse(tokenStore.fbAuthResponse); } loginURL = params.loginURL || loginURL; @@ -211,8 +211,7 @@ var openFB = (function () { queryString = url.substr(url.indexOf('#') + 1); obj = parseQueryString(queryString); authResponse = { accessToken:obj['access_token'], expiresIn:obj['expires_in'], signedRequest:obj['signed_request'], userID:decodeSignedRequest(obj['signed_request']).user_id }; - // TODO: Guardar em cookie como `FB` e não em storage, por questões de segurança. - window.localStorage.fbAuthResponse = JSON.stringify(authResponse); + tokenStore.fbAuthResponse = JSON.stringify(authResponse); if (loginCallback) loginCallback({ status:'connected', authResponse:authResponse }); } else if (url.indexOf('error=') > 0) { queryString = url.substring(url.indexOf('?') + 1, url.indexOf('#')); @@ -231,14 +230,16 @@ var openFB = (function () { /** * Logout from Facebook, and remove the token. * IMPORTANT: For the Facebook logout to work, the logoutRedirectURL must be on the domain specified in "Site URL" in your Facebook App Settings - * + * e.g. https://rawgit.com/ccoenraets/OpenFB/master/logoutcallback.html */ function logout(callback) { var logoutWindow, token = authResponse ? authResponse.accessToken : null; /* Remove token. Will fail silently if does not exist */ + tokenStore.removeItem('fbAuthResponse'); tokenStore.removeItem('fbtoken'); + authResponse = null; if (token && !logoutProcessed) { logoutProcessed = true; @@ -287,6 +288,7 @@ var openFB = (function () { url; url = 'https://graph.facebook.com' + obj.path + '?' + toQueryString(params); + xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status === 200) { From cd4c3557879c6165993521c80d9414d6a6a27a7a Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Thu, 2 Jul 2015 08:26:07 -0300 Subject: [PATCH 15/47] Update openfb.js --- openfb.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openfb.js b/openfb.js index 0c12cba..8d3e7c1 100644 --- a/openfb.js +++ b/openfb.js @@ -117,7 +117,9 @@ var openFB = (function () { loginStatus.status = 'connected'; loginStatus.authResponse = authResponse; } else { - loginStatus.status = 'unknown'; + loginStatus.status = 'revoked_access'; + tokenStore.removeItem('fbAuthResponse'); + tokenStore.removeItem('fbtoken'); authResponse = null; } if (callback) callback(loginStatus); From afe571a38321caadd75f872dbaf29e852ca0a580 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Thu, 2 Jul 2015 09:07:51 -0300 Subject: [PATCH 16/47] Update ngopenfb.js --- ngopenfb.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ngopenfb.js b/ngopenfb.js index bbc4fff..7df5deb 100644 --- a/ngopenfb.js +++ b/ngopenfb.js @@ -45,6 +45,18 @@ angular.module('ngOpenFB', []) $window.openFB.api(obj); return deferred.promise; } + + function graph(obj) { + var deferred = $q.defer(); + obj.success = function(result) { + deferred.resolve(result); + }; + obj.error = function(error) { + deferred.reject(error); + }; + $window.openFB.graph(obj); + return deferred.promise; + } function revokePermissions() { var deferred = $q.defer(); @@ -79,6 +91,7 @@ angular.module('ngOpenFB', []) logout: logout, revokePermissions: revokePermissions, api: api, + graph: graph, getLoginStatus: getLoginStatus, getAuthResponse: getAuthResponse }; From c1ac899d2dd6056189cdb90d8e749f40a4084ea4 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Sat, 4 Jul 2015 19:05:28 -0300 Subject: [PATCH 17/47] Update openfb.js --- openfb.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfb.js b/openfb.js index 8d3e7c1..8cb6335 100644 --- a/openfb.js +++ b/openfb.js @@ -184,7 +184,7 @@ var openFB = (function () { startTime = new Date().getTime(); loginWindow = window.open(loginURL + '?client_id=' + fbAppId + '&redirect_uri=' + redirectURL + - '&response_type=token,signed_request,code&scope=' + scope, '_blank', 'location=no,clearcache=yes'); + '&response_type=token,signed_request,code&scope=' + scope, '_blank', 'location=no,clearcache=yes,zoom=no'); // If the app is running in Cordova, listen to URL changes in the InAppBrowser until we get a URL with an access_token or an error if (runningInCordova) { @@ -245,7 +245,7 @@ var openFB = (function () { if (token && !logoutProcessed) { logoutProcessed = true; - logoutWindow = window.open(logoutURL + '?confirm=1&access_token=' + token + '&next=' + logoutRedirectURL, '_blank', 'location=no,clearcache=yes'); + logoutWindow = window.open(logoutURL + '?confirm=1&access_token=' + token + '&next=' + logoutRedirectURL, '_blank', 'location=no,clearcache=yes,zoom=no'); if (runningInCordova) { setTimeout(function() { logoutWindow.close(); From 89444a6b943e3abc03af6afc7b4f5ef5510edf44 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Mon, 3 Aug 2015 15:17:55 -0300 Subject: [PATCH 18/47] Prevent low connection state in login --- openfb.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/openfb.js b/openfb.js index 8cb6335..d1374e1 100644 --- a/openfb.js +++ b/openfb.js @@ -150,9 +150,14 @@ var openFB = (function () { return callback({ status:'unknown', error:'Facebook App Id not set.' }); } + // `cordova-plugin-network-information` offline handler: Used when running in Cordova only + function document_offline(evt){ + loginWindow.close(); + } + // Inappbrowser load start handler: Used when running in Cordova only - function loginWindow_loadStartHandler(event) { - var url = event.url; + function loginWindow_loadStartHandler(evt) { + var url = evt.url; if (url.indexOf('access_token=') > 0 || url.indexOf('error=') > 0) { // When we get the access token fast, the login window (inappbrowser) is still opening with animation // in the Cordova app, and trying to close it while it's animating generates an exception. Wait a little... @@ -164,11 +169,18 @@ var openFB = (function () { } } + // Inappbrowser load stop handler fires when loading is complete: Used when running in Cordova only + function loginWindow_loadStopHandler(evt){ + // N/A yet. + } + // Inappbrowser exit handler: Used when running in Cordova only function loginWindow_exitHandler() { console.log('exit and remove listeners'); // Handle the situation where the user closes the login window manually before completing the login process if (loginCallback && !loginProcessed) loginCallback({status:'user_cancelled'}); + document.removeEventListener('offline', document_offline); + loginWindow.removeEventListener('loadstart', loginWindow_loadStartHandler); loginWindow.removeEventListener('loadstop', loginWindow_loadStopHandler); loginWindow.removeEventListener('exit', loginWindow_exitHandler); loginWindow = null; @@ -188,7 +200,9 @@ var openFB = (function () { // If the app is running in Cordova, listen to URL changes in the InAppBrowser until we get a URL with an access_token or an error if (runningInCordova) { + document.addEventListener('offline', document_offline, false); loginWindow.addEventListener('loadstart', loginWindow_loadStartHandler); + loginWindow.addEventListener('loadstop', loginWindow_loadStopHandler); loginWindow.addEventListener('exit', loginWindow_exitHandler); } // Note: if the app is running in the browser the loginWindow dialog will call back by invoking the From 8a2b430d2c56055ad4fec8e006fc10ecec8fcc11 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Mon, 3 Aug 2015 17:17:36 -0300 Subject: [PATCH 19/47] Update openfb.js --- openfb.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openfb.js b/openfb.js index d1374e1..9ae7684 100644 --- a/openfb.js +++ b/openfb.js @@ -15,6 +15,8 @@ var openFB = (function () { authResponse = null, + disconnected = false, + // By default we store fbtoken in sessionStorage. This can be overridden in init() tokenStore = window.sessionStorage, @@ -152,6 +154,7 @@ var openFB = (function () { // `cordova-plugin-network-information` offline handler: Used when running in Cordova only function document_offline(evt){ + disconnected = true; loginWindow.close(); } @@ -178,12 +181,13 @@ var openFB = (function () { function loginWindow_exitHandler() { console.log('exit and remove listeners'); // Handle the situation where the user closes the login window manually before completing the login process - if (loginCallback && !loginProcessed) loginCallback({status:'user_cancelled'}); + if (loginCallback && !loginProcessed) loginCallback({status:disconnected?'user_disconnected':'user_cancelled'}); document.removeEventListener('offline', document_offline); loginWindow.removeEventListener('loadstart', loginWindow_loadStartHandler); loginWindow.removeEventListener('loadstop', loginWindow_loadStopHandler); loginWindow.removeEventListener('exit', loginWindow_exitHandler); loginWindow = null; + disconnected = false; console.log('done removing listeners'); } From 0e9ea357796467ec1cedd48390287a2a70dda810 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Tue, 4 Aug 2015 10:26:16 -0300 Subject: [PATCH 20/47] Update openfb.js --- openfb.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/openfb.js b/openfb.js index 9ae7684..df9cf6e 100644 --- a/openfb.js +++ b/openfb.js @@ -153,7 +153,7 @@ var openFB = (function () { } // `cordova-plugin-network-information` offline handler: Used when running in Cordova only - function document_offline(evt){ + function document_offline(){ disconnected = true; loginWindow.close(); } @@ -172,6 +172,11 @@ var openFB = (function () { } } + // Inappbrowser load error handler fires when occurs an error when loading a URL: Used when running in Cordova only + function loginWindow_loadErrorHandler(){ + document_offline(); + } + // Inappbrowser load stop handler fires when loading is complete: Used when running in Cordova only function loginWindow_loadStopHandler(evt){ // N/A yet. @@ -184,6 +189,7 @@ var openFB = (function () { if (loginCallback && !loginProcessed) loginCallback({status:disconnected?'user_disconnected':'user_cancelled'}); document.removeEventListener('offline', document_offline); loginWindow.removeEventListener('loadstart', loginWindow_loadStartHandler); + loginWindow.removeEventListener('loaderror', loginWindow_loadErrorHandler); loginWindow.removeEventListener('loadstop', loginWindow_loadStopHandler); loginWindow.removeEventListener('exit', loginWindow_exitHandler); loginWindow = null; @@ -206,6 +212,7 @@ var openFB = (function () { if (runningInCordova) { document.addEventListener('offline', document_offline, false); loginWindow.addEventListener('loadstart', loginWindow_loadStartHandler); + loginWindow.addEventListener('loaderror', loginWindow_loadErrorHandler); loginWindow.addEventListener('loadstop', loginWindow_loadStopHandler); loginWindow.addEventListener('exit', loginWindow_exitHandler); } From 7f661fc50a598516d71bef896a19e9aa0f208c9a Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Tue, 4 Aug 2015 10:51:53 -0300 Subject: [PATCH 21/47] Update openfb.js --- openfb.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfb.js b/openfb.js index df9cf6e..317b306 100644 --- a/openfb.js +++ b/openfb.js @@ -205,8 +205,8 @@ var openFB = (function () { loginProcessed = false; startTime = new Date().getTime(); - loginWindow = window.open(loginURL + '?client_id=' + fbAppId + '&redirect_uri=' + redirectURL + - '&response_type=token,signed_request,code&scope=' + scope, '_blank', 'location=no,clearcache=yes,zoom=no'); + loginWindow = window.open(loginURL +'?client_id='+ fbAppId +'&redirect_uri='+ redirectURL + + '&response_type=token,signed_request,code&scope='+ scope, '_blank', 'location=no,clearcache=yes,zoom=no'); // If the app is running in Cordova, listen to URL changes in the InAppBrowser until we get a URL with an access_token or an error if (runningInCordova) { From 26345891287a963cddf8435a743ecf7e218fcc90 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Tue, 4 Aug 2015 11:19:02 -0300 Subject: [PATCH 22/47] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6307c59..ddadf63 100644 --- a/README.md +++ b/README.md @@ -88,11 +88,12 @@ The library works for both browser-based apps and Cordova/PhoneGap apps. When ru cordova create sample com.openfb.sample sample ``` -1. Add the InAppBrowser Plugin +1. Add the InAppBrowser Plugin and NetworkInformation ``` cd sample - cordova plugins add org.apache.cordova.inappbrowser + cordova plugins add cordova-plugin-inappbrowser + cordova plugins add cordova-plugin-network-information ``` 1. Delete the contents of the ```www``` directory From 7568e74b7e9d024d771019a2b9a05b681382a582 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Tue, 4 Aug 2015 11:32:50 -0300 Subject: [PATCH 23/47] Update openfb.js --- openfb.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/openfb.js b/openfb.js index 317b306..f2a4eba 100644 --- a/openfb.js +++ b/openfb.js @@ -158,6 +158,11 @@ var openFB = (function () { loginWindow.close(); } + // `cordova-plugin-network-information` online handler: Used when running in Cordova only + function document_online(){ + // N/A yet. + } + // Inappbrowser load start handler: Used when running in Cordova only function loginWindow_loadStartHandler(evt) { var url = evt.url; @@ -187,6 +192,7 @@ var openFB = (function () { console.log('exit and remove listeners'); // Handle the situation where the user closes the login window manually before completing the login process if (loginCallback && !loginProcessed) loginCallback({status:disconnected?'user_disconnected':'user_cancelled'}); + document.removeEventListener('online', document_online); document.removeEventListener('offline', document_offline); loginWindow.removeEventListener('loadstart', loginWindow_loadStartHandler); loginWindow.removeEventListener('loaderror', loginWindow_loadErrorHandler); @@ -205,11 +211,15 @@ var openFB = (function () { loginProcessed = false; startTime = new Date().getTime(); - loginWindow = window.open(loginURL +'?client_id='+ fbAppId +'&redirect_uri='+ redirectURL + - '&response_type=token,signed_request,code&scope='+ scope, '_blank', 'location=no,clearcache=yes,zoom=no'); + if(window.navigator.onLine){ + loginWindow = window.open(loginURL +'?client_id='+ fbAppId +'&redirect_uri='+ redirectURL +'&response_type=token,signed_request,code&scope='+ scope, '_blank', 'location=no,clearcache=yes,zoom=no'); + }else{ + loginCallback && loginCallback({status:'user_disconnected'}); + } // If the app is running in Cordova, listen to URL changes in the InAppBrowser until we get a URL with an access_token or an error - if (runningInCordova) { + if(runningInCordova){ + document.addEventListener('online', document_online, false); document.addEventListener('offline', document_offline, false); loginWindow.addEventListener('loadstart', loginWindow_loadStartHandler); loginWindow.addEventListener('loaderror', loginWindow_loadErrorHandler); From dea57196ac1ac76b1fd4462819d9f4d5e0697fe1 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Tue, 4 Aug 2015 17:26:39 -0300 Subject: [PATCH 24/47] Update openfb.js --- openfb.js | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/openfb.js b/openfb.js index f2a4eba..1b2c247 100644 --- a/openfb.js +++ b/openfb.js @@ -211,7 +211,7 @@ var openFB = (function () { loginProcessed = false; startTime = new Date().getTime(); - if(window.navigator.onLine){ + if(navigator.onLine){ loginWindow = window.open(loginURL +'?client_id='+ fbAppId +'&redirect_uri='+ redirectURL +'&response_type=token,signed_request,code&scope='+ scope, '_blank', 'location=no,clearcache=yes,zoom=no'); }else{ loginCallback && loginCallback({status:'user_disconnected'}); @@ -270,7 +270,8 @@ var openFB = (function () { * e.g. https://rawgit.com/ccoenraets/OpenFB/master/logoutcallback.html */ function logout(callback) { - var logoutWindow, + var response = {}, + logoutWindow, token = authResponse ? authResponse.accessToken : null; /* Remove token. Will fail silently if does not exist */ @@ -278,20 +279,22 @@ var openFB = (function () { tokenStore.removeItem('fbtoken'); authResponse = null; - if (token && !logoutProcessed) { + if(token && !logoutProcessed){ logoutProcessed = true; - logoutWindow = window.open(logoutURL + '?confirm=1&access_token=' + token + '&next=' + logoutRedirectURL, '_blank', 'location=no,clearcache=yes,zoom=no'); - if (runningInCordova) { - setTimeout(function() { - logoutWindow.close(); + if(navigator.onLine){ + logoutWindow = window.open(logoutURL +'?confirm=1&access_token='+ token +'&next='+ logoutRedirectURL, '_blank', 'location=no,clearcache=yes,zoom=no'); + }else{ + response = { error:true, status:'user_disconnected' }; + } + if(runningInCordova){ + setTimeout(function(){ + logoutWindow && logoutWindow.close(); }, 700); } } - - if (callback) { - callback(); + if(callback){ + callback(response); } - } /** From d2d0fe58a05ec8a0414f91b23800239bf79eeb0d Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Tue, 4 Aug 2015 17:35:49 -0300 Subject: [PATCH 25/47] Update openfb.js --- openfb.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfb.js b/openfb.js index 1b2c247..b69bb7b 100644 --- a/openfb.js +++ b/openfb.js @@ -286,9 +286,9 @@ var openFB = (function () { }else{ response = { error:true, status:'user_disconnected' }; } - if(runningInCordova){ + if(runningInCordova && logoutWindow){ setTimeout(function(){ - logoutWindow && logoutWindow.close(); + logoutWindow.close(); }, 700); } } From a870493f93d9943f8ee09b117573da92b15f7f2f Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Wed, 5 Aug 2015 10:30:21 -0300 Subject: [PATCH 26/47] Update openfb.js --- openfb.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/openfb.js b/openfb.js index b69bb7b..0ea80d7 100644 --- a/openfb.js +++ b/openfb.js @@ -145,6 +145,7 @@ var openFB = (function () { var loginWindow, startTime, + timeout, scope = '', redirectURL = runningInCordova ? cordovaOAuthRedirectURL : oauthRedirectURL; @@ -169,7 +170,7 @@ var openFB = (function () { if (url.indexOf('access_token=') > 0 || url.indexOf('error=') > 0) { // When we get the access token fast, the login window (inappbrowser) is still opening with animation // in the Cordova app, and trying to close it while it's animating generates an exception. Wait a little... - var timeout = 600 - (new Date().getTime() - startTime); + timeout = 600 - (new Date().getTime() - startTime); setTimeout(function () { loginWindow.close(); }, timeout > 0 ? timeout : 0); @@ -214,7 +215,10 @@ var openFB = (function () { if(navigator.onLine){ loginWindow = window.open(loginURL +'?client_id='+ fbAppId +'&redirect_uri='+ redirectURL +'&response_type=token,signed_request,code&scope='+ scope, '_blank', 'location=no,clearcache=yes,zoom=no'); }else{ - loginCallback && loginCallback({status:'user_disconnected'}); + timeout = 600 - (new Date().getTime() - startTime); + setTimeout(function(){ + loginCallback && loginCallback({status:'user_disconnected'}); + }, timeout > 0 ? timeout : 0); } // If the app is running in Cordova, listen to URL changes in the InAppBrowser until we get a URL with an access_token or an error From 30dfec1defb14b472aa24faefb629c72d9eb7c95 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Wed, 5 Aug 2015 10:41:09 -0300 Subject: [PATCH 27/47] Update openfb.js --- openfb.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/openfb.js b/openfb.js index 0ea80d7..b69bb7b 100644 --- a/openfb.js +++ b/openfb.js @@ -145,7 +145,6 @@ var openFB = (function () { var loginWindow, startTime, - timeout, scope = '', redirectURL = runningInCordova ? cordovaOAuthRedirectURL : oauthRedirectURL; @@ -170,7 +169,7 @@ var openFB = (function () { if (url.indexOf('access_token=') > 0 || url.indexOf('error=') > 0) { // When we get the access token fast, the login window (inappbrowser) is still opening with animation // in the Cordova app, and trying to close it while it's animating generates an exception. Wait a little... - timeout = 600 - (new Date().getTime() - startTime); + var timeout = 600 - (new Date().getTime() - startTime); setTimeout(function () { loginWindow.close(); }, timeout > 0 ? timeout : 0); @@ -215,10 +214,7 @@ var openFB = (function () { if(navigator.onLine){ loginWindow = window.open(loginURL +'?client_id='+ fbAppId +'&redirect_uri='+ redirectURL +'&response_type=token,signed_request,code&scope='+ scope, '_blank', 'location=no,clearcache=yes,zoom=no'); }else{ - timeout = 600 - (new Date().getTime() - startTime); - setTimeout(function(){ - loginCallback && loginCallback({status:'user_disconnected'}); - }, timeout > 0 ? timeout : 0); + loginCallback && loginCallback({status:'user_disconnected'}); } // If the app is running in Cordova, listen to URL changes in the InAppBrowser until we get a URL with an access_token or an error From 9fd254550dd0bec236946d710d7895f95e5e545d Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Mon, 10 Aug 2015 15:37:31 -0300 Subject: [PATCH 28/47] Update openfb.js --- openfb.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/openfb.js b/openfb.js index b69bb7b..bc984a2 100644 --- a/openfb.js +++ b/openfb.js @@ -146,6 +146,7 @@ var openFB = (function () { var loginWindow, startTime, scope = '', + auth_type = '', redirectURL = runningInCordova ? cordovaOAuthRedirectURL : oauthRedirectURL; if (!fbAppId) { @@ -207,12 +208,16 @@ var openFB = (function () { scope = options.scope; } + if (options && options.auth_type) { + auth_type = '&auth_type='+ options.auth_type; + } + loginCallback = callback; loginProcessed = false; startTime = new Date().getTime(); if(navigator.onLine){ - loginWindow = window.open(loginURL +'?client_id='+ fbAppId +'&redirect_uri='+ redirectURL +'&response_type=token,signed_request,code&scope='+ scope, '_blank', 'location=no,clearcache=yes,zoom=no'); + loginWindow = window.open(loginURL +'?client_id='+ fbAppId +'&redirect_uri='+ redirectURL +'&response_type=token,signed_request,code&scope='+ scope + auth_type, '_blank', 'location=no,clearcache=yes,zoom=no'); }else{ loginCallback && loginCallback({status:'user_disconnected'}); } From 4585ba7987b89e8e436d24dcb4bdcb1ef5accb20 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Thu, 13 Aug 2015 14:21:53 -0300 Subject: [PATCH 29/47] Update openfb.js --- openfb.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfb.js b/openfb.js index bc984a2..ae06d11 100644 --- a/openfb.js +++ b/openfb.js @@ -161,7 +161,7 @@ var openFB = (function () { // `cordova-plugin-network-information` online handler: Used when running in Cordova only function document_online(){ - // N/A yet. + disconnected = false; } // Inappbrowser load start handler: Used when running in Cordova only From a595589f7c782589ae106a47283768d44bfb0adf Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Thu, 13 Aug 2015 14:27:59 -0300 Subject: [PATCH 30/47] Update openfb.js --- openfb.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/openfb.js b/openfb.js index ae06d11..d6877cf 100644 --- a/openfb.js +++ b/openfb.js @@ -224,12 +224,14 @@ var openFB = (function () { // If the app is running in Cordova, listen to URL changes in the InAppBrowser until we get a URL with an access_token or an error if(runningInCordova){ - document.addEventListener('online', document_online, false); + if(loginWindow){ + loginWindow.addEventListener('loadstart', loginWindow_loadStartHandler); + loginWindow.addEventListener('loaderror', loginWindow_loadErrorHandler); + loginWindow.addEventListener('loadstop', loginWindow_loadStopHandler); + loginWindow.addEventListener('exit', loginWindow_exitHandler); + } document.addEventListener('offline', document_offline, false); - loginWindow.addEventListener('loadstart', loginWindow_loadStartHandler); - loginWindow.addEventListener('loaderror', loginWindow_loadErrorHandler); - loginWindow.addEventListener('loadstop', loginWindow_loadStopHandler); - loginWindow.addEventListener('exit', loginWindow_exitHandler); + document.addEventListener('online', document_online, false); } // Note: if the app is running in the browser the loginWindow dialog will call back by invoking the // oauthCallback() function. See oauthcallback.html for details. From 13d9b6bc57d8c95e608c528c2733ca8195a9574f Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Fri, 14 Aug 2015 17:01:47 -0300 Subject: [PATCH 31/47] Update openfb.js --- openfb.js | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/openfb.js b/openfb.js index d6877cf..c879f8b 100644 --- a/openfb.js +++ b/openfb.js @@ -280,25 +280,27 @@ var openFB = (function () { var response = {}, logoutWindow, token = authResponse ? authResponse.accessToken : null; - - /* Remove token. Will fail silently if does not exist */ - tokenStore.removeItem('fbAuthResponse'); - tokenStore.removeItem('fbtoken'); - authResponse = null; - - if(token && !logoutProcessed){ - logoutProcessed = true; - if(navigator.onLine){ + + if(navigator.onLine){ + /* Remove token. Will fail silently if does not exist */ + tokenStore.removeItem('fbAuthResponse'); + tokenStore.removeItem('fbtoken'); + authResponse = null; + + if(token && !logoutProcessed){ + response = { error:false, status:'success' }; + logoutProcessed = true; logoutWindow = window.open(logoutURL +'?confirm=1&access_token='+ token +'&next='+ logoutRedirectURL, '_blank', 'location=no,clearcache=yes,zoom=no'); - }else{ - response = { error:true, status:'user_disconnected' }; - } - if(runningInCordova && logoutWindow){ - setTimeout(function(){ - logoutWindow.close(); - }, 700); + if(runningInCordova && logoutWindow){ + setTimeout(function(){ + logoutWindow.close(); + }, 700); + } } + }else{ + response = { error:true, status:'user_disconnected' }; } + if(callback){ callback(response); } From 291e0626ec1718e6bfeefd16b5ca9ba311c29e12 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Fri, 14 Aug 2015 17:40:27 -0300 Subject: [PATCH 32/47] Update openfb.js --- openfb.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfb.js b/openfb.js index c879f8b..7f0dc5c 100644 --- a/openfb.js +++ b/openfb.js @@ -156,7 +156,7 @@ var openFB = (function () { // `cordova-plugin-network-information` offline handler: Used when running in Cordova only function document_offline(){ disconnected = true; - loginWindow.close(); + loginWindow && loginWindow.close(); } // `cordova-plugin-network-information` online handler: Used when running in Cordova only From 07e816650b231056f92fb9d1bf7f537e74f37d0a Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Sat, 15 Aug 2015 15:52:48 -0300 Subject: [PATCH 33/47] Update logoutcallback.html --- logoutcallback.html | 1 + 1 file changed, 1 insertion(+) diff --git a/logoutcallback.html b/logoutcallback.html index 499f325..2395112 100644 --- a/logoutcallback.html +++ b/logoutcallback.html @@ -1,6 +1,7 @@ From e36662f34d76c0b0bf18dee241fceda9efce4385 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Sat, 15 Aug 2015 15:53:25 -0300 Subject: [PATCH 34/47] Update openfb.js --- openfb.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openfb.js b/openfb.js index 7f0dc5c..2047905 100644 --- a/openfb.js +++ b/openfb.js @@ -305,6 +305,9 @@ var openFB = (function () { callback(response); } } + function logoutCallback(url) { + // N/A yet + } /** * Lets you make any Facebook Graph API request. @@ -466,6 +469,7 @@ var openFB = (function () { api: api, graph: graph, oauthCallback: oauthCallback, + logoutCallback: logoutCallback, getLoginStatus: getLoginStatus } }()); From fa1a65f3ffeeeb085666deb37c628f2a95a1e7cf Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Sun, 16 Aug 2015 18:30:24 -0300 Subject: [PATCH 35/47] Update openfb.js --- openfb.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/openfb.js b/openfb.js index 2047905..e3b8b70 100644 --- a/openfb.js +++ b/openfb.js @@ -147,6 +147,7 @@ var openFB = (function () { startTime, scope = '', auth_type = '', + io_error = false, redirectURL = runningInCordova ? cordovaOAuthRedirectURL : oauthRedirectURL; if (!fbAppId) { @@ -180,6 +181,7 @@ var openFB = (function () { // Inappbrowser load error handler fires when occurs an error when loading a URL: Used when running in Cordova only function loginWindow_loadErrorHandler(){ + io_error = true; document_offline(); } @@ -192,15 +194,16 @@ var openFB = (function () { function loginWindow_exitHandler() { console.log('exit and remove listeners'); // Handle the situation where the user closes the login window manually before completing the login process - if (loginCallback && !loginProcessed) loginCallback({status:disconnected?'user_disconnected':'user_cancelled'}); + if (loginCallback && !loginProcessed) loginCallback({status:disconnected?(io_error?'io_error':'user_disconnected':'user_cancelled'}); document.removeEventListener('online', document_online); document.removeEventListener('offline', document_offline); loginWindow.removeEventListener('loadstart', loginWindow_loadStartHandler); loginWindow.removeEventListener('loaderror', loginWindow_loadErrorHandler); loginWindow.removeEventListener('loadstop', loginWindow_loadStopHandler); loginWindow.removeEventListener('exit', loginWindow_exitHandler); - loginWindow = null; + loginWindow = undefined; disconnected = false; + io_error = false; console.log('done removing listeners'); } From d91d6ec38e4c0e59880ccd18057dddffb66f9fc3 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Sun, 16 Aug 2015 18:34:06 -0300 Subject: [PATCH 36/47] Update openfb.js --- openfb.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/openfb.js b/openfb.js index e3b8b70..e078349 100644 --- a/openfb.js +++ b/openfb.js @@ -145,9 +145,9 @@ var openFB = (function () { var loginWindow, startTime, + io_error, scope = '', auth_type = '', - io_error = false, redirectURL = runningInCordova ? cordovaOAuthRedirectURL : oauthRedirectURL; if (!fbAppId) { @@ -181,7 +181,7 @@ var openFB = (function () { // Inappbrowser load error handler fires when occurs an error when loading a URL: Used when running in Cordova only function loginWindow_loadErrorHandler(){ - io_error = true; + io_error = 'io_error'; document_offline(); } @@ -192,19 +192,17 @@ var openFB = (function () { // Inappbrowser exit handler: Used when running in Cordova only function loginWindow_exitHandler() { - console.log('exit and remove listeners'); // Handle the situation where the user closes the login window manually before completing the login process - if (loginCallback && !loginProcessed) loginCallback({status:disconnected?(io_error?'io_error':'user_disconnected':'user_cancelled'}); + if (loginCallback && !loginProcessed) loginCallback({status:disconnected?(io_error||'user_disconnected'):'user_cancelled'}); document.removeEventListener('online', document_online); document.removeEventListener('offline', document_offline); loginWindow.removeEventListener('loadstart', loginWindow_loadStartHandler); loginWindow.removeEventListener('loaderror', loginWindow_loadErrorHandler); loginWindow.removeEventListener('loadstop', loginWindow_loadStopHandler); loginWindow.removeEventListener('exit', loginWindow_exitHandler); - loginWindow = undefined; disconnected = false; - io_error = false; - console.log('done removing listeners'); + loginWindow = undefined; + io_error = undefined; } if (options && options.scope) { From 5d46bbc6b72f510623b7c69a2c56b5210331e29b Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Sun, 16 Aug 2015 19:37:25 -0300 Subject: [PATCH 37/47] Update openfb.js --- openfb.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openfb.js b/openfb.js index e078349..4073e6d 100644 --- a/openfb.js +++ b/openfb.js @@ -181,6 +181,8 @@ var openFB = (function () { // Inappbrowser load error handler fires when occurs an error when loading a URL: Used when running in Cordova only function loginWindow_loadErrorHandler(){ + // To avoid this error in Android, do not forget: + // io_error = 'io_error'; document_offline(); } From 606cea5be6bacaca66facf2988fa99bb8060fb62 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Sun, 16 Aug 2015 20:11:01 -0300 Subject: [PATCH 38/47] Update openfb.js --- openfb.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openfb.js b/openfb.js index 4073e6d..e96bb3e 100644 --- a/openfb.js +++ b/openfb.js @@ -189,7 +189,9 @@ var openFB = (function () { // Inappbrowser load stop handler fires when loading is complete: Used when running in Cordova only function loginWindow_loadStopHandler(evt){ - // N/A yet. + tokenStore.removeItem('fbAuthResponse'); + tokenStore.removeItem('fbtoken'); + authResponse = null; } // Inappbrowser exit handler: Used when running in Cordova only From de97fd6e512f40af8ccaa88e591f98cc0e44bb75 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Sun, 16 Aug 2015 20:47:58 -0300 Subject: [PATCH 39/47] Update openfb.js --- openfb.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfb.js b/openfb.js index e96bb3e..7245582 100644 --- a/openfb.js +++ b/openfb.js @@ -222,7 +222,7 @@ var openFB = (function () { startTime = new Date().getTime(); if(navigator.onLine){ - loginWindow = window.open(loginURL +'?client_id='+ fbAppId +'&redirect_uri='+ redirectURL +'&response_type=token,signed_request,code&scope='+ scope + auth_type, '_blank', 'location=no,clearcache=yes,zoom=no'); + loginWindow = window.open(loginURL +'?client_id='+ fbAppId +'&redirect_uri='+ redirectURL +'&response_type=token,signed_request,code&scope='+ scope + auth_type, '_blank', 'location=no,clearcache=yes,clearsessioncache=yes,zoom=no'); }else{ loginCallback && loginCallback({status:'user_disconnected'}); } @@ -295,7 +295,7 @@ var openFB = (function () { if(token && !logoutProcessed){ response = { error:false, status:'success' }; logoutProcessed = true; - logoutWindow = window.open(logoutURL +'?confirm=1&access_token='+ token +'&next='+ logoutRedirectURL, '_blank', 'location=no,clearcache=yes,zoom=no'); + logoutWindow = window.open(logoutURL +'?confirm=1&access_token='+ token +'&next='+ logoutRedirectURL, '_blank', 'location=no,clearcache=yes,clearsessioncache=yes,zoom=no'); if(runningInCordova && logoutWindow){ setTimeout(function(){ logoutWindow.close(); From e93092e2185d1211213717a9c806610da914f38c Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Sun, 16 Aug 2015 23:58:51 -0300 Subject: [PATCH 40/47] Update openfb.js --- openfb.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openfb.js b/openfb.js index 7245582..857cd05 100644 --- a/openfb.js +++ b/openfb.js @@ -189,9 +189,9 @@ var openFB = (function () { // Inappbrowser load stop handler fires when loading is complete: Used when running in Cordova only function loginWindow_loadStopHandler(evt){ - tokenStore.removeItem('fbAuthResponse'); - tokenStore.removeItem('fbtoken'); - authResponse = null; + // tokenStore.removeItem('fbAuthResponse'); + // tokenStore.removeItem('fbtoken'); + // authResponse = null; } // Inappbrowser exit handler: Used when running in Cordova only From 01bf841f6426305eded7f47872f6dbe7115f3e88 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Sat, 5 Sep 2015 10:08:14 -0300 Subject: [PATCH 41/47] Update openfb.js --- openfb.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/openfb.js b/openfb.js index 857cd05..ccc4b66 100644 --- a/openfb.js +++ b/openfb.js @@ -296,11 +296,10 @@ var openFB = (function () { response = { error:false, status:'success' }; logoutProcessed = true; logoutWindow = window.open(logoutURL +'?confirm=1&access_token='+ token +'&next='+ logoutRedirectURL, '_blank', 'location=no,clearcache=yes,clearsessioncache=yes,zoom=no'); - if(runningInCordova && logoutWindow){ - setTimeout(function(){ - logoutWindow.close(); - }, 700); - } + setTimeout(function(){ + logoutWindow && logoutWindow.close(); + logoutWindow = undefined; + }, 700); } }else{ response = { error:true, status:'user_disconnected' }; From 480c4a5a7d53cf983e79c63d015a4e9e0d7adb26 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Wed, 16 Sep 2015 18:50:12 -0300 Subject: [PATCH 42/47] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index ddadf63..42969fa 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,11 @@ openFB.api( }); ``` +Facebook `Valid OAuth redirect URIs` for development: +``` +https://rawgit.com/adriancmiranda/OpenFB/master/oauthcallback.html +``` + The approach used in OpenFB (plain OAuth + direct requests to Graph API endpoints) is simple and lightweight, but it is definitely not perfect. Pros: From 530d83fdcc2a814369f30aa91aba36bd8b33e212 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Wed, 16 Sep 2015 18:51:43 -0300 Subject: [PATCH 43/47] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 42969fa..7e954cc 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,8 @@ openFB.api( }); ``` -Facebook `Valid OAuth redirect URIs` for development: +You can use [this](https://rawgit.com/adriancmiranda/OpenFB/master/oauthcallback.html) Facebook `Valid OAuth redirect URI` for development: + ``` https://rawgit.com/adriancmiranda/OpenFB/master/oauthcallback.html ``` From 03f1c4d8e8c45086c471a754ea8be1522935730e Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Wed, 16 Sep 2015 18:53:13 -0300 Subject: [PATCH 44/47] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7e954cc..a709c4b 100644 --- a/README.md +++ b/README.md @@ -35,10 +35,10 @@ openFB.api( }); ``` -You can use [this](https://rawgit.com/adriancmiranda/OpenFB/master/oauthcallback.html) Facebook `Valid OAuth redirect URI` for development: +You can use [this](https://cdn.rawgit.com/adriancmiranda/OpenFB/master/oauthcallback.html) Facebook `Valid OAuth redirect URI` for development: ``` -https://rawgit.com/adriancmiranda/OpenFB/master/oauthcallback.html +https://cdn.rawgit.com/adriancmiranda/OpenFB/master/oauthcallback.html ``` The approach used in OpenFB (plain OAuth + direct requests to Graph API endpoints) is simple and lightweight, but it is definitely not perfect. From aa1bb020df23ad260a13d0f6e41597aa300c889e Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Wed, 16 Sep 2015 18:56:19 -0300 Subject: [PATCH 45/47] Update README.md --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index a709c4b..269aa3f 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,16 @@ OpenFB allows you to login to Facebook and execute any Facebook Graph API reques Here are a few code examples... +Init: + +``` +openFB.init({ + oauthRedirectURL:'https://cdn.rawgit.com/adriancmiranda/OpenFB/master/oauthcallback.html', + appSecret:facebook.appSecret, + appId:facebook.appId +}); +``` + Login using Facebook: ``` From 6efe0886bb84a8cdb25c829bbcb31285bbf6db56 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Wed, 16 Sep 2015 18:57:50 -0300 Subject: [PATCH 46/47] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 269aa3f..03d29ce 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,9 @@ Init: ``` openFB.init({ - oauthRedirectURL:'https://cdn.rawgit.com/adriancmiranda/OpenFB/master/oauthcallback.html', - appSecret:facebook.appSecret, - appId:facebook.appId + oauthRedirectURL:'https://cdn.rawgit.com/adriancmiranda/OpenFB/master/oauthcallback.html', + appSecret:facebook.appSecret, + appId:facebook.appId }); ``` From 072d1957aedc75dcbfb21a6aa70314fe5a9c93a8 Mon Sep 17 00:00:00 2001 From: Adrian Miranda Date: Wed, 16 Sep 2015 18:58:33 -0300 Subject: [PATCH 47/47] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 03d29ce..1b9d26f 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Init: ``` openFB.init({ - oauthRedirectURL:'https://cdn.rawgit.com/adriancmiranda/OpenFB/master/oauthcallback.html', + oauthRedirectURL:'https://cdn.rawgit.com/ccoenraets/OpenFB/master/oauthcallback.html', appSecret:facebook.appSecret, appId:facebook.appId }); @@ -45,10 +45,10 @@ openFB.api( }); ``` -You can use [this](https://cdn.rawgit.com/adriancmiranda/OpenFB/master/oauthcallback.html) Facebook `Valid OAuth redirect URI` for development: +You can use [this](https://cdn.rawgit.com/ccoenraets/OpenFB/master/oauthcallback.html) Facebook `Valid OAuth redirect URI` for development: ``` -https://cdn.rawgit.com/adriancmiranda/OpenFB/master/oauthcallback.html +https://cdn.rawgit.com/ccoenraets/OpenFB/master/oauthcallback.html ``` The approach used in OpenFB (plain OAuth + direct requests to Graph API endpoints) is simple and lightweight, but it is definitely not perfect.