facebook-sdk
Advanced tools
Comparing version 0.2.1 to 0.2.2
@@ -0,1 +1,17 @@ | ||
/** | ||
* Copyright 2011 Christopher Johnson <tenorviol@yahoo.com> | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
var crypto = require('crypto'), | ||
@@ -10,4 +26,2 @@ http = require('http'), | ||
* Thrown when an API call returns an exception. | ||
* | ||
* @author Naitik Shah <naitik@facebook.com> | ||
*/ | ||
@@ -35,5 +49,3 @@ var FacebookApiException = function(result) { | ||
FacebookApiException.prototype = { | ||
/** | ||
* The result from the API server that represents the exception information. | ||
*/ | ||
// The result from the API server that represents the exception information. | ||
result: null, | ||
@@ -44,3 +56,3 @@ | ||
* | ||
* @returns Array the result from the API server | ||
* @return {Object} the result from the API server | ||
*/ | ||
@@ -55,3 +67,3 @@ getResult: function() { | ||
* | ||
* @return String | ||
* @return {String} | ||
*/ | ||
@@ -75,3 +87,3 @@ getType: function() { | ||
* | ||
* @returns String the string representation of the error | ||
* @return {String} the string representation of the error | ||
*/ | ||
@@ -88,3 +100,3 @@ toString: function() { | ||
/** | ||
* Initialize a Facebook Application. | ||
* Initialize the Facebook Application, providing access to the Facebook platform API. | ||
* | ||
@@ -94,12 +106,16 @@ * The configuration: | ||
* - secret: the application secret | ||
* // TODO: rename to httpRequest? | ||
* - request: http.ServerRequest for reclaiming sessions | ||
* - response: http.ServerResponse for writing the cookie to | ||
* - siteUrl: | ||
* - siteUrl: (optional) url of the Facebook app, used for generating next/cancel urls | ||
* - request: (optional) http.ServerRequest for reclaiming sessions | ||
* - response: (optional) http.ServerResponse for writing the cookie to | ||
* - domain: (optional) domain for the cookie | ||
* TODO: | ||
* - fileUpload: (optional) boolean indicating if file uploads are enabled | ||
* | ||
* @param Array config the application configuration | ||
* @param {Object} config the application configuration | ||
*/ | ||
var Facebook = exports.Facebook = function(config) { | ||
if (!(this instanceof Facebook)) { | ||
return new Facebook(config); | ||
} | ||
for (var i in config) { | ||
@@ -110,19 +126,42 @@ this[i] = config[i]; | ||
/** | ||
* Provides access to the Facebook Platform. | ||
*/ | ||
Facebook.prototype = { | ||
/** | ||
* Default options for curl. | ||
*/ | ||
// TODO: can these be used? | ||
CURLOPT_CONNECTTIMEOUT : 10, | ||
//CURLOPT_RETURNTRANSFER : true, | ||
CURLOPT_TIMEOUT_MS : 60000, | ||
//CURLOPT_USERAGENT : 'facebook-php-2.0', | ||
/** | ||
* List of query parameters that get automatically dropped when rebuilding | ||
* the current URL. | ||
*/ | ||
// The Application ID. | ||
appId: null, | ||
// The Application API Secret. | ||
secret: null, | ||
// Url of the app | ||
siteUrl: null, | ||
// http.ServerRequest for initializing the session | ||
request: null, | ||
// http.ServerResponse for writing the session cookie | ||
response: null, | ||
// Base domain for the Cookie. | ||
domain: '', | ||
// 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, | ||
// The active user session, if one is available. | ||
_session: null, | ||
// The data from the signed_request token. | ||
_signedRequest: null, | ||
// 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: [ | ||
@@ -133,5 +172,3 @@ 'session', | ||
/** | ||
* Maps aliases to Facebook domains. | ||
*/ | ||
// Map of aliases to Facebook domains | ||
DOMAIN_MAP: { | ||
@@ -144,32 +181,15 @@ api : 'https://api.facebook.com/', | ||
// /** | ||
// * The active user session, if one is available. | ||
// */ | ||
// protected session; | ||
// | ||
// /** | ||
// * The data from the signed_request token. | ||
// */ | ||
// protected signedRequest; | ||
// | ||
// /** | ||
// * Indicates that we already loaded the session as best as we could. | ||
// */ | ||
// protected sessionLoaded = false; | ||
/** | ||
* Get the data from a signed_request token | ||
* | ||
* @return String the base domain | ||
* @return {Object} | ||
*/ | ||
getSignedRequest: function() { | ||
if (!this.signedRequest) { | ||
if (this.request) { | ||
var parse = URL.parse(this.request.url, true); | ||
if (parse.query.signed_request) { | ||
this.signedRequest = this._parseSignedRequest(parse.query.signed_request); | ||
} | ||
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; | ||
return this._signedRequest; | ||
}, | ||
@@ -180,5 +200,4 @@ | ||
* | ||
* @param Array session the session | ||
* @param Boolean write_cookie indicate if a cookie should be written. this | ||
* value is ignored if cookie support has been disabled. | ||
* @param {Object} session the session | ||
* @param {boolean} write_cookie indicate if a cookie should be written. ignored if no response object. | ||
*/ | ||
@@ -188,4 +207,4 @@ setSession: function(session, write_cookie) { | ||
session = this._validateSessionObject(session); | ||
this.sessionLoaded = true; | ||
this.session = session; | ||
this._sessionLoaded = true; | ||
this._session = session; | ||
if (write_cookie) { | ||
@@ -201,10 +220,10 @@ this._setCookieFromSession(session); | ||
* | ||
* @return Array the session | ||
* @return {Object} the session | ||
*/ | ||
getSession: function() { | ||
if (!this.sessionLoaded) { | ||
if (!this._sessionLoaded) { | ||
var session = null; | ||
var write_cookie = true; | ||
// try loading session from signed_request in _REQUEST | ||
// try loading session from signed_request in request | ||
signedRequest = this.getSignedRequest(); | ||
@@ -216,4 +235,4 @@ if (signedRequest) { | ||
// try loading session from _REQUEST | ||
// TODO: this works from querystring requests, make it work with POST, PUT and DELETE data | ||
// 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) { | ||
@@ -229,6 +248,5 @@ var parse = URL.parse(this.request.url, true); | ||
if (!session && this.request) { | ||
var cookies = querystring.parse(this.request.headers.cookie); | ||
var cookieName = this._getSessionCookieName(); | ||
if (cookies[cookieName]) { | ||
var cookie = cookies[cookieName].replace(/^"*|"*$/g, ''); | ||
var cookie = this._getSessionCookie(); | ||
if (cookie) { | ||
var cookie = cookie.replace(/^"*|"*$/g, ''); | ||
session = querystring.parse(cookie); | ||
@@ -244,9 +262,26 @@ session = this._validateSessionObject(session); | ||
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]; | ||
}, | ||
/** | ||
* Get the UID from the session. | ||
* | ||
* @return String the UID if available | ||
* @return {String} the UID if available | ||
*/ | ||
@@ -261,3 +296,3 @@ getUser: function() { | ||
* | ||
* @return String the access token | ||
* @return {String} the access token | ||
*/ | ||
@@ -279,3 +314,3 @@ getAccessToken: function() { | ||
* | ||
* The parameters: | ||
* The parameters (optional): | ||
* - next: the url to go to after a successful login | ||
@@ -286,4 +321,4 @@ * - cancel_url: the url to go to after the user cancels | ||
* | ||
* @param Array params provide custom parameters | ||
* @return String the URL for the login flow | ||
* @param {Object} params provide custom parameters | ||
* @return {String} the URL for the login flow | ||
*/ | ||
@@ -317,4 +352,4 @@ getLoginUrl: function(params) { | ||
* | ||
* @param Array params provide custom parameters | ||
* @return String the URL for the logout flow | ||
* @param {Object} params provide custom parameters | ||
* @return {String} the URL for the logout flow | ||
*/ | ||
@@ -343,4 +378,4 @@ getLogoutUrl: function(params) { | ||
* | ||
* @param Array params provide custom parameters | ||
* @return String the URL for the logout flow | ||
* @param {Object} params provide custom parameters | ||
* @return {String} the URL for the logout flow | ||
*/ | ||
@@ -366,5 +401,2 @@ getLoginStatusUrl: function(params) { | ||
* Make an API call. | ||
* | ||
* @param Array params the API call parameters | ||
* @return the decoded response | ||
*/ | ||
@@ -382,5 +414,4 @@ api: function(/* polymorphic */) { | ||
* | ||
* @param Array params method call object | ||
* @return the decoded response object | ||
* @throws FacebookApiException | ||
* @param {Object} params method call object | ||
* @param {Function( object )} callback to send the decoded response object | ||
*/ | ||
@@ -409,8 +440,6 @@ _restserver: function(params, callback) { | ||
* | ||
* @param String path the path (required) | ||
* @param String method the http method (default 'GET') | ||
* @param Array params the query/post data | ||
* @return the decoded response object | ||
* @throws FacebookApiException | ||
* NOTE: the method param has been removed, but can be included in the params (default 'GET') | ||
* @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 | ||
*/ | ||
@@ -455,6 +484,6 @@ _graph: function(path, method, params, callback) { | ||
* | ||
* @param String path the path (required) | ||
* @param Array params the query/post data | ||
* @return the decoded response object | ||
* @throws FacebookApiException | ||
* @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 | ||
*/ | ||
@@ -467,3 +496,3 @@ _oauthRequest: function(url, params, success, error) { | ||
// json encode all params values that are not strings | ||
// TODO: this is untested | ||
// TODO: untested | ||
for (var key in params) { | ||
@@ -483,6 +512,6 @@ if (typeof params[key] == 'object') { | ||
* | ||
* @param String url the URL to make the request to | ||
* @param Array params the parameters to use for the POST body | ||
* @param CurlHandler ch optional initialized curl handle | ||
* @return String the response text | ||
* @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 | ||
*/ | ||
@@ -506,2 +535,4 @@ _makeRequest: function(url, params, success, error) { | ||
// TODO: header 'Expect: 100-continue'? This was a part of the original curl makeRequest | ||
var request = protocol.request(options, function(result) { | ||
@@ -521,2 +552,9 @@ result.setEncoding('utf8'); | ||
// TODO? | ||
// if (this.useFileUploadSupport()) { | ||
// opts[CURLOPT_POSTFIELDS] = params; | ||
// } else { | ||
// opts[CURLOPT_POSTFIELDS] = http_build_query(params, null, '&'); | ||
// } | ||
request.write(querystring.stringify(params)); | ||
@@ -534,47 +572,4 @@ request.end(); | ||
}); | ||
error(e); | ||
}, this.CURLOPT_TIMEOUT_MS); | ||
// opts = self::CURL_OPTS; | ||
// if (this.useFileUploadSupport()) { | ||
// opts[CURLOPT_POSTFIELDS] = params; | ||
// } else { | ||
// opts[CURLOPT_POSTFIELDS] = http_build_query(params, null, '&'); | ||
// } | ||
// opts[CURLOPT_URL] = url; | ||
// | ||
// // disable the 'Expect: 100-continue' behaviour. This causes CURL to wait | ||
// // for 2 seconds if the server does not support this header. | ||
// if (isset(opts[CURLOPT_HTTPHEADER])) { | ||
// existing_headers = opts[CURLOPT_HTTPHEADER]; | ||
// existing_headers[] = 'Expect:'; | ||
// opts[CURLOPT_HTTPHEADER] = existing_headers; | ||
// } else { | ||
// opts[CURLOPT_HTTPHEADER] = array('Expect:'); | ||
// } | ||
// | ||
// curl_setopt_array(ch, opts); | ||
// result = curl_exec(ch); | ||
// | ||
// if (curl_errno(ch) == 60) { // CURLE_SSL_CACERT | ||
// self::errorLog('Invalid or no certificate authority found, using bundled information'); | ||
// curl_setopt(ch, CURLOPT_CAINFO, | ||
// dirname(__FILE__) . '/fb_ca_chain_bundle.crt'); | ||
// result = curl_exec(ch); | ||
// } | ||
// | ||
// if (result === false) { | ||
// e = new FacebookApiException(array( | ||
// error_code : curl_errno(ch), | ||
// error : array( | ||
// message : curl_error(ch), | ||
// type : 'CurlException', | ||
// ), | ||
// )); | ||
// curl_close(ch); | ||
// throw e; | ||
// } | ||
// curl_close(ch); | ||
// return result; | ||
error && error(e); | ||
}, this.timeout); | ||
}, | ||
@@ -585,3 +580,3 @@ | ||
* | ||
* @return String the cookie name | ||
* @return {String} the cookie name | ||
*/ | ||
@@ -596,3 +591,3 @@ _getSessionCookieName: function() { | ||
* | ||
* @param Array session the session to use for setting the cookie | ||
* @param {Object} session the session to use for setting the cookie | ||
*/ | ||
@@ -635,3 +630,13 @@ _setCookieFromSession: function(session) { | ||
/** | ||
* 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); | ||
@@ -653,4 +658,4 @@ if (expires) { | ||
* | ||
* @param Array session the session object | ||
* @return Array the session object if it validates, null otherwise | ||
* @param {Object} session the session object | ||
* @return {Object} the session object if it validates, null otherwise | ||
*/ | ||
@@ -691,4 +696,4 @@ _validateSessionObject: function(session) { | ||
* | ||
* @param Array the output of getSignedRequest | ||
* @return Array Something that will work as a session | ||
* @param {Object} data the output of getSignedRequest | ||
* @return {Object} Something that will work as a session | ||
*/ | ||
@@ -719,6 +724,4 @@ _createSessionFromSignedRequest: function(data) { | ||
* | ||
* @param String A signed token | ||
* @param Boolean Should we remove the parts of the payload that | ||
* are used by the algorithm? | ||
* @return Array the payload inside it or null if the sig is wrong | ||
* @param {String} signed_request A signed token | ||
* @return {Object} the payload inside it or null if the sig is wrong | ||
*/ | ||
@@ -757,4 +760,4 @@ _parseSignedRequest: function(signed_request) { | ||
* | ||
* @param method String the method name. | ||
* @return String the URL for the given parameters | ||
* @param {String} method the method name. | ||
* @return {String} the URL for the given parameters | ||
*/ | ||
@@ -834,6 +837,6 @@ _getApiUrl: function(method) { | ||
* | ||
* @param name String the name of the domain | ||
* @param path String optional path (without a leading slash) | ||
* @param params Array optional query parameters | ||
* @return String the URL for the given 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 | ||
*/ | ||
@@ -858,3 +861,3 @@ _getUrl: function(name, path, params) { | ||
* | ||
* @return String the current URL | ||
* @return {String} the current URL | ||
*/ | ||
@@ -881,5 +884,5 @@ _getCurrentUrl: function() { | ||
* | ||
* @param Array params the parameters to sign | ||
* @param String secret the secret to sign with | ||
* @return String the generated signature | ||
* @param {Object} params the parameters to sign | ||
* @param {String} secret the secret to sign with | ||
* @return {String} the generated signature | ||
*/ | ||
@@ -898,3 +901,3 @@ _generateSignature: function(params, secret) { | ||
* | ||
* @param String log message | ||
* @param {String} msg log message | ||
*/ | ||
@@ -911,3 +914,4 @@ _errorLog: function(msg) { | ||
* | ||
* @param String base64UrlEncodeded string | ||
* @param {String} input base64UrlEncodeded string | ||
* @param {String} decoded | ||
*/ | ||
@@ -914,0 +918,0 @@ _base64UrlDecode: function(input) { |
@@ -5,3 +5,3 @@ { | ||
"keywords": ["facebook", "sdk", "graph", "api", "connect", "canvas"], | ||
"version": "0.2.1", | ||
"version": "0.2.2", | ||
"author": "Christopher Johnson <tenorviol@yahoo.com> (http://github.com/tenorviol)", | ||
@@ -8,0 +8,0 @@ "repository" : { |
@@ -1,5 +0,5 @@ | ||
node.js Facebook SDK | ||
==================== | ||
[node.js Facebook SDK](https://github.com/tenorviol/node-facebook-sdk) | ||
====================== | ||
This is a port of Facebook's [PHP SDK library](http://github.com/facebook/php-sdk). | ||
This is a complete port of Facebook's [PHP SDK library](http://github.com/facebook/php-sdk). | ||
@@ -11,5 +11,4 @@ > The [Facebook Platform](http://developers.facebook.com/) is | ||
I retain the open source apache license of the original SDK. | ||
The node.js Facebook SDK is licensed under the Apache License, Version 2.0 | ||
(http://www.apache.org/licenses/LICENSE-2.0.html). | ||
(http://www.apache.org/licenses/LICENSE-2.0.html), as was the original library. | ||
@@ -58,4 +57,4 @@ Usage | ||
The tests have been ported as well. It was the easiest way to confirm the new node.js | ||
library works as expected. New tests are to be added as needed for reported bugs or | ||
new features. | ||
The tests have been ported to run using nodeunit. This was the easiest way to confirm | ||
the new node.js library works as expected. Some new tests have been added to cover | ||
edge cases, and others that are not relevant in the new environment have been removed. |
@@ -0,1 +1,17 @@ | ||
/** | ||
* Copyright 2011 Christopher Johnson <tenorviol@yahoo.com> | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
var fbsdk = require('../lib/facebook'), | ||
@@ -182,4 +198,23 @@ http = require('http'), | ||
test.done(); | ||
} | ||
}; | ||
// regression: this is to test cookies that were set using Facebook's client-side Javascript SDK | ||
exports.testGetSessionUnescaped = function(test) { | ||
// regression test: the cookie we set should be getSession-able | ||
var request = { | ||
url: '/', | ||
headers: { | ||
// cookie copied from Facebook's Javascript SDK running on Safari | ||
cookie: 'junk=foo; fbs_117743971608120="access_token=117743971608120%7C2.vdCKd4ZIEJlHwwtrkilgKQ__.86400.1281049200-1677846385%7CNF_2DDNxFBznj2CuwiwabHhTAHc.&expires=1281049200&secret=u0QiRGAwaPCyQ7JE_hiz1w__&session_key=2.vdCKd4ZIEJlHwwtrkilgKQ__.86400.1281049200-1677846385&sig=7a9b063de0bef334637832166948dcad&uid=1677846385"' | ||
} | ||
}; | ||
var facebook = new fbsdk.Facebook({ | ||
appId : APP_ID, | ||
secret : SECRET, | ||
request: request | ||
}); | ||
test.deepEqual(facebook.getSession(), VALID_EXPIRED_SESSION); | ||
test.done(); | ||
}; | ||
exports.testGetSessionFromCookie = function(test) { | ||
@@ -406,3 +441,3 @@ var cookieName = 'fbs_' + APP_ID; | ||
// we dont expect facebook will ever return in 1ms | ||
facebook.CURLOPT_TIMEOUT_MS = 1; | ||
facebook.timeout = 1; | ||
facebook.api('/naitik', function(data) { | ||
@@ -409,0 +444,0 @@ test.ok(data.error); |
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
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
No License Found
License(Experimental) License information could not be found.
Found 1 instance in 1 package
49456
0
1487
4
59