facebook-sdk
Advanced tools
Comparing version 0.2.5 to 0.2.6
var connect = require('connect'), | ||
fbsdk = require('facebook-sdk'); | ||
fbsdk = require('facebook-sdk'); | ||
var port = 3000; | ||
connect() | ||
.use(connect.favicon()) | ||
.use(fbsdk.facebook({ | ||
appId : 'YOUR APP ID', | ||
secret : 'YOUR API SECRET' | ||
})) | ||
.use(function(req, res, next) { | ||
if (req.facebook.getSession()) { | ||
res.end('<a href="' + req.facebook.getLogoutUrl() + '">Logout</a>'); | ||
// get my graph api information | ||
req.facebook.api('/me', function(me) { | ||
console.log(me); | ||
}); | ||
} else { | ||
res.end('<a href="' + req.facebook.getLoginUrl() + '">Login</a>'); | ||
} | ||
}) | ||
.listen(3000); | ||
.use(connect.favicon()) | ||
.use(fbsdk.facebook({ | ||
appId : 'YOUR APP ID', | ||
secret : 'YOUR APP SECRET' | ||
})) | ||
.use(function(req, res, next) { | ||
if (req.facebook.getSession()) { | ||
// get my graph api information | ||
req.facebook.api('/me', function(me) { | ||
console.log(me); | ||
}); | ||
res.end('<a href="' + req.facebook.getLogoutUrl() + '">Logout</a>'); | ||
} else { | ||
res.end('<a href="' + req.facebook.getLoginUrl() + '">Login</a>'); | ||
} | ||
}) | ||
.listen(port); | ||
console.log('Listening for http requests on port ' + port); |
1546
lib/facebook.js
@@ -18,7 +18,7 @@ /** | ||
var crypto = require('crypto'), | ||
http = require('http'), | ||
https = require('https'), | ||
querystring = require('querystring'), | ||
URL = require('url'), | ||
util = require('util'); | ||
http = require('http'), | ||
https = require('https'), | ||
querystring = require('querystring'), | ||
URL = require('url'), | ||
util = require('util'); | ||
@@ -29,66 +29,66 @@ /** | ||
var FacebookApiException = function(result) { | ||
this.result = result; | ||
this.result = result; | ||
this.error = true; | ||
this.code = result.error_code ? result.error_code : 0; | ||
this.error = true; | ||
this.code = result.error_code ? result.error_code : 0; | ||
if (result.error_description) { | ||
// OAuth 2.0 Draft 10 style | ||
this.message = result.error_description; | ||
} else if (result.error && result.error.message) { | ||
// OAuth 2.0 Draft 00 style | ||
this.message = result.error.message; | ||
} else if (result.error_msg) { | ||
// Rest server style | ||
this.message = result.error_msg; | ||
} else { | ||
this.message = 'Unknown Error. Check getResult()'; | ||
} | ||
if (result.error_description) { | ||
// OAuth 2.0 Draft 10 style | ||
this.message = result.error_description; | ||
} else if (result.error && result.error.message) { | ||
// OAuth 2.0 Draft 00 style | ||
this.message = result.error.message; | ||
} else if (result.error_msg) { | ||
// Rest server style | ||
this.message = result.error_msg; | ||
} else { | ||
this.message = 'Unknown Error. Check getResult()'; | ||
} | ||
}; | ||
FacebookApiException.prototype = { | ||
// The result from the API server that represents the exception information. | ||
result: null, | ||
// The result from the API server that represents the exception information. | ||
result: null, | ||
/** | ||
* Return the associated result object returned by the API server. | ||
* | ||
* @return {Object} the result from the API server | ||
*/ | ||
getResult: function() { | ||
return this.result; | ||
}, | ||
/** | ||
* Return the associated result object returned by the API server. | ||
* | ||
* @return {Object} the result from the API server | ||
*/ | ||
getResult: function() { | ||
return this.result; | ||
}, | ||
/** | ||
* Returns the associated type for the error. This will default to | ||
* 'Exception' when a type is not available. | ||
* | ||
* @return {String} | ||
*/ | ||
getType: function() { | ||
if (this.result.error) { | ||
error = this.result.error; | ||
if (typeof error == 'string') { | ||
// OAuth 2.0 Draft 10 style | ||
return error; | ||
} else if (error.type) { | ||
// OAuth 2.0 Draft 00 style | ||
return error.type; | ||
} | ||
} | ||
return 'Exception'; | ||
}, | ||
/** | ||
* Returns the associated type for the error. This will default to | ||
* 'Exception' when a type is not available. | ||
* | ||
* @return {String} | ||
*/ | ||
getType: function() { | ||
if (this.result.error) { | ||
error = this.result.error; | ||
if (typeof error == 'string') { | ||
// OAuth 2.0 Draft 10 style | ||
return error; | ||
} else if (error.type) { | ||
// OAuth 2.0 Draft 00 style | ||
return error.type; | ||
} | ||
} | ||
return 'Exception'; | ||
}, | ||
/** | ||
* To make debugging easier. | ||
* | ||
* @return {String} the string representation of the error | ||
*/ | ||
toString: function() { | ||
str = this.getType() + ': '; | ||
if (this.code != 0) { | ||
str += this.code + ': '; | ||
} | ||
return str + this.message; | ||
} | ||
/** | ||
* To make debugging easier. | ||
* | ||
* @return {String} the string representation of the error | ||
*/ | ||
toString: function() { | ||
str = this.getType() + ': '; | ||
if (this.code != 0) { | ||
str += this.code + ': '; | ||
} | ||
return str + this.message; | ||
} | ||
}; | ||
@@ -112,22 +112,22 @@ | ||
var Facebook = exports.facebook = exports.Facebook = function(config) { | ||
var facebook; | ||
if (this instanceof Facebook) { | ||
// instantiation using the 'new' operator | ||
facebook = this; | ||
} else { | ||
// connect style middleware function | ||
// TODO: this should also function as a Facebook object, add prototype | ||
facebook = function(req, res, next) { | ||
req.facebook = new Facebook(config); | ||
req.facebook.request = req; | ||
req.facebook.response = res; | ||
next(); | ||
}; | ||
} | ||
var facebook; | ||
if (this instanceof Facebook) { | ||
// instantiation using the 'new' operator | ||
facebook = this; | ||
} else { | ||
// connect style middleware function | ||
// TODO: this should also function as a Facebook object, add prototype | ||
facebook = function(req, res, next) { | ||
req.facebook = new Facebook(config); | ||
req.facebook.request = req; | ||
req.facebook.response = res; | ||
next(); | ||
}; | ||
} | ||
for (var i in config) { | ||
facebook[i] = config[i]; | ||
} | ||
return facebook; | ||
for (var i in config) { | ||
facebook[i] = config[i]; | ||
} | ||
return facebook; | ||
}; | ||
@@ -137,771 +137,767 @@ | ||
// The Application ID. | ||
appId: null, | ||
// The Application ID. | ||
appId: null, | ||
// The Application API Secret. | ||
secret: null, | ||
// The Application API Secret. | ||
secret: null, | ||
// Url of the app | ||
siteUrl: null, | ||
// Url of the app | ||
siteUrl: null, | ||
// http.ServerRequest for initializing the session | ||
request: null, | ||
// http.ServerRequest for initializing the session | ||
request: null, | ||
// http.ServerResponse for writing the session cookie | ||
response: null, | ||
// http.ServerResponse for writing the session cookie | ||
response: null, | ||
// Base domain for the Cookie. | ||
domain: '', | ||
// Base domain for the Cookie. | ||
domain: '', | ||
// Indicates if the CURL based @ syntax for file uploads is enabled. | ||
fileUpload: false, | ||
// Indicates if the CURL based @ syntax for file uploads is enabled. | ||
fileUpload: false, | ||
// Milliseconds for connection with Facebook's servers to be established | ||
// TODO: connectTimeout: 10000, | ||
// Milliseconds for transmition of data from Facebook to complete | ||
timeout: 60000, | ||
// Milliseconds for connection with Facebook's servers to be established | ||
// TODO: connectTimeout: 10000, | ||
// Milliseconds for transmition of data from Facebook to complete | ||
timeout: 60000, | ||
// The active user session, if one is available. | ||
_session: null, | ||
// The active user session, if one is available. | ||
_session: null, | ||
// The data from the signed_request token. | ||
_signedRequest: null, | ||
// The data from the signed_request token. | ||
_signedRequest: null, | ||
// Indicates that we already loaded the session as best as we could. | ||
_sessionLoaded: false, | ||
// Indicates that we already loaded the session as best as we could. | ||
_sessionLoaded: false, | ||
// List of query parameters that get automatically dropped when rebuilding the current URL | ||
DROP_QUERY_PARAMS: [ | ||
'session', | ||
'signed_request' | ||
], | ||
// List of query parameters that get automatically dropped when rebuilding the current URL | ||
DROP_QUERY_PARAMS: [ | ||
'session', | ||
'signed_request' | ||
], | ||
// Map of aliases to Facebook domains | ||
DOMAIN_MAP: { | ||
api : 'https://api.facebook.com/', | ||
api_read : 'https://api-read.facebook.com/', | ||
graph : 'https://graph.facebook.com/', | ||
www : 'https://www.facebook.com/' | ||
}, | ||
// Map of aliases to Facebook domains | ||
DOMAIN_MAP: { | ||
api : 'https://api.facebook.com/', | ||
api_video: 'https://api-video.facebook.com/', | ||
api_read : 'https://api-read.facebook.com/', | ||
graph : 'https://graph.facebook.com/', | ||
www : 'https://www.facebook.com/' | ||
}, | ||
/** | ||
* Get the data from a signed_request token | ||
* | ||
* @return {Object} | ||
*/ | ||
getSignedRequest: function() { | ||
if (!this._signedRequest && this.request) { | ||
var parse = URL.parse(this.request.url, true); | ||
if (parse.query.signed_request) { | ||
this._signedRequest = this._parseSignedRequest(parse.query.signed_request); | ||
} | ||
} | ||
return this._signedRequest; | ||
}, | ||
/** | ||
* Get the data from a signed_request token | ||
* | ||
* @return {Object} | ||
*/ | ||
getSignedRequest: function() { | ||
if (!this._signedRequest && this.request) { | ||
var parse = URL.parse(this.request.url, true); | ||
if (parse.query.signed_request) { | ||
this._signedRequest = this._parseSignedRequest(parse.query.signed_request); | ||
} | ||
} | ||
return this._signedRequest; | ||
}, | ||
/** | ||
* Set the Session. | ||
* | ||
* @param {Object} session the session | ||
* @param {boolean} write_cookie indicate if a cookie should be written. ignored if no response object. | ||
*/ | ||
setSession: function(session, write_cookie) { | ||
write_cookie = write_cookie === undefined ? true : write_cookie; | ||
session = this._validateSessionObject(session); | ||
this._sessionLoaded = true; | ||
this._session = session; | ||
if (write_cookie) { | ||
this._setCookieFromSession(session); | ||
} | ||
return this; | ||
}, | ||
/** | ||
* Set the Session. | ||
* | ||
* @param {Object} session the session | ||
* @param {boolean} write_cookie indicate if a cookie should be written. ignored if no response object. | ||
*/ | ||
setSession: function(session, write_cookie) { | ||
write_cookie = write_cookie === undefined ? true : write_cookie; | ||
session = this._validateSessionObject(session); | ||
this._sessionLoaded = true; | ||
this._session = session; | ||
if (write_cookie) { | ||
this._setCookieFromSession(session); | ||
} | ||
return this; | ||
}, | ||
/** | ||
* Get the session object. This will automatically look for a signed session | ||
* sent via the signed_request, Cookie or Query Parameters if needed. | ||
* | ||
* @return {Object} the session | ||
*/ | ||
getSession: function() { | ||
if (!this._sessionLoaded) { | ||
var session = null; | ||
var write_cookie = true; | ||
/** | ||
* Get the session object. This will automatically look for a signed session | ||
* sent via the signed_request, Cookie or Query Parameters if needed. | ||
* | ||
* @return {Object} the session | ||
*/ | ||
getSession: function() { | ||
if (!this._sessionLoaded) { | ||
var session = null; | ||
var write_cookie = true; | ||
// try loading session from signed_request in request | ||
signedRequest = this.getSignedRequest(); | ||
if (signedRequest) { | ||
// sig is good, use the signedRequest | ||
session = this._createSessionFromSignedRequest(signedRequest); | ||
} | ||
// try loading session from signed_request in request | ||
signedRequest = this.getSignedRequest(); | ||
if (signedRequest) { | ||
// sig is good, use the signedRequest | ||
session = this._createSessionFromSignedRequest(signedRequest); | ||
} | ||
// try loading session from request | ||
// TODO: this works from querystring requests, make it work with POST, PUT and DELETE data (aka express support) | ||
if (!session && this.request) { | ||
var parse = URL.parse(this.request.url, true); | ||
if (parse.query.session) { | ||
session = JSON.parse(parse.query.session); | ||
session = this._validateSessionObject(session); | ||
} | ||
} | ||
// try loading session from request | ||
// TODO: this works from querystring requests, make it work with POST, PUT and DELETE data (aka express support) | ||
if (!session && this.request) { | ||
var parse = URL.parse(this.request.url, true); | ||
if (parse.query.session) { | ||
session = JSON.parse(parse.query.session); | ||
session = this._validateSessionObject(session); | ||
} | ||
} | ||
// try loading session from cookie if necessary | ||
if (!session && this.request) { | ||
var cookie = this._getSessionCookie(); | ||
if (cookie) { | ||
var cookie = cookie.replace(/^"*|"*$/g, ''); | ||
session = querystring.parse(cookie); | ||
session = this._validateSessionObject(session); | ||
// write only if we need to delete a invalid session cookie | ||
write_cookie = !session; | ||
} | ||
} | ||
// try loading session from cookie if necessary | ||
if (!session && this.request) { | ||
var cookie = this._getSessionCookie(); | ||
if (cookie) { | ||
var cookie = cookie.replace(/^"*|"*$/g, ''); | ||
session = querystring.parse(cookie); | ||
session = this._validateSessionObject(session); | ||
// write only if we need to delete a invalid session cookie | ||
write_cookie = !session; | ||
} | ||
} | ||
this.setSession(session, write_cookie); | ||
} | ||
this.setSession(session, write_cookie); | ||
} | ||
return this._session; | ||
}, | ||
return this._session; | ||
}, | ||
// TODO: make this work with express cookies | ||
// TODO: this cookie parsing may still not be quite right, consult the RFC or just use connect | ||
_getSessionCookie: function() { | ||
if (!this.request.headers.cookie) { | ||
return; | ||
} | ||
var cookieName = this._getSessionCookieName(); | ||
var cookies = {}; | ||
this.request.headers.cookie.split(';').forEach(function(cookie) { | ||
var split = cookie.indexOf('='); | ||
if (split > 0) { | ||
cookies[cookie.substr(0, split).trim()] = querystring.unescape(cookie.substr(split + 1)).trim(); | ||
} | ||
}); | ||
return cookies[cookieName]; | ||
}, | ||
// TODO: make this work with express cookies | ||
// TODO: this cookie parsing may still not be quite right, consult the RFC or just use connect | ||
_getSessionCookie: function() { | ||
if (!this.request.headers.cookie) { | ||
return; | ||
} | ||
var cookieName = this._getSessionCookieName(); | ||
var cookies = {}; | ||
this.request.headers.cookie.split(';').forEach(function(cookie) { | ||
var split = cookie.indexOf('='); | ||
if (split > 0) { | ||
cookies[cookie.substr(0, split).trim()] = querystring.unescape(cookie.substr(split + 1)).trim(); | ||
} | ||
}); | ||
return cookies[cookieName]; | ||
}, | ||
/** | ||
* Get the UID from the session. | ||
* | ||
* @return {String} the UID if available | ||
*/ | ||
getUser: function() { | ||
session = this.getSession(); | ||
return session ? session.uid : null; | ||
}, | ||
/** | ||
* Get the UID from the session. | ||
* | ||
* @return {String} the UID if available | ||
*/ | ||
getUser: function() { | ||
session = this.getSession(); | ||
return session ? session.uid : null; | ||
}, | ||
/** | ||
* Gets a OAuth access token. | ||
* | ||
* @return {String} the access token | ||
*/ | ||
getAccessToken: function() { | ||
session = this.getSession(); | ||
// either user session signed, or app signed | ||
if (session) { | ||
return session.access_token; | ||
} else { | ||
return this.appId +'|'+ this.secret; | ||
} | ||
}, | ||
/** | ||
* Gets a OAuth access token. | ||
* | ||
* @return {String} the access token | ||
*/ | ||
getAccessToken: function() { | ||
session = this.getSession(); | ||
// either user session signed, or app signed | ||
if (session) { | ||
return session.access_token; | ||
} else { | ||
return this.appId +'|'+ this.secret; | ||
} | ||
}, | ||
/** | ||
* Get a Login URL for use with redirects. By default, full page redirect is | ||
* assumed. If you are using the generated URL with a window.open() call in | ||
* JavaScript, you can pass in display=popup as part of the params. | ||
* | ||
* The parameters (optional): | ||
* - next: the url to go to after a successful login | ||
* - cancel_url: the url to go to after the user cancels | ||
* - req_perms: comma separated list of requested extended perms | ||
* - display: can be "page" (default, full page) or "popup" | ||
* | ||
* @param {Object} params provide custom parameters | ||
* @return {String} the URL for the login flow | ||
*/ | ||
getLoginUrl: function(params) { | ||
params = params || {}; | ||
currentUrl = this._getCurrentUrl(); | ||
/** | ||
* Get a Login URL for use with redirects. By default, full page redirect is | ||
* assumed. If you are using the generated URL with a window.open() call in | ||
* JavaScript, you can pass in display=popup as part of the params. | ||
* | ||
* The parameters (optional): | ||
* - next: the url to go to after a successful login | ||
* - cancel_url: the url to go to after the user cancels | ||
* - req_perms: comma separated list of requested extended perms | ||
* - display: can be "page" (default, full page) or "popup" | ||
* | ||
* @param {Object} params provide custom parameters | ||
* @return {String} the URL for the login flow | ||
*/ | ||
getLoginUrl: function(params) { | ||
params = params || {}; | ||
currentUrl = this._getCurrentUrl(); | ||
var defaults = { | ||
api_key : this.appId, | ||
cancel_url : currentUrl, | ||
display : 'page', | ||
fbconnect : 1, | ||
next : currentUrl, | ||
return_session : 1, | ||
session_version : 3, | ||
v : '1.0' | ||
}; | ||
for (var i in defaults) { | ||
params[i] = params[i] || defaults[i]; | ||
} | ||
var defaults = { | ||
api_key : this.appId, | ||
cancel_url : currentUrl, | ||
display : 'page', | ||
fbconnect : 1, | ||
next : currentUrl, | ||
return_session : 1, | ||
session_version : 3, | ||
v : '1.0' | ||
}; | ||
for (var i in defaults) { | ||
params[i] = params[i] || defaults[i]; | ||
} | ||
return this._getUrl('www', 'login.php', params); | ||
}, | ||
return this._getUrl('www', 'login.php', params); | ||
}, | ||
/** | ||
* Get a Logout URL suitable for use with redirects. | ||
* | ||
* The parameters: | ||
* - next: the url to go to after a successful logout | ||
* | ||
* @param {Object} params provide custom parameters | ||
* @return {String} the URL for the logout flow | ||
*/ | ||
getLogoutUrl: function(params) { | ||
params = params || {}; | ||
/** | ||
* Get a Logout URL suitable for use with redirects. | ||
* | ||
* The parameters: | ||
* - next: the url to go to after a successful logout | ||
* | ||
* @param {Object} params provide custom parameters | ||
* @return {String} the URL for the logout flow | ||
*/ | ||
getLogoutUrl: function(params) { | ||
params = params || {}; | ||
var defaults = { | ||
next : this._getCurrentUrl(), | ||
access_token : this.getAccessToken() | ||
}; | ||
for (var i in defaults) { | ||
params[i] = params[i] || defaults[i]; | ||
} | ||
var defaults = { | ||
next : this._getCurrentUrl(), | ||
access_token : this.getAccessToken() | ||
}; | ||
for (var i in defaults) { | ||
params[i] = params[i] || defaults[i]; | ||
} | ||
return this._getUrl('www', 'logout.php', params); | ||
}, | ||
return this._getUrl('www', 'logout.php', params); | ||
}, | ||
/** | ||
* Get a login status URL to fetch the status from facebook. | ||
* | ||
* The parameters: | ||
* - ok_session: the URL to go to if a session is found | ||
* - no_session: the URL to go to if the user is not connected | ||
* - no_user: the URL to go to if the user is not signed into facebook | ||
* | ||
* @param {Object} params provide custom parameters | ||
* @return {String} the URL for the logout flow | ||
*/ | ||
getLoginStatusUrl: function(params) { | ||
params = params || {}; | ||
/** | ||
* Get a login status URL to fetch the status from facebook. | ||
* | ||
* The parameters: | ||
* - ok_session: the URL to go to if a session is found | ||
* - no_session: the URL to go to if the user is not connected | ||
* - no_user: the URL to go to if the user is not signed into facebook | ||
* | ||
* @param {Object} params provide custom parameters | ||
* @return {String} the URL for the logout flow | ||
*/ | ||
getLoginStatusUrl: function(params) { | ||
params = params || {}; | ||
var defaults = { | ||
api_key : this.appId, | ||
no_session : this._getCurrentUrl(), | ||
no_user : this._getCurrentUrl(), | ||
ok_session : this._getCurrentUrl(), | ||
session_version : 3 | ||
}; | ||
for (var i in defaults) { | ||
params[i] = params[i] || defaults[i]; | ||
} | ||
var defaults = { | ||
api_key : this.appId, | ||
no_session : this._getCurrentUrl(), | ||
no_user : this._getCurrentUrl(), | ||
ok_session : this._getCurrentUrl(), | ||
session_version : 3 | ||
}; | ||
for (var i in defaults) { | ||
params[i] = params[i] || defaults[i]; | ||
} | ||
return this._getUrl('www', 'extern/login_status.php', params); | ||
}, | ||
return this._getUrl('www', 'extern/login_status.php', params); | ||
}, | ||
/** | ||
* Make an API call. | ||
*/ | ||
api: function(/* polymorphic */) { | ||
if (typeof arguments[0] == 'object') { | ||
this._restserver.apply(this, arguments); | ||
} else { | ||
this._graph.apply(this, arguments); | ||
} | ||
}, | ||
/** | ||
* Make an API call. | ||
*/ | ||
api: function(/* polymorphic */) { | ||
if (typeof arguments[0] == 'object') { | ||
this._restserver.apply(this, arguments); | ||
} else { | ||
this._graph.apply(this, arguments); | ||
} | ||
}, | ||
/** | ||
* Invoke the old restserver.php endpoint. | ||
* | ||
* @param {Object} params method call object | ||
* @param {Function( object )} callback to send the decoded response object | ||
*/ | ||
_restserver: function(params, callback) { | ||
// generic application level parameters | ||
params.api_key = this.appId; | ||
params.format = 'json-strings'; | ||
/** | ||
* Invoke the old restserver.php endpoint. | ||
* | ||
* @param {Object} params method call object | ||
* @param {Function( object )} callback to send the decoded response object | ||
*/ | ||
_restserver: function(params, callback) { | ||
// generic application level parameters | ||
params.api_key = this.appId; | ||
params.format = 'json-strings'; | ||
this._oauthRequest( | ||
this._getApiUrl(params.method), | ||
params, | ||
function(result) { | ||
result = JSON.parse(result); | ||
if (result && result.error_code) { | ||
result = new FacebookApiException(result); | ||
} | ||
callback(result); | ||
}, | ||
callback | ||
); | ||
}, | ||
this._oauthRequest( | ||
this._getApiUrl(params.method), | ||
params, | ||
function(result) { | ||
result = JSON.parse(result); | ||
if (result && result.error_code) { | ||
result = new FacebookApiException(result); | ||
} | ||
callback(result); | ||
}, | ||
callback | ||
); | ||
}, | ||
/** | ||
* Invoke the Graph API. | ||
* | ||
* @param {String} path the path (required) | ||
* @param {String} method the http method (default 'GET') | ||
* @param {Object} params the query/post data | ||
* @param {Function( object )} callback to send the decoded response object | ||
*/ | ||
_graph: function(path, method, params, callback) { | ||
var self = this; | ||
/** | ||
* Invoke the Graph API. | ||
* | ||
* @param {String} path the path (required) | ||
* @param {String} method the http method (default 'GET') | ||
* @param {Object} params the query/post data | ||
* @param {Function( object )} callback to send the decoded response object | ||
*/ | ||
_graph: function(path, method, params, callback) { | ||
var self = this; | ||
if (typeof method != 'string') { | ||
callback = params; | ||
params = method || {}; | ||
method = params.method || 'GET'; | ||
} | ||
if (typeof params == 'function') { | ||
callback = params; | ||
params = {}; | ||
} | ||
params.method = method; | ||
if (typeof method != 'string') { | ||
callback = params; | ||
params = method || {}; | ||
method = params.method || 'GET'; | ||
} | ||
if (typeof params == 'function') { | ||
callback = params; | ||
params = {}; | ||
} | ||
params.method = method; | ||
this._oauthRequest( | ||
this._getUrl('graph', path), | ||
params, | ||
function(result) { | ||
result = JSON.parse(result); | ||
if (result && result.error) { | ||
var result = new FacebookApiException(result); | ||
switch (result.getType()) { | ||
// OAuth 2.0 Draft 00 style | ||
case 'OAuthException': | ||
// OAuth 2.0 Draft 10 style | ||
case 'invalid_token': | ||
self.setSession(null); | ||
} | ||
} | ||
callback && callback(result); | ||
}, | ||
callback | ||
); | ||
}, | ||
this._oauthRequest( | ||
this._getUrl('graph', path), | ||
params, | ||
function(result) { | ||
result = JSON.parse(result); | ||
if (result && result.error) { | ||
var result = new FacebookApiException(result); | ||
switch (result.getType()) { | ||
case 'OAuthException': // OAuth 2.0 Draft 00 style | ||
case 'invalid_token': // OAuth 2.0 Draft 10 style | ||
// TODO: test and check if headers have alread been sent | ||
try { | ||
self.setSession(null); | ||
} catch (err) { | ||
console.log(err); | ||
} | ||
} | ||
} | ||
callback && callback(result); | ||
}, | ||
callback | ||
); | ||
}, | ||
/** | ||
* Make a OAuth Request | ||
* | ||
* @param {String} path the path (required) | ||
* @param {Object} params the query/post data | ||
* @param {Function( string )} success to send the raw response string | ||
* @param {Function( FacebookApiException )} error to send the error on failure | ||
*/ | ||
_oauthRequest: function(url, params, success, error) { | ||
if (!params.access_token) { | ||
params.access_token = this.getAccessToken(); | ||
} | ||
/** | ||
* Make a OAuth Request | ||
* | ||
* @param {String} path the path (required) | ||
* @param {Object} params the query/post data | ||
* @param {Function( string )} success to send the raw response string | ||
* @param {Function( FacebookApiException )} error to send the error on failure | ||
*/ | ||
_oauthRequest: function(url, params, success, error) { | ||
if (!params.access_token) { | ||
params.access_token = this.getAccessToken(); | ||
} | ||
// json encode all params values that are not strings | ||
// TODO: untested | ||
for (var key in params) { | ||
if (typeof params[key] == 'object') { | ||
params[key] = JSON.stringify(params[key]); | ||
} | ||
} | ||
// json encode all params values that are not strings | ||
// TODO: untested | ||
for (var key in params) { | ||
if (typeof params[key] == 'object') { | ||
params[key] = JSON.stringify(params[key]); | ||
} | ||
} | ||
this._makeRequest(url, params, success, error); | ||
}, | ||
this._makeRequest(url, params, success, error); | ||
}, | ||
/** | ||
* Makes an HTTP request. This method can be overriden by subclasses if | ||
* developers want to do fancier things or use something other than curl to | ||
* make the request. | ||
* | ||
* @param {String} url the URL to make the request to | ||
* @param {Object} params the parameters to use for the POST body | ||
* @param {Function( string )} success callback to send the raw response data | ||
* @param {Function{ FacebookApiException }} error callback to send an error object | ||
*/ | ||
_makeRequest: function(url, params, success, error) { | ||
var parts = URL.parse(url); | ||
/** | ||
* Makes an HTTP request. This method can be overriden by subclasses if | ||
* developers want to do fancier things or use something other than curl to | ||
* make the request. | ||
* | ||
* @param {String} url the URL to make the request to | ||
* @param {Object} params the parameters to use for the POST body | ||
* @param {Function( string )} success callback to send the raw response data | ||
* @param {Function{ FacebookApiException }} error callback to send an error object | ||
*/ | ||
_makeRequest: function(url, params, success, error) { | ||
var parts = URL.parse(url); | ||
var protocol = http; | ||
var port = 80; | ||
if (parts.protocol == 'https:') { | ||
protocol = https; | ||
port = 443; | ||
} | ||
var protocol = http; | ||
var port = 80; | ||
if (parts.protocol == 'https:') { | ||
protocol = https; | ||
port = 443; | ||
} | ||
var options = { | ||
host: parts.hostname, | ||
port: parts.port ? parts.port : port, | ||
path: parts.pathname, | ||
method: 'POST' | ||
}; | ||
var options = { | ||
host: parts.hostname, | ||
port: parts.port ? parts.port : port, | ||
path: parts.pathname, | ||
method: 'POST' | ||
}; | ||
// TODO: header 'Expect: 100-continue'? This was a part of the original curl makeRequest | ||
// TODO: header 'Expect: 100-continue'? This was a part of the original curl makeRequest | ||
var request = protocol.request(options, function(result) { | ||
result.setEncoding('utf8'); | ||
var request = protocol.request(options, function(result) { | ||
result.setEncoding('utf8'); | ||
var body = ''; | ||
result.on('data', function(chunk) { | ||
body += chunk; | ||
}); | ||
var body = ''; | ||
result.on('data', function(chunk) { | ||
body += chunk; | ||
}); | ||
result.on('end', function() { | ||
clearTimeout(timeout); | ||
success(body); | ||
}); | ||
}); | ||
result.on('end', function() { | ||
clearTimeout(timeout); | ||
success(body); | ||
}); | ||
}); | ||
// TODO? | ||
// if (this.useFileUploadSupport()) { | ||
// opts[CURLOPT_POSTFIELDS] = params; | ||
// } else { | ||
// opts[CURLOPT_POSTFIELDS] = http_build_query(params, null, '&'); | ||
// } | ||
request.write(querystring.stringify(params)); | ||
request.end(); | ||
// TODO? | ||
// if (this.useFileUploadSupport()) { | ||
// opts[CURLOPT_POSTFIELDS] = params; | ||
// } else { | ||
// opts[CURLOPT_POSTFIELDS] = http_build_query(params, null, '&'); | ||
// } | ||
request.write(querystring.stringify(params)); | ||
request.end(); | ||
var timeout = setTimeout(function() { | ||
request.abort(); | ||
var e = new FacebookApiException({ | ||
error_code : 28 /* CURLE_OPERATION_TIMEDOUT */, | ||
error : { | ||
message : 'timeout', | ||
type : 'CurlException' | ||
} | ||
}); | ||
error && error(e); | ||
}, this.timeout); | ||
}, | ||
var timeout = setTimeout(function() { | ||
request.abort(); | ||
var e = new FacebookApiException({ | ||
error_code : 28 /* CURLE_OPERATION_TIMEDOUT */, | ||
error : { | ||
message : 'timeout', | ||
type : 'CurlException' | ||
} | ||
}); | ||
error && error(e); | ||
}, this.timeout); | ||
}, | ||
/** | ||
* The name of the Cookie that contains the session. | ||
* | ||
* @return {String} the cookie name | ||
*/ | ||
_getSessionCookieName: function() { | ||
return 'fbs_' + this.appId; | ||
}, | ||
/** | ||
* The name of the Cookie that contains the session. | ||
* | ||
* @return {String} the cookie name | ||
*/ | ||
_getSessionCookieName: function() { | ||
return 'fbs_' + this.appId; | ||
}, | ||
/** | ||
* Set a JS Cookie based on the _passed in_ session. It does not use the | ||
* currently stored session -- you need to explicitly pass it in. | ||
* | ||
* @param {Object} session the session to use for setting the cookie | ||
*/ | ||
_setCookieFromSession: function(session) { | ||
if (!this.response) { | ||
return; | ||
} | ||
/** | ||
* Set a JS Cookie based on the _passed in_ session. It does not use the | ||
* currently stored session -- you need to explicitly pass it in. | ||
* | ||
* @param {Object} session the session to use for setting the cookie | ||
*/ | ||
_setCookieFromSession: function(session) { | ||
if (!this.response) { | ||
return; | ||
} | ||
var cookieName = this._getSessionCookieName(); | ||
var value = 'deleted'; | ||
var expires = new Date(Date.now() - 3600000); | ||
var domain = this.domain; | ||
if (session) { | ||
value = '"' + querystring.stringify(session) + '"'; | ||
if (session.base_domain) { | ||
domain = session.base_domain; | ||
} | ||
expires = new Date(session.expires * 1000); | ||
} | ||
// prepend dot if a domain is found | ||
if (domain) { | ||
domain = '.' + domain; | ||
} | ||
// if an existing cookie is not set, we dont need to delete it | ||
// TODO: how do we know the cookie does not exist? | ||
//if (value == 'deleted' && empty(_COOKIE[cookieName])) { | ||
// return; | ||
//} | ||
// TODO: is this relevant for node.js? | ||
//if (headers_sent()) { | ||
// this._errorLog('Could not set cookie. Headers already sent.'); | ||
//} else { | ||
this._setCookie(cookieName, value, expires, '/', domain); | ||
//} | ||
}, | ||
var cookieName = this._getSessionCookieName(); | ||
var value = 'deleted'; | ||
var expires = new Date(Date.now() - 3600000); | ||
var domain = this.domain; | ||
if (session) { | ||
value = '"' + querystring.stringify(session) + '"'; | ||
if (session.base_domain) { | ||
domain = session.base_domain; | ||
} | ||
expires = new Date(session.expires * 1000); | ||
} | ||
// prepend dot if a domain is found | ||
if (domain) { | ||
domain = '.' + domain; | ||
} | ||
// if an existing cookie is not set, we dont need to delete it | ||
// TODO: how do we know the cookie does not exist? | ||
//if (value == 'deleted' && empty(_COOKIE[cookieName])) { | ||
// return; | ||
//} | ||
// TODO: is this relevant for node.js? | ||
//if (headers_sent()) { | ||
// this._errorLog('Could not set cookie. Headers already sent.'); | ||
//} else { | ||
this._setCookie(cookieName, value, expires, '/', domain); | ||
//} | ||
}, | ||
/** | ||
* Set the cookie in the http response. | ||
* | ||
* @param {String} name of cookie | ||
* @param {String} value of cookie | ||
* @param {Date} expires the date the cookie should expire | ||
* @param {String} path under which the cookie should be available | ||
* @param {String} domain of sites where the cookie should be available | ||
*/ | ||
_setCookie: function(name, value, expires, path, domain) { | ||
// TODO: express support | ||
var cookie = querystring.escape(name) + '=' + querystring.escape(value); | ||
if (expires) { | ||
cookie += '; expires=' + expires.toUTCString(); | ||
} | ||
if (path) { | ||
cookie += '; path=' + path; | ||
} | ||
if (domain) { | ||
cookie += '; domain=' + domain; | ||
} | ||
this.response.setHeader('Set-Cookie', cookie); | ||
}, | ||
/** | ||
* Set the cookie in the http response. | ||
* | ||
* @param {String} name of cookie | ||
* @param {String} value of cookie | ||
* @param {Date} expires the date the cookie should expire | ||
* @param {String} path under which the cookie should be available | ||
* @param {String} domain of sites where the cookie should be available | ||
*/ | ||
_setCookie: function(name, value, expires, path, domain) { | ||
// TODO: express support | ||
var cookie = querystring.escape(name) + '=' + querystring.escape(value); | ||
if (expires) { | ||
cookie += '; expires=' + expires.toUTCString(); | ||
} | ||
if (path) { | ||
cookie += '; path=' + path; | ||
} | ||
if (domain) { | ||
cookie += '; domain=' + domain; | ||
} | ||
this.response.setHeader('Set-Cookie', cookie); | ||
}, | ||
/** | ||
* Validates a session_version=3 style session object. | ||
* | ||
* @param {Object} session the session object | ||
* @return {Object} the session object if it validates, null otherwise | ||
*/ | ||
_validateSessionObject: function(session) { | ||
// make sure some essential fields exist | ||
if (session && | ||
session.uid && | ||
session.access_token && | ||
session.sig) { | ||
// validate the signature | ||
session_without_sig = {}; | ||
for (var key in session) { | ||
if (key != 'sig') { | ||
session_without_sig[key] = session[key]; | ||
} | ||
} | ||
expected_sig = this._generateSignature( | ||
session_without_sig, | ||
this.secret | ||
); | ||
if (session.sig != expected_sig) { | ||
this._errorLog('Got invalid session signature in cookie.'); | ||
session = null; | ||
} | ||
// check expiry time | ||
} else { | ||
session = null; | ||
} | ||
return session; | ||
}, | ||
/** | ||
* Validates a session_version=3 style session object. | ||
* | ||
* @param {Object} session the session object | ||
* @return {Object} the session object if it validates, null otherwise | ||
*/ | ||
_validateSessionObject: function(session) { | ||
// make sure some essential fields exist | ||
if (session && | ||
session.uid && | ||
session.access_token && | ||
session.sig) { | ||
expected_sig = this._generateSignature(session, this.secret); | ||
if (session.sig != expected_sig) { | ||
this._errorLog('Got invalid session signature in cookie.'); | ||
session = null; | ||
} | ||
// check expiry time | ||
} else { | ||
session = null; | ||
} | ||
return session; | ||
}, | ||
/** | ||
* Returns something that looks like our JS session object from the | ||
* signed token's data | ||
* | ||
* TODO: Nuke this once the login flow uses OAuth2 | ||
* | ||
* @param {Object} data the output of getSignedRequest | ||
* @return {Object} Something that will work as a session | ||
*/ | ||
_createSessionFromSignedRequest: function(data) { | ||
if (!data.oauth_token) { | ||
return null; | ||
} | ||
/** | ||
* Returns something that looks like our JS session object from the | ||
* signed token's data | ||
* | ||
* TODO: Nuke this once the login flow uses OAuth2 | ||
* | ||
* @param {Object} data the output of getSignedRequest | ||
* @return {Object} Something that will work as a session | ||
*/ | ||
_createSessionFromSignedRequest: function(data) { | ||
if (!data.oauth_token) { | ||
return null; | ||
} | ||
session = { | ||
uid : data.user_id, | ||
access_token : data.oauth_token, | ||
expires : data.expires | ||
}; | ||
session = { | ||
uid : data.user_id, | ||
access_token : data.oauth_token, | ||
expires : data.expires | ||
}; | ||
// put a real sig, so that validateSignature works | ||
session.sig = this._generateSignature( | ||
session, | ||
this.secret | ||
); | ||
// put a real sig, so that validateSignature works | ||
session.sig = this._generateSignature(session, this.secret); | ||
return session; | ||
}, | ||
return session; | ||
}, | ||
/** | ||
* Parses a signed_request and validates the signature. | ||
* Then saves it in this.signed_data | ||
* | ||
* @param {String} signed_request A signed token | ||
* @return {Object} the payload inside it or null if the sig is wrong | ||
*/ | ||
_parseSignedRequest: function(signed_request) { | ||
var split = signed_request.split('.', 2); | ||
if (split.length != 2) { | ||
return null; | ||
} | ||
var encoded_sig = split[0]; | ||
var payload = split[1]; | ||
/** | ||
* Parses a signed_request and validates the signature. | ||
* Then saves it in this.signed_data | ||
* | ||
* @param {String} signed_request A signed token | ||
* @return {Object} the payload inside it or null if the sig is wrong | ||
*/ | ||
_parseSignedRequest: function(signed_request) { | ||
var split = signed_request.split('.', 2); | ||
if (split.length != 2) { | ||
return null; | ||
} | ||
var encoded_sig = split[0]; | ||
var payload = split[1]; | ||
// decode the data | ||
sig = this._base64UrlDecode(encoded_sig); | ||
data = JSON.parse(this._base64UrlDecode(payload)); | ||
// decode the data | ||
sig = this._base64UrlDecode(encoded_sig); | ||
data = JSON.parse(this._base64UrlDecode(payload)); | ||
if (data.algorithm.toUpperCase() !== 'HMAC-SHA256') { | ||
this._errorLog('Unknown algorithm. Expected HMAC-SHA256'); | ||
return null; | ||
} | ||
if (data.algorithm.toUpperCase() !== 'HMAC-SHA256') { | ||
this._errorLog('Unknown algorithm. Expected HMAC-SHA256'); | ||
return null; | ||
} | ||
// check sig | ||
var hmac = crypto.createHmac('sha256', this.secret); | ||
hmac.update(payload); | ||
expected_sig = hmac.digest(); | ||
if (sig !== expected_sig) { | ||
this._errorLog('Bad Signed JSON signature!'); | ||
return null; | ||
} | ||
// check sig | ||
var hmac = crypto.createHmac('sha256', this.secret); | ||
hmac.update(payload); | ||
expected_sig = hmac.digest(); | ||
if (sig !== expected_sig) { | ||
this._errorLog('Bad Signed JSON signature!'); | ||
return null; | ||
} | ||
return data; | ||
}, | ||
return data; | ||
}, | ||
/** | ||
* Build the URL for api given parameters. | ||
* | ||
* @param {String} method the method name. | ||
* @return {String} the URL for the given parameters | ||
*/ | ||
_getApiUrl: function(method) { | ||
const READ_ONLY_CALLS = { | ||
'admin.getallocation' : 1, | ||
'admin.getappproperties' : 1, | ||
'admin.getbannedusers' : 1, | ||
'admin.getlivestreamvialink' : 1, | ||
'admin.getmetrics' : 1, | ||
'admin.getrestrictioninfo' : 1, | ||
'application.getpublicinfo' : 1, | ||
'auth.getapppublickey' : 1, | ||
'auth.getsession' : 1, | ||
'auth.getsignedpublicsessiondata' : 1, | ||
'comments.get' : 1, | ||
'connect.getunconnectedfriendscount' : 1, | ||
'dashboard.getactivity' : 1, | ||
'dashboard.getcount' : 1, | ||
'dashboard.getglobalnews' : 1, | ||
'dashboard.getnews' : 1, | ||
'dashboard.multigetcount' : 1, | ||
'dashboard.multigetnews' : 1, | ||
'data.getcookies' : 1, | ||
'events.get' : 1, | ||
'events.getmembers' : 1, | ||
'fbml.getcustomtags' : 1, | ||
'feed.getappfriendstories' : 1, | ||
'feed.getregisteredtemplatebundlebyid' : 1, | ||
'feed.getregisteredtemplatebundles' : 1, | ||
'fql.multiquery' : 1, | ||
'fql.query' : 1, | ||
'friends.arefriends' : 1, | ||
'friends.get' : 1, | ||
'friends.getappusers' : 1, | ||
'friends.getlists' : 1, | ||
'friends.getmutualfriends' : 1, | ||
'gifts.get' : 1, | ||
'groups.get' : 1, | ||
'groups.getmembers' : 1, | ||
'intl.gettranslations' : 1, | ||
'links.get' : 1, | ||
'notes.get' : 1, | ||
'notifications.get' : 1, | ||
'pages.getinfo' : 1, | ||
'pages.isadmin' : 1, | ||
'pages.isappadded' : 1, | ||
'pages.isfan' : 1, | ||
'permissions.checkavailableapiaccess' : 1, | ||
'permissions.checkgrantedapiaccess' : 1, | ||
'photos.get' : 1, | ||
'photos.getalbums' : 1, | ||
'photos.gettags' : 1, | ||
'profile.getinfo' : 1, | ||
'profile.getinfooptions' : 1, | ||
'stream.get' : 1, | ||
'stream.getcomments' : 1, | ||
'stream.getfilters' : 1, | ||
'users.getinfo' : 1, | ||
'users.getloggedinuser' : 1, | ||
'users.getstandardinfo' : 1, | ||
'users.hasapppermission' : 1, | ||
'users.isappuser' : 1, | ||
'users.isverified' : 1, | ||
'video.getuploadlimits' : 1 | ||
}; | ||
var name = 'api'; | ||
if (READ_ONLY_CALLS[method.toLowerCase()]) { | ||
name = 'api_read'; | ||
} | ||
return this._getUrl(name, 'restserver.php'); | ||
}, | ||
/** | ||
* Build the URL for api given parameters. | ||
* | ||
* @param {String} method the method name. | ||
* @return {String} the URL for the given parameters | ||
*/ | ||
_getApiUrl: function(method) { | ||
const READ_ONLY_CALLS = { | ||
'admin.getallocation' : 1, | ||
'admin.getappproperties' : 1, | ||
'admin.getbannedusers' : 1, | ||
'admin.getlivestreamvialink' : 1, | ||
'admin.getmetrics' : 1, | ||
'admin.getrestrictioninfo' : 1, | ||
'application.getpublicinfo' : 1, | ||
'auth.getapppublickey' : 1, | ||
'auth.getsession' : 1, | ||
'auth.getsignedpublicsessiondata' : 1, | ||
'comments.get' : 1, | ||
'connect.getunconnectedfriendscount' : 1, | ||
'dashboard.getactivity' : 1, | ||
'dashboard.getcount' : 1, | ||
'dashboard.getglobalnews' : 1, | ||
'dashboard.getnews' : 1, | ||
'dashboard.multigetcount' : 1, | ||
'dashboard.multigetnews' : 1, | ||
'data.getcookies' : 1, | ||
'events.get' : 1, | ||
'events.getmembers' : 1, | ||
'fbml.getcustomtags' : 1, | ||
'feed.getappfriendstories' : 1, | ||
'feed.getregisteredtemplatebundlebyid' : 1, | ||
'feed.getregisteredtemplatebundles' : 1, | ||
'fql.multiquery' : 1, | ||
'fql.query' : 1, | ||
'friends.arefriends' : 1, | ||
'friends.get' : 1, | ||
'friends.getappusers' : 1, | ||
'friends.getlists' : 1, | ||
'friends.getmutualfriends' : 1, | ||
'gifts.get' : 1, | ||
'groups.get' : 1, | ||
'groups.getmembers' : 1, | ||
'intl.gettranslations' : 1, | ||
'links.get' : 1, | ||
'notes.get' : 1, | ||
'notifications.get' : 1, | ||
'pages.getinfo' : 1, | ||
'pages.isadmin' : 1, | ||
'pages.isappadded' : 1, | ||
'pages.isfan' : 1, | ||
'permissions.checkavailableapiaccess' : 1, | ||
'permissions.checkgrantedapiaccess' : 1, | ||
'photos.get' : 1, | ||
'photos.getalbums' : 1, | ||
'photos.gettags' : 1, | ||
'profile.getinfo' : 1, | ||
'profile.getinfooptions' : 1, | ||
'stream.get' : 1, | ||
'stream.getcomments' : 1, | ||
'stream.getfilters' : 1, | ||
'users.getinfo' : 1, | ||
'users.getloggedinuser' : 1, | ||
'users.getstandardinfo' : 1, | ||
'users.hasapppermission' : 1, | ||
'users.isappuser' : 1, | ||
'users.isverified' : 1, | ||
'video.getuploadlimits' : 1 | ||
}; | ||
var name = 'api'; | ||
method = method.toLowerCase(); | ||
if (READ_ONLY_CALLS[method]) { | ||
name = 'api_read'; | ||
} else if (method === 'video.upload') { | ||
name = 'api_video'; | ||
} | ||
return this._getUrl(name, 'restserver.php'); | ||
}, | ||
/** | ||
* Build the URL for given domain alias, path and parameters. | ||
* | ||
* @param {String} name the name of the domain | ||
* @param {String} path optional path (without a leading slash) | ||
* @param {Object} params optional query parameters | ||
* @return {String} the URL for the given parameters | ||
*/ | ||
_getUrl: function(name, path, params) { | ||
var url = this.DOMAIN_MAP[name]; | ||
if (path) { | ||
if (path[0] === '/') { | ||
path = path.substr(1); | ||
} | ||
url += path; | ||
} | ||
if (params) { | ||
url += '?' + querystring.stringify(params); | ||
} | ||
return url; | ||
}, | ||
/** | ||
* Build the URL for given domain alias, path and parameters. | ||
* | ||
* @param {String} name the name of the domain | ||
* @param {String} path optional path (without a leading slash) | ||
* @param {Object} params optional query parameters | ||
* @return {String} the URL for the given parameters | ||
*/ | ||
_getUrl: function(name, path, params) { | ||
var url = this.DOMAIN_MAP[name]; | ||
if (path) { | ||
if (path[0] === '/') { | ||
path = path.substr(1); | ||
} | ||
url += path; | ||
} | ||
if (params) { | ||
url += '?' + querystring.stringify(params); | ||
} | ||
return url; | ||
}, | ||
/** | ||
* Returns the Current URL, stripping it of known FB parameters that should | ||
* not persist. | ||
* | ||
* @return {String} the current URL | ||
*/ | ||
_getCurrentUrl: function() { | ||
if (this.siteUrl) { | ||
var site = URL.parse(this.siteUrl); | ||
} else if (this.request && this.request.headers.host) { | ||
var site = { | ||
protocol: 'http:', // TODO: can we detect this? | ||
host: this.request.headers.host | ||
}; | ||
} else { | ||
throw new Error('No host or siteUrl available'); | ||
} | ||
var url = URL.parse(this.request.url, true); | ||
/** | ||
* Returns the Current URL, stripping it of known FB parameters that should | ||
* not persist. | ||
* | ||
* @return {String} the current URL | ||
*/ | ||
_getCurrentUrl: function() { | ||
if (this.siteUrl) { | ||
var site = URL.parse(this.siteUrl); | ||
} else if (this.request && this.request.headers.host) { | ||
var site = { | ||
protocol: this.request.connection.encrypted ? 'https:' : 'http:', | ||
host: this.request.headers.host | ||
}; | ||
} else { | ||
throw new Error('No host or siteUrl available'); | ||
} | ||
var url = URL.parse(this.request.url, true); | ||
// drop known fb params | ||
this.DROP_QUERY_PARAMS.forEach(function(key) { | ||
delete url.query[key]; | ||
}); | ||
// drop known fb params | ||
this.DROP_QUERY_PARAMS.forEach(function(key) { | ||
delete url.query[key]; | ||
}); | ||
var currentUrl = site.protocol + '//' + site.host + url.pathname; | ||
if (url.query) { | ||
currentUrl += '?' + querystring.stringify(url.query); | ||
} | ||
var currentUrl = site.protocol + '//' + site.host + url.pathname; | ||
if (url.query) { | ||
currentUrl += '?' + querystring.stringify(url.query); | ||
} | ||
return currentUrl; | ||
}, | ||
return currentUrl; | ||
}, | ||
/** | ||
* Generate a signature for the given params and secret. | ||
* | ||
* @param {Object} params the parameters to sign | ||
* @param {String} secret the secret to sign with | ||
* @return {String} the generated signature | ||
*/ | ||
_generateSignature: function(params, secret) { | ||
var md5 = crypto.createHash('md5'); | ||
Object.keys(params).sort().forEach(function(key) { | ||
md5.update(key + '=' + params[key]); | ||
}); | ||
md5.update(secret); | ||
return md5.digest('hex'); | ||
}, | ||
/** | ||
* Generate a signature for the given params and secret. | ||
* | ||
* @param {Object} params the parameters to sign | ||
* @param {String} secret the secret to sign with | ||
* @return {String} the generated signature | ||
*/ | ||
_generateSignature: function(params, secret) { | ||
var md5 = crypto.createHash('md5'); | ||
Object.keys(params).sort().forEach(function(key) { | ||
if (key !== 'sig') { | ||
md5.update(key + '=' + params[key]); | ||
} | ||
}); | ||
md5.update(secret); | ||
return md5.digest('hex'); | ||
}, | ||
/** | ||
* Prints to the error log if you aren't in command line mode. | ||
* | ||
* @param {String} msg log message | ||
*/ | ||
_errorLog: function(msg) { | ||
console.log(msg); | ||
}, | ||
/** | ||
* Prints to the error log if you aren't in command line mode. | ||
* | ||
* @param {String} msg log message | ||
*/ | ||
_errorLog: function(msg) { | ||
console.log(msg); | ||
}, | ||
/** | ||
* Base64 encoding that doesn't need to be urlencode()ed. | ||
* Exactly the same as base64_encode except it uses | ||
* - instead of + | ||
* _ instead of / | ||
* | ||
* @param {String} input base64UrlEncodeded string | ||
* @param {String} decoded | ||
*/ | ||
_base64UrlDecode: function(input) { | ||
var buffer = new Buffer(input.replace('-', '+').replace('_', '/'), 'base64'); | ||
return buffer.toString('binary'); | ||
} | ||
/** | ||
* Base64 encoding that doesn't need to be urlencode()ed. | ||
* Exactly the same as base64_encode except it uses | ||
* - instead of + | ||
* _ instead of / | ||
* | ||
* @param {String} input base64UrlEncodeded string | ||
* @param {String} decoded | ||
*/ | ||
_base64UrlDecode: function(input) { | ||
var buffer = new Buffer(input.replace('-', '+').replace('_', '/'), 'base64'); | ||
return buffer.toString('binary'); | ||
} | ||
}; |
{ | ||
"name": "facebook-sdk", | ||
"description": "A full port of Facebook's PHP SDK library", | ||
"keywords": ["facebook", "sdk", "graph", "api", "connect", "canvas"], | ||
"version": "0.2.5", | ||
"author": "Christopher Johnson <tenorviol@yahoo.com> (http://github.com/tenorviol)", | ||
"repository" : { | ||
"type" : "git", | ||
"url" : "git://github.com/tenorviol/node-facebook-sdk.git" | ||
}, | ||
"directories" : { | ||
"lib" : "./lib" | ||
}, | ||
"licenses" : [ | ||
{ "type" : "Apache License, Version 2.0", "url" : "http://www.apache.org/licenses/LICENSE-2.0.html" } | ||
], | ||
"main": "lib/facebook", | ||
"engines": { "node" : ">= 0.4" } | ||
"name": "facebook-sdk", | ||
"description": "A full port of Facebook's PHP SDK library", | ||
"keywords": ["facebook", "sdk", "graph", "api", "connect", "canvas"], | ||
"version": "0.2.6", | ||
"author": "Christopher Johnson <tenorviol@yahoo.com> (http://github.com/tenorviol)", | ||
"repository" : { | ||
"type" : "git", | ||
"url" : "git://github.com/tenorviol/node-facebook-sdk.git" | ||
}, | ||
"directories" : { | ||
"lib" : "./lib" | ||
}, | ||
"licenses" : [ | ||
{ "type" : "Apache License, Version 2.0", "url" : "http://www.apache.org/licenses/LICENSE-2.0.html" } | ||
], | ||
"main": "lib/facebook", | ||
"engines": { "node" : ">= 0.4" } | ||
} |
@@ -18,3 +18,3 @@ [node.js Facebook SDK](https://github.com/tenorviol/node-facebook-sdk) | ||
npm install facebook-sdk | ||
npm install facebook-sdk | ||
@@ -28,26 +28,26 @@ Use as connect middleware | ||
var connect = require('connect'), | ||
fbsdk = require('facebook-sdk'); | ||
connect() | ||
.use(fbsdk.facebook({ | ||
appId : 'YOUR APP ID', | ||
secret : 'YOUR API SECRET' | ||
})) | ||
.use(function(req, res, next) { | ||
if (req.facebook.getSession()) { | ||
res.end('<a href="' + req.facebook.getLogoutUrl() + '">Logout</a>'); | ||
// get my graph api information | ||
req.facebook.api('/me', function(me) { | ||
console.log(me); | ||
}); | ||
} else { | ||
res.end('<a href="' + req.facebook.getLoginUrl() + '">Login</a>'); | ||
} | ||
}) | ||
.listen(3000); | ||
var connect = require('connect'), | ||
fbsdk = require('facebook-sdk'); | ||
connect() | ||
.use(fbsdk.facebook({ | ||
appId : 'YOUR APP ID', | ||
secret : 'YOUR API SECRET' | ||
})) | ||
.use(function(req, res, next) { | ||
if (req.facebook.getSession()) { | ||
res.end('<a href="' + req.facebook.getLogoutUrl() + '">Logout</a>'); | ||
// get my graph api information | ||
req.facebook.api('/me', function(me) { | ||
console.log(me); | ||
}); | ||
} else { | ||
res.end('<a href="' + req.facebook.getLoginUrl() + '">Login</a>'); | ||
} | ||
}) | ||
.listen(3000); | ||
@@ -57,12 +57,12 @@ Stand alone usage | ||
var fbsdk = require('facebook-sdk'); | ||
var facebook = new fbsdk.Facebook({ | ||
appId : 'YOUR APP ID', | ||
secret : 'YOUR API SECRET' | ||
}); | ||
facebook.api('/YOUR APP ID', function(data) { | ||
console.log(data); | ||
}); | ||
var fbsdk = require('facebook-sdk'); | ||
var facebook = new fbsdk.Facebook({ | ||
appId : 'YOUR APP ID', | ||
secret : 'YOUR API SECRET' | ||
}); | ||
facebook.api('/YOUR APP ID', function(data) { | ||
console.log(data); | ||
}); | ||
@@ -69,0 +69,0 @@ Tests |
var connect = require('connect'), | ||
http = require('http'), | ||
fbsdk = require('../lib/facebook'); | ||
http = require('http'), | ||
fbsdk = require('../lib/facebook'); | ||
@@ -9,8 +9,8 @@ var APP_ID = '117743971608120'; | ||
var VALID_EXPIRED_SESSION = { | ||
access_token : '117743971608120|2.vdCKd4ZIEJlHwwtrkilgKQ__.86400.1281049200-1677846385|NF_2DDNxFBznj2CuwiwabHhTAHc.', | ||
expires : '1281049200', | ||
secret : 'u0QiRGAwaPCyQ7JE_hiz1w__', | ||
session_key : '2.vdCKd4ZIEJlHwwtrkilgKQ__.86400.1281049200-1677846385', | ||
sig : '7a9b063de0bef334637832166948dcad', | ||
uid : '1677846385' | ||
access_token : '117743971608120|2.vdCKd4ZIEJlHwwtrkilgKQ__.86400.1281049200-1677846385|NF_2DDNxFBznj2CuwiwabHhTAHc.', | ||
expires : '1281049200', | ||
secret : 'u0QiRGAwaPCyQ7JE_hiz1w__', | ||
session_key : '2.vdCKd4ZIEJlHwwtrkilgKQ__.86400.1281049200-1677846385', | ||
sig : '7a9b063de0bef334637832166948dcad', | ||
uid : '1677846385' | ||
}; | ||
@@ -22,31 +22,29 @@ | ||
exports.testFacebookMiddleware = function(test) { | ||
var port = 3000; | ||
connect() | ||
.use(fbsdk.facebook({ | ||
appId: APP_ID, | ||
secret: SECRET | ||
})) | ||
.use(connect.router(function(app) { | ||
app.get('/', function(req, res, next) { | ||
res.end(); | ||
var facebook = req.facebook; | ||
test.equal(req, facebook.request); | ||
test.equal(res, facebook.response); | ||
test.deepEqual(VALID_EXPIRED_SESSION, facebook.getSession()); | ||
test.done(); | ||
}); | ||
})) | ||
.listen(port, function() { | ||
http.request({ | ||
host: 'localhost', | ||
port: port, | ||
path: '/', | ||
headers: { | ||
cookie: UNESCAPED_SESSION_COOKIE | ||
} | ||
}).end(); | ||
}); | ||
var port = 3000; | ||
connect() | ||
.use(fbsdk.facebook({ | ||
appId: APP_ID, | ||
secret: SECRET | ||
})) | ||
.use(function(req, res, next) { | ||
res.end(); | ||
var facebook = req.facebook; | ||
test.equal(req, facebook.request); | ||
test.equal(res, facebook.response); | ||
test.deepEqual(VALID_EXPIRED_SESSION, facebook.getSession()); | ||
test.done(); | ||
}) | ||
.listen(port, function() { | ||
http.request({ | ||
host: 'localhost', | ||
port: port, | ||
path: '/', | ||
headers: { | ||
cookie: UNESCAPED_SESSION_COOKIE | ||
} | ||
}).end(); | ||
}); | ||
}; | ||
1138
test/tests.js
@@ -18,5 +18,7 @@ /** | ||
var fbsdk = require('../lib/facebook'), | ||
http = require('http'), | ||
querystring = require('querystring'); | ||
var Facebook = require('../lib/facebook').Facebook, | ||
fs = require('fs'), | ||
http = require('http'), | ||
https = require('https'), | ||
querystring = require('querystring'); | ||
@@ -30,8 +32,8 @@ var APP_ID = '117743971608120'; | ||
var VALID_EXPIRED_SESSION = { | ||
access_token : '117743971608120|2.vdCKd4ZIEJlHwwtrkilgKQ__.86400.1281049200-1677846385|NF_2DDNxFBznj2CuwiwabHhTAHc.', | ||
expires : '1281049200', | ||
secret : 'u0QiRGAwaPCyQ7JE_hiz1w__', | ||
session_key : '2.vdCKd4ZIEJlHwwtrkilgKQ__.86400.1281049200-1677846385', | ||
sig : '7a9b063de0bef334637832166948dcad', | ||
uid : '1677846385' | ||
access_token : '117743971608120|2.vdCKd4ZIEJlHwwtrkilgKQ__.86400.1281049200-1677846385|NF_2DDNxFBznj2CuwiwabHhTAHc.', | ||
expires : '1281049200', | ||
secret : 'u0QiRGAwaPCyQ7JE_hiz1w__', | ||
session_key : '2.vdCKd4ZIEJlHwwtrkilgKQ__.86400.1281049200-1677846385', | ||
sig : '7a9b063de0bef334637832166948dcad', | ||
uid : '1677846385' | ||
}; | ||
@@ -48,79 +50,23 @@ | ||
exports.testConstructor = function(test) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
test.equal(facebook.appId, APP_ID, 'Expect the App ID to be set.'); | ||
test.equal(facebook.secret, SECRET, 'Expect the API secret to be set.'); | ||
test.ok(!facebook.cookieSupport, 'Expect Cookie support to be off.'); | ||
test.done(); | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
siteUrl: 'http://fbrell.com', | ||
request: {}, | ||
response: {}, | ||
domain : 'fbrell.com', | ||
fileUpload : true | ||
}); | ||
test.equal(facebook.appId, APP_ID, 'Expect the App ID to be set.'); | ||
test.equal(facebook.secret, SECRET, 'Expect the API secret to be set.'); | ||
test.equal(facebook.siteUrl, 'http://fbrell.com'); | ||
test.ok(facebook.request); | ||
test.ok(facebook.response); | ||
test.equal(facebook.domain, 'fbrell.com'); | ||
test.ok(facebook.fileUpload); | ||
test.done(); | ||
}; | ||
exports.testConstructorWithCookie = function(test) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
cookie : true | ||
}); | ||
test.equal(facebook.appId, APP_ID, 'Expect the App ID to be set.'); | ||
test.equal(facebook.secret, SECRET, 'Expect the API secret to be set.'); | ||
test.ok(facebook.cookie, 'Expect Cookie support to be on.'); | ||
test.done(); | ||
}; | ||
exports.testConstructorWithFileUpload = function(test) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
fileUpload : true | ||
}); | ||
test.equal(facebook.appId, APP_ID, 'Expect the App ID to be set.'); | ||
test.equal(facebook.secret, SECRET, 'Expect the API secret to be set.'); | ||
test.ok(facebook.fileUpload, 'Expect file upload support to be on.'); | ||
test.done(); | ||
}; | ||
exports.testSetAppId = function(test) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
facebook.appId = 'dummy'; | ||
test.equal(facebook.appId, 'dummy', 'Expect the App ID to be dummy.'); | ||
test.done(); | ||
}; | ||
exports.testSetAPISecret = function(test) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
facebook.secret = 'dummy'; | ||
test.equal(facebook.secret, 'dummy', 'Expect the API secret to be dummy.'); | ||
test.done(); | ||
}; | ||
exports.testDefaultBaseDomain = function(test) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
domain : 'fbrell.com' | ||
}); | ||
test.equal(facebook.domain, 'fbrell.com'); | ||
test.done(); | ||
}; | ||
exports.testSetCookieSupport = function(test) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
test.ok(!facebook.cookie, 'Expect Cookie support to be off.'); | ||
facebook.cookie = true; | ||
test.ok(facebook.cookie, 'Expect Cookie support to be on.'); | ||
test.done(); | ||
}; | ||
// exports.testIgnoreDeleteSetCookie = function(test) { | ||
// var facebook = new fbsdk.Facebook({ | ||
// var facebook = new Facebook({ | ||
// appId : APP_ID, | ||
@@ -136,72 +82,60 @@ // secret : SECRET, | ||
exports.testSetFileUploadSupport = function(test) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
test.ok(!facebook.fileUploadSupport, 'Expect file upload support to be off.'); | ||
facebook.fileUploadSupport = true; | ||
test.ok(facebook.fileUploadSupport, 'Expect file upload support to be on.'); | ||
test.done(); | ||
}; | ||
exports.testSetNullSession = function(test) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
facebook.setSession(null); | ||
test.ok(facebook.getSession() === null, 'Expect null session back.'); | ||
test.done(); | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
facebook.setSession(null); | ||
test.ok(facebook.getSession() === null, 'Expect null session back.'); | ||
test.done(); | ||
}; | ||
exports.testNonUserAccessToken = function(test) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
cookie : true | ||
}); | ||
test.ok(facebook.getAccessToken() == APP_ID+'|'+SECRET, 'Expect appId|secret.'); | ||
test.done(); | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
test.ok(facebook.getAccessToken() == APP_ID+'|'+SECRET, 'Expect appId|secret.'); | ||
test.done(); | ||
}; | ||
exports.testSetSession = function(test) { | ||
test.expect(4); | ||
// the setSession below should call this response.setHeader method | ||
var response = { | ||
setHeader: function(name, value) { | ||
// setting the session sets the cookie (copied from a php-sdk instance) | ||
test.equal(name, 'Set-Cookie'); | ||
test.equal(value, SESSION_COOKIE+'; expires=Thu, 05 Aug 2010 23:00:00 GMT; path=/; domain=.foo.com'); | ||
} | ||
}; | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
response : response, | ||
domain : 'foo.com' | ||
}); | ||
facebook.setSession(VALID_EXPIRED_SESSION); | ||
test.ok(facebook.getUser() == VALID_EXPIRED_SESSION.uid, 'Expect uid back.'); | ||
test.ok(facebook.getAccessToken() == VALID_EXPIRED_SESSION.access_token, 'Expect access token back.'); | ||
test.done(); | ||
test.expect(4); | ||
// the setSession below should call this response.setHeader method | ||
var response = { | ||
setHeader: function(name, value) { | ||
// setting the session sets the cookie (copied from a php-sdk instance) | ||
test.equal(name, 'Set-Cookie'); | ||
test.equal(value, SESSION_COOKIE+'; expires=Thu, 05 Aug 2010 23:00:00 GMT; path=/; domain=.foo.com'); | ||
} | ||
}; | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
response : response, | ||
domain : 'foo.com' | ||
}); | ||
facebook.setSession(VALID_EXPIRED_SESSION); | ||
test.ok(facebook.getUser() == VALID_EXPIRED_SESSION.uid, 'Expect uid back.'); | ||
test.ok(facebook.getAccessToken() == VALID_EXPIRED_SESSION.access_token, 'Expect access token back.'); | ||
test.done(); | ||
}; | ||
exports.testGetSession = function(test) { | ||
// regression test: the cookie we set should be getSession-able | ||
var request = { | ||
url: '/', | ||
headers: { | ||
cookie: SESSION_COOKIE | ||
} | ||
}; | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request: request | ||
}); | ||
test.deepEqual(facebook.getSession(), VALID_EXPIRED_SESSION); | ||
test.done(); | ||
// regression test: the cookie we set should be getSession-able | ||
var request = { | ||
url: '/', | ||
headers: { | ||
cookie: SESSION_COOKIE | ||
} | ||
}; | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request: request | ||
}); | ||
test.deepEqual(facebook.getSession(), VALID_EXPIRED_SESSION); | ||
test.done(); | ||
}; | ||
@@ -211,214 +145,212 @@ | ||
exports.testGetSessionUnescaped = function(test) { | ||
// regression test: the cookie we set should be getSession-able | ||
var request = { | ||
url: '/', | ||
headers: { | ||
cookie: UNESCAPED_SESSION_COOKIE | ||
} | ||
}; | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request: request | ||
}); | ||
test.deepEqual(facebook.getSession(), VALID_EXPIRED_SESSION); | ||
test.done(); | ||
// regression test: the cookie we set should be getSession-able | ||
var request = { | ||
url: '/', | ||
headers: { | ||
cookie: UNESCAPED_SESSION_COOKIE | ||
} | ||
}; | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request: request | ||
}); | ||
test.deepEqual(facebook.getSession(), VALID_EXPIRED_SESSION); | ||
test.done(); | ||
}; | ||
exports.testGetSessionFromCookie = function(test) { | ||
var cookieName = 'fbs_' + APP_ID; | ||
var session = VALID_EXPIRED_SESSION; | ||
var cookie = {}; | ||
cookie[cookieName] = querystring.stringify(session); | ||
var cookieName = 'fbs_' + APP_ID; | ||
var session = VALID_EXPIRED_SESSION; | ||
var cookie = {}; | ||
cookie[cookieName] = querystring.stringify(session); | ||
var options = { | ||
headers: { Cookie: querystring.stringify(cookie) } | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
cookie : true, | ||
request : request | ||
}); | ||
test.deepEqual(facebook.getSession(), session, 'Expect session back.'); | ||
test.done(); | ||
}); | ||
var options = { | ||
headers: { Cookie: querystring.stringify(cookie) } | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request : request | ||
}); | ||
test.deepEqual(facebook.getSession(), session, 'Expect session back.'); | ||
test.done(); | ||
}); | ||
}; | ||
exports.testInvalidGetSessionFromCookie = function(test) { | ||
var cookieName = 'fbs_' + APP_ID; | ||
var session = clone(VALID_EXPIRED_SESSION); | ||
session.uid = 'make me invalid'; | ||
var cookie = {}; | ||
cookie[cookieName] = querystring.stringify(session); | ||
var cookieName = 'fbs_' + APP_ID; | ||
var session = clone(VALID_EXPIRED_SESSION); | ||
session.uid = 'make me invalid'; | ||
var cookie = {}; | ||
cookie[cookieName] = querystring.stringify(session); | ||
var options = { | ||
headers: { Cookie: querystring.stringify(cookie) } | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
cookie : true, | ||
request : request | ||
}); | ||
test.ok(facebook.getSession() === null, 'Expect no session back.'); | ||
test.done(); | ||
}); | ||
var options = { | ||
headers: { Cookie: querystring.stringify(cookie) } | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request : request | ||
}); | ||
test.ok(facebook.getSession() === null, 'Expect no session back.'); | ||
test.done(); | ||
}); | ||
}; | ||
exports.testSessionFromQueryString = function(test) { | ||
var options = { | ||
path: '/?' + querystring.stringify({ session: JSON.stringify(VALID_EXPIRED_SESSION) }) | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request : request | ||
}); | ||
test.equal(facebook.getUser(), VALID_EXPIRED_SESSION.uid, 'Expect uid back.'); | ||
test.done(); | ||
}); | ||
var options = { | ||
path: '/?' + querystring.stringify({ session: JSON.stringify(VALID_EXPIRED_SESSION) }) | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request : request | ||
}); | ||
test.equal(facebook.getUser(), VALID_EXPIRED_SESSION.uid, 'Expect uid back.'); | ||
test.done(); | ||
}); | ||
}; | ||
exports.testInvalidSessionFromQueryString = function(test) { | ||
var qs = { | ||
fb_sig_in_iframe : 1, | ||
fb_sig_user : '1677846385', | ||
fb_sig_session_key : '2.NdKHtYIuB0EcNSHOvqAKHg__.86400.1258092000-1677846385', | ||
fb_sig_ss : 'AdCOu5nhDiexxRDLwZfqnA__', | ||
fb_sig : '1949f256171f37ecebe00685ce33bf17' | ||
}; | ||
var options = { | ||
path: '/?' + querystring.stringify(qs) | ||
}; | ||
var qs = { | ||
fb_sig_in_iframe : 1, | ||
fb_sig_user : '1677846385', | ||
fb_sig_session_key : '2.NdKHtYIuB0EcNSHOvqAKHg__.86400.1258092000-1677846385', | ||
fb_sig_ss : 'AdCOu5nhDiexxRDLwZfqnA__', | ||
fb_sig : '1949f256171f37ecebe00685ce33bf17' | ||
}; | ||
var options = { | ||
path: '/?' + querystring.stringify(qs) | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request : request | ||
}); | ||
test.equal(facebook.getUser(), null, 'Expect uid back.'); | ||
test.done(); | ||
}); | ||
httpServerTest(options, function(request, response) { | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request : request | ||
}); | ||
test.equal(facebook.getUser(), null, 'Expect uid back.'); | ||
test.done(); | ||
}); | ||
}; | ||
exports.testGetUID = function(test) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
var session = VALID_EXPIRED_SESSION; | ||
facebook.setSession(session); | ||
test.equal(facebook.getUser(), session.uid, 'Expect dummy uid back.'); | ||
test.done(); | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
var session = VALID_EXPIRED_SESSION; | ||
facebook.setSession(session); | ||
test.equal(facebook.getUser(), session.uid, 'Expect dummy uid back.'); | ||
test.done(); | ||
}; | ||
exports.testAPIWithoutSession = function(test) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
facebook.api({ | ||
method : 'fql.query', | ||
query : 'SELECT name FROM user WHERE uid=4' | ||
}, function(response) { | ||
test.equal(response.length, 1, 'Expect one row back.'); | ||
test.equal(response[0].name, 'Mark Zuckerberg', 'Expect the name back.'); | ||
test.done(); | ||
}); | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
facebook.api({ | ||
method : 'fql.query', | ||
query : 'SELECT name FROM user WHERE uid=4' | ||
}, function(response) { | ||
test.equal(response.length, 1, 'Expect one row back.'); | ||
test.equal(response[0].name, 'Mark Zuckerberg', 'Expect the name back.'); | ||
test.done(); | ||
}); | ||
}; | ||
exports.testAPIWithSession = function(test) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
facebook.setSession(VALID_EXPIRED_SESSION); | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
facebook.setSession(VALID_EXPIRED_SESSION); | ||
// this is strange in that we are expecting a session invalid error vs a | ||
// signature invalid error. basically we're just making sure session based | ||
// signing is working, not that the api call is returning data. | ||
facebook.api({ | ||
method : 'fql.query', | ||
query : 'SELECT name FROM profile WHERE id=4' | ||
}, function(data) { | ||
test.ok(data.error); | ||
// this is strange in that we are expecting a session invalid error vs a | ||
// signature invalid error. basically we're just making sure session based | ||
// signing is working, not that the api call is returning data. | ||
facebook.api({ | ||
method : 'fql.query', | ||
query : 'SELECT name FROM profile WHERE id=4' | ||
}, function(data) { | ||
test.ok(data.error); | ||
var msg = 'Exception: 190: Invalid OAuth 2.0 Access Token'; | ||
test.equal(data, msg, 'Expect the invalid session message.'); | ||
var msg = 'Exception: 190: Invalid OAuth 2.0 Access Token'; | ||
test.equal(data, msg, 'Expect the invalid session message.'); | ||
var result = data.getResult(); | ||
test.ok(typeof result == 'object', 'expect a result object'); | ||
test.equal(result.error_code, 190, 'expect code'); | ||
test.done(); | ||
}); | ||
var result = data.getResult(); | ||
test.ok(typeof result == 'object', 'expect a result object'); | ||
test.equal(result.error_code, 190, 'expect code'); | ||
test.done(); | ||
}); | ||
}; | ||
exports.testAPIGraphPublicData = function(test) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
facebook.api('/naitik', function(response) { | ||
test.equal(response.id, '5526183', 'should get expected id.'); | ||
test.done(); | ||
}); | ||
facebook.api('/naitik', function(response) { | ||
test.equal(response.id, '5526183', 'should get expected id.'); | ||
test.done(); | ||
}); | ||
// regression test: calling api w/o callback throws TypeError | ||
facebook.api('/4'); | ||
// regression test: calling api w/o callback throws TypeError | ||
facebook.api('/4'); | ||
}; | ||
exports.testGraphAPIWithSession = function(test) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
facebook.setSession(VALID_EXPIRED_SESSION); | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
facebook.setSession(VALID_EXPIRED_SESSION); | ||
facebook.api('/me', function(data) { | ||
test.ok(data.error); | ||
// means the server got the access token | ||
var msg = 'OAuthException: Error validating access token.'; | ||
test.equal(msg, data, 'Expect the invalid session message.'); | ||
// also ensure the session was reset since it was invalid | ||
test.equal(facebook.getSession(), null, 'Expect the session to be reset.'); | ||
test.done(); | ||
}); | ||
facebook.api('/me', function(data) { | ||
test.ok(data.error); | ||
// means the server got the access token | ||
var msg = 'OAuthException: Error validating access token.'; | ||
test.equal(msg, data, 'Expect the invalid session message.'); | ||
// also ensure the session was reset since it was invalid | ||
test.equal(facebook.getSession(), null, 'Expect the session to be reset.'); | ||
test.done(); | ||
}); | ||
}; | ||
exports.testGraphAPIMethod = function(test) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
facebook.api('/naitik', 'DELETE', function(data) { | ||
test.ok(data.error); | ||
// ProfileDelete means the server understood the DELETE | ||
var msg = 'OAuthException: An access token is required to request this resource.'; | ||
test.equal(msg, data, 'Expect the invalid session message.'); | ||
test.done(); | ||
}); | ||
facebook.api('/naitik', 'DELETE', function(data) { | ||
test.ok(data.error); | ||
// ProfileDelete means the server understood the DELETE | ||
var msg = 'OAuthException: An access token is required to request this resource.'; | ||
test.equal(msg, data, 'Expect the invalid session message.'); | ||
test.done(); | ||
}); | ||
}; | ||
exports.testGraphAPIOAuthSpecError = function(test) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : MIGRATED_APP_ID, | ||
secret : MIGRATED_SECRET | ||
}); | ||
var facebook = new Facebook({ | ||
appId : MIGRATED_APP_ID, | ||
secret : MIGRATED_SECRET | ||
}); | ||
facebook.api('/me', { client_id: MIGRATED_APP_ID }, function(data) { | ||
test.ok(data.error); | ||
// means the server got the access token | ||
msg = 'invalid_request: An active access token must be used to query information about the current user.'; | ||
test.equal(msg, data, 'Expect the invalid session message.'); | ||
// also ensure the session was reset since it was invalid | ||
test.equal(facebook.getSession(), null, 'Expect the session to be reset.'); | ||
test.done(); | ||
}); | ||
facebook.api('/me', { client_id: MIGRATED_APP_ID }, function(data) { | ||
test.ok(data.error); | ||
// means the server got the access token | ||
msg = 'invalid_request: An active access token must be used to query information about the current user.'; | ||
test.equal(msg, data, 'Expect the invalid session message.'); | ||
// also ensure the session was reset since it was invalid | ||
test.equal(facebook.getSession(), null, 'Expect the session to be reset.'); | ||
test.done(); | ||
}); | ||
}; | ||
@@ -428,3 +360,3 @@ | ||
//exports.testGraphAPIMethodOAuthSpecError = function(test) { | ||
// var facebook = new fbsdk.Facebook({ | ||
// var facebook = new Facebook({ | ||
// appId : MIGRATED_APP_ID, | ||
@@ -444,16 +376,16 @@ // secret : MIGRATED_SECRET | ||
exports.testCurlFailure = function(test) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
// we dont expect facebook will ever return in 1ms | ||
facebook.timeout = 1; | ||
facebook.api('/naitik', function(data) { | ||
test.ok(data.error); | ||
var CURLE_OPERATION_TIMEDOUT = 28; | ||
test.equal(CURLE_OPERATION_TIMEDOUT, data.code, 'expect timeout'); | ||
test.equal('CurlException', data.getType(), 'expect type'); | ||
test.done(); | ||
}); | ||
// we dont expect facebook will ever return in 1ms | ||
facebook.timeout = 1; | ||
facebook.api('/naitik', function(data) { | ||
test.ok(data.error); | ||
var CURLE_OPERATION_TIMEDOUT = 28; | ||
test.equal(CURLE_OPERATION_TIMEDOUT, data.code, 'expect timeout'); | ||
test.equal('CurlException', data.getType(), 'expect type'); | ||
test.done(); | ||
}); | ||
}; | ||
@@ -463,309 +395,322 @@ | ||
exports.testGraphAPIWithOnlyParams = function(test) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
facebook.api('/' + APP_ID + '/insights', { limit:1 }, function(response) { | ||
test.equal(1, response.data.length, 'should get one entry'); | ||
test.done(); | ||
}); | ||
facebook.api('/' + APP_ID + '/insights', { limit:1 }, function(response) { | ||
test.equal(1, response.data.length, 'should get one entry'); | ||
test.done(); | ||
}); | ||
}; | ||
exports.testLoginURLDefaults = function(test) { | ||
var options = { | ||
path: '/examples' | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
request.headers.host = 'fbrell.com'; | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request: request | ||
}); | ||
var encodedUrl = querystring.escape('http://fbrell.com/examples'); | ||
test.ok(facebook.getLoginUrl().indexOf(encodedUrl) >= 0, 'Expect the current url to exist.'); | ||
test.done(); | ||
}); | ||
var options = { | ||
path: '/examples', | ||
headers: { host : 'fbrell.com' } | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request: request | ||
}); | ||
var encodedUrl = querystring.escape('http://fbrell.com/examples'); | ||
test.ok(facebook.getLoginUrl().indexOf(encodedUrl) >= 0, 'Expect the current url to exist.'); | ||
test.done(); | ||
}); | ||
}; | ||
// The siteUrl option trumps the 'host' header | ||
// TODO: deprecate this feature | ||
exports.testLoginURLUsingSiteUrl = function(test) { | ||
var options = { | ||
path: '/examples' | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
test.ok(request.headers.host != 'fbrell.com'); | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
siteUrl: 'http://fbrell.com', | ||
request: request | ||
}); | ||
var encodedUrl = querystring.escape('http://fbrell.com/examples'); | ||
test.ok(facebook.getLoginUrl().indexOf(encodedUrl) >= 0, 'Expect the current url to exist.'); | ||
test.done(); | ||
}); | ||
var options = { | ||
path: '/examples' | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
test.ok(request.headers.host != 'fbrell.com'); | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
siteUrl: 'http://fbrell.com', | ||
request: request | ||
}); | ||
var encodedUrl = querystring.escape('http://fbrell.com/examples'); | ||
test.ok(facebook.getLoginUrl().indexOf(encodedUrl) >= 0, 'Expect the current url to exist.'); | ||
test.done(); | ||
}); | ||
}; | ||
exports.testUnavailableLoginURLThrowsError = function(test) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
test.expect(1); | ||
test['throws'](function() { | ||
facebook.getLoginUrl(); | ||
}); | ||
test.done(); | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
test.expect(1); | ||
test['throws'](function() { | ||
facebook.getLoginUrl(); | ||
}); | ||
test.done(); | ||
}; | ||
exports.testLoginURLDefaultsDropSessionQueryParam = function(test) { | ||
var options = { | ||
path: '/examples?session=xx42xx' | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
request.headers.host = 'fbrell.com'; | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request: request | ||
}); | ||
var expectEncodedUrl = querystring.escape('http://fbrell.com/examples'); | ||
test.ok(facebook.getLoginUrl().indexOf(expectEncodedUrl) >= 0, 'Expect the current url to exist.'); | ||
test.ok(facebook.getLoginUrl().indexOf('xx42xx') == -1, 'Expect the session param to be dropped.'); | ||
test.done(); | ||
}); | ||
var options = { | ||
path: '/examples?session=xx42xx', | ||
headers: { host : 'fbrell.com' } | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request: request | ||
}); | ||
var expectEncodedUrl = querystring.escape('http://fbrell.com/examples'); | ||
test.ok(facebook.getLoginUrl().indexOf(expectEncodedUrl) >= 0, 'Expect the current url to exist.'); | ||
test.ok(facebook.getLoginUrl().indexOf('xx42xx') == -1, 'Expect the session param to be dropped.'); | ||
test.done(); | ||
}); | ||
}; | ||
exports.testLoginURLDefaultsDropSessionQueryParamButNotOthers = function(test) { | ||
var options = { | ||
path: '/examples?session=xx42xx&do_not_drop=xx43xx' | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
request.headers.host = 'fbrell.com'; | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request: request | ||
}); | ||
var expectEncodedUrl = querystring.escape('http://fbrell.com/examples'); | ||
test.ok(facebook.getLoginUrl().indexOf('xx42xx') == -1, 'Expect the session param to be dropped.'); | ||
test.ok(facebook.getLoginUrl().indexOf('xx43xx') >= 0, 'Expect the do_not_drop param to exist.'); | ||
test.done(); | ||
}); | ||
var options = { | ||
path: '/examples?session=xx42xx&do_not_drop=xx43xx', | ||
headers: { host : 'fbrell.com' } | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request: request | ||
}); | ||
var expectEncodedUrl = querystring.escape('http://fbrell.com/examples'); | ||
test.ok(facebook.getLoginUrl().indexOf('xx42xx') == -1, 'Expect the session param to be dropped.'); | ||
test.ok(facebook.getLoginUrl().indexOf('xx43xx') >= 0, 'Expect the do_not_drop param to exist.'); | ||
test.done(); | ||
}); | ||
}; | ||
exports.testLoginURLCustomNext = function(test) { | ||
var options = { | ||
path: '/examples' | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
request.headers.host = 'fbrell.com'; | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request: request | ||
}); | ||
var next = 'http://fbrell.com/custom'; | ||
var loginUrl = facebook.getLoginUrl({ | ||
next : next, | ||
cancel_url : next | ||
}); | ||
var currentEncodedUrl = querystring.escape('http://fbrell.com/examples'); | ||
var expectedEncodedUrl = querystring.escape(next); | ||
test.ok(loginUrl.indexOf(expectedEncodedUrl) >= 0, 'Expect the custom url to exist.'); | ||
test.ok(loginUrl.indexOf(currentEncodedUrl) == -1, 'Expect the current url to not exist.'); | ||
test.done(); | ||
}); | ||
var options = { | ||
path: '/examples', | ||
headers: { host : 'fbrell.com' } | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request: request | ||
}); | ||
var next = 'http://fbrell.com/custom'; | ||
var loginUrl = facebook.getLoginUrl({ | ||
next : next, | ||
cancel_url : next | ||
}); | ||
var currentEncodedUrl = querystring.escape('http://fbrell.com/examples'); | ||
var expectedEncodedUrl = querystring.escape(next); | ||
test.ok(loginUrl.indexOf(expectedEncodedUrl) >= 0, 'Expect the custom url to exist.'); | ||
test.ok(loginUrl.indexOf(currentEncodedUrl) == -1, 'Expect the current url to not exist.'); | ||
test.done(); | ||
}); | ||
}; | ||
exports.testLogoutURLDefaults = function(test) { | ||
var options = { | ||
path: '/examples' | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
request.headers.host = 'fbrell.com'; | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request: request | ||
}); | ||
var encodedUrl = querystring.escape('http://fbrell.com/examples'); | ||
test.ok(facebook.getLogoutUrl().indexOf(encodedUrl) >= 0, 'Expect the current url to exist.'); | ||
test.done(); | ||
}); | ||
var options = { | ||
path: '/examples', | ||
headers: { host : 'fbrell.com' } | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request: request | ||
}); | ||
var encodedUrl = querystring.escape('http://fbrell.com/examples'); | ||
test.ok(facebook.getLogoutUrl().indexOf(encodedUrl) >= 0, 'Expect the current url to exist.'); | ||
test.done(); | ||
}); | ||
}; | ||
exports.testLoginStatusURLDefaults = function(test) { | ||
var options = { | ||
path: '/examples' | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
request.headers.host = 'fbrell.com'; | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request: request | ||
}); | ||
var encodedUrl = querystring.escape('http://fbrell.com/examples'); | ||
test.ok(facebook.getLoginStatusUrl().indexOf(encodedUrl) >= 0, 'Expect the current url to exist.'); | ||
test.done(); | ||
}); | ||
var options = { | ||
path: '/examples', | ||
headers: { host : 'fbrell.com' } | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request: request | ||
}); | ||
var encodedUrl = querystring.escape('http://fbrell.com/examples'); | ||
test.ok(facebook.getLoginStatusUrl().indexOf(encodedUrl) >= 0, 'Expect the current url to exist.'); | ||
test.done(); | ||
}); | ||
}; | ||
exports.testLoginStatusURLCustom = function(test) { | ||
var options = { | ||
path: '/examples' | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
request.headers.host = 'fbrell.com'; | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request: request | ||
}); | ||
var encodedUrl1 = querystring.escape('http://fbrell.com/examples'); | ||
var okUrl = 'http://fbrell.com/here1'; | ||
var encodedUrl2 = querystring.escape(okUrl); | ||
var loginStatusUrl = facebook.getLoginStatusUrl({ ok_session: okUrl }); | ||
test.ok(loginStatusUrl.indexOf(encodedUrl1) >= 0, 'Expect the current url to exist.'); | ||
test.ok(loginStatusUrl.indexOf(encodedUrl2) >= 0, 'Expect the custom url to exist.'); | ||
test.done(); | ||
}); | ||
var options = { | ||
path: '/examples', | ||
headers: { host : 'fbrell.com' } | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request: request | ||
}); | ||
var encodedUrl1 = querystring.escape('http://fbrell.com/examples'); | ||
var okUrl = 'http://fbrell.com/here1'; | ||
var encodedUrl2 = querystring.escape(okUrl); | ||
var loginStatusUrl = facebook.getLoginStatusUrl({ ok_session: okUrl }); | ||
test.ok(loginStatusUrl.indexOf(encodedUrl1) >= 0, 'Expect the current url to exist.'); | ||
test.ok(loginStatusUrl.indexOf(encodedUrl2) >= 0, 'Expect the custom url to exist.'); | ||
test.done(); | ||
}); | ||
}; | ||
exports.testNonDefaultPort = function(test) { | ||
var options = { | ||
path: '/examples' | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
request.headers.host = 'fbrell.com:8080'; | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request: request | ||
}); | ||
var encodedUrl = querystring.escape('http://fbrell.com:8080/examples'); | ||
test.ok(facebook.getLoginUrl().indexOf(encodedUrl) >= 0, 'Expect the current url to exist.'); | ||
test.done(); | ||
}); | ||
var options = { | ||
path: '/examples', | ||
headers: { host : 'fbrell.com:8080' } | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request: request | ||
}); | ||
var encodedUrl = querystring.escape('http://fbrell.com:8080/examples'); | ||
test.ok(facebook.getLoginUrl().indexOf(encodedUrl) >= 0, 'Expect the current url to exist.'); | ||
test.done(); | ||
}); | ||
}; | ||
// TODO: currently it is only possible to do this with a siteUrl | ||
exports.testSecureCurrentUrl = function(test) { | ||
var options = { | ||
path: '/examples' | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
siteUrl: 'https://fbrell.com/', | ||
request: request | ||
}); | ||
var encodedUrl = querystring.escape('https://fbrell.com/examples'); | ||
test.ok(facebook.getLoginUrl().indexOf(encodedUrl) >= 0, 'Expect the current url to exist.'); | ||
test.done(); | ||
}); | ||
var options = { | ||
https: true, | ||
path: '/examples', | ||
headers: { host : 'fbrell.com' } | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request: request | ||
}); | ||
var encodedUrl = querystring.escape('https://fbrell.com/examples'); | ||
test.ok(facebook.getLoginUrl().indexOf(encodedUrl) >= 0, 'Expect the current url to exist.'); | ||
test.done(); | ||
}); | ||
}; | ||
// TODO: do this without siteUrl? | ||
exports.testSecureCurrentUrlWithNonDefaultPort = function(test) { | ||
var options = { | ||
path: '/examples' | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
siteUrl: 'https://fbrell.com:8080/', | ||
request: request | ||
}); | ||
var encodedUrl = querystring.escape('https://fbrell.com:8080/examples'); | ||
test.ok(facebook.getLoginUrl().indexOf(encodedUrl) >= 0, 'Expect the current url to exist.'); | ||
test.done(); | ||
}); | ||
var options = { | ||
https: true, | ||
path: '/examples', | ||
headers: { host : 'fbrell.com:8080' } | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request: request | ||
}); | ||
var encodedUrl = querystring.escape('https://fbrell.com:8080/examples'); | ||
test.ok(facebook.getLoginUrl().indexOf(encodedUrl) >= 0, 'Expect the current url to exist.'); | ||
test.done(); | ||
}); | ||
}; | ||
exports.testAppSecretCall = function(test) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
facebook.api('/' + APP_ID + '/insights', function(response) { | ||
test.ok(response.data.length > 0, 'Expect some data back.'); | ||
test.done(); | ||
}); | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
facebook.api('/' + APP_ID + '/insights', function(response) { | ||
test.ok(response.data.length > 0, 'Expect some data back.'); | ||
test.done(); | ||
}); | ||
}; | ||
exports.testBase64UrlEncode = function(test) { | ||
var input = 'Facebook rocks'; | ||
var output = 'RmFjZWJvb2sgcm9ja3M'; | ||
test.equal(fbsdk.Facebook.prototype._base64UrlDecode(output), input); | ||
test.done(); | ||
var input = 'Facebook rocks'; | ||
var output = 'RmFjZWJvb2sgcm9ja3M'; | ||
test.equal(Facebook.prototype._base64UrlDecode(output), input); | ||
test.done(); | ||
}; | ||
exports.testSignedToken = function(test) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
var payload = facebook._parseSignedRequest(VALID_SIGNED_REQUEST); | ||
test.ok(payload, 'Expected token to parse'); | ||
var session = facebook._createSessionFromSignedRequest(payload); | ||
test.equal(session.uid, VALID_EXPIRED_SESSION.uid); | ||
test.equal(facebook.getSignedRequest(), null); | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
var payload = facebook._parseSignedRequest(VALID_SIGNED_REQUEST); | ||
test.ok(payload, 'Expected token to parse'); | ||
var session = facebook._createSessionFromSignedRequest(payload); | ||
test.equal(session.uid, VALID_EXPIRED_SESSION.uid); | ||
test.equal(facebook.getSignedRequest(), null); | ||
// test that the actual signed request equals the expected one | ||
var options = { | ||
path: '/?' + querystring.stringify({ signed_request: VALID_SIGNED_REQUEST }) | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
facebook.request = request; | ||
test.deepEqual(facebook.getSignedRequest(), payload); | ||
test.done(); | ||
}); | ||
// test that the actual signed request equals the expected one | ||
var options = { | ||
path: '/?' + querystring.stringify({ signed_request: VALID_SIGNED_REQUEST }) | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
facebook.request = request; | ||
test.deepEqual(facebook.getSignedRequest(), payload); | ||
test.done(); | ||
}); | ||
}; | ||
exports.testSignedTokenInQuery = function(test) { | ||
var options = { | ||
path: '/?' + querystring.stringify({ signed_request: VALID_SIGNED_REQUEST }) | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request : request | ||
}); | ||
test.ok(facebook.getSession()); | ||
test.done(); | ||
}); | ||
var options = { | ||
path: '/?' + querystring.stringify({ signed_request: VALID_SIGNED_REQUEST }) | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request : request | ||
}); | ||
test.ok(facebook.getSession()); | ||
test.done(); | ||
}); | ||
}; | ||
exports.testNonTossedSignedtoken = function(test) { | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
var payload = facebook._parseSignedRequest(NON_TOSSED_SIGNED_REQUEST); | ||
test.ok(payload, 'Expected token to parse'); | ||
var session = facebook._createSessionFromSignedRequest(payload); | ||
test.ok(!session); | ||
test.ok(!facebook.getSignedRequest()); | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
var payload = facebook._parseSignedRequest(NON_TOSSED_SIGNED_REQUEST); | ||
test.ok(payload, 'Expected token to parse'); | ||
var session = facebook._createSessionFromSignedRequest(payload); | ||
test.ok(!session); | ||
test.ok(!facebook.getSignedRequest()); | ||
// test an actual http signed request | ||
var options = { | ||
path: '/?' + querystring.stringify({ signed_request: NON_TOSSED_SIGNED_REQUEST }) | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
facebook.request = request; | ||
test.deepEqual(facebook.getSignedRequest(), {algorithm : 'HMAC-SHA256'}); | ||
test.done(); | ||
}); | ||
// test an actual http signed request | ||
var options = { | ||
path: '/?' + querystring.stringify({ signed_request: NON_TOSSED_SIGNED_REQUEST }) | ||
}; | ||
httpServerTest(options, function(request, response) { | ||
facebook.request = request; | ||
test.deepEqual(facebook.getSignedRequest(), {algorithm : 'HMAC-SHA256'}); | ||
test.done(); | ||
}); | ||
}; | ||
exports.testVideoUpload = function(test) { | ||
var facebook = new Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET | ||
}); | ||
facebook.setSession(VALID_EXPIRED_SESSION); | ||
var url = facebook._getApiUrl('video.upload'); | ||
test.ok(url.indexOf('//api-video.') >= 0, 'video.upload should go against api-video'); | ||
test.done(); | ||
}; | ||
// TODO: is it possible or necessary to support this? | ||
// exports.testBundledCACert = function(test) { | ||
// var facebook = new fbsdk.Facebook({ | ||
// var facebook = new Facebook({ | ||
// appId : APP_ID, | ||
@@ -789,24 +734,35 @@ // secret : SECRET, | ||
*/ | ||
function httpServerTest(options, test, result) { | ||
options.host = 'localhost'; | ||
options.port = 8889; | ||
options.path = options.path || '/'; | ||
function httpServerTest(options, test) { | ||
var transport = options.https ? https : http; | ||
options.host = 'localhost'; | ||
options.port = 8889; | ||
options.path = options.path || '/'; | ||
// create a server to test an http request | ||
var server = http.createServer(function(request, response) { | ||
test(request, response); | ||
response.end(); | ||
server.close(); | ||
}); | ||
server.listen(options.port, function() { | ||
http.request(options, result).end(); | ||
}); | ||
if (options.https) { | ||
var server = transport.createServer({ | ||
key: fs.readFileSync(__dirname + '/test_key.pem'), | ||
cert: fs.readFileSync(__dirname + '/test_cert.pem') | ||
}); | ||
} else { | ||
var server = transport.createServer(); | ||
} | ||
server.on('request', function(request, response) { | ||
test(request, response); | ||
response.end(); | ||
server.close(); | ||
}); | ||
server.listen(options.port, function() { | ||
transport.request(options /* , response */ ).end(); | ||
}); | ||
} | ||
function clone(object) { | ||
var new_object = {}; | ||
for (var i in object) { | ||
new_object[i] = object[i]; | ||
} | ||
return new_object; | ||
var new_object = {}; | ||
for (var i in object) { | ||
new_object[i] = object[i]; | ||
} | ||
return new_object; | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
58066
9
1561
1
5