PageRenderTime 26ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/src/core/auth.js

https://github.com/cramforce/mu
JavaScript | 403 lines | 133 code | 27 blank | 243 comment | 37 complexity | 3bdc858f60869d4ade3f001726d1bf59 MD5 | raw file
  1. /**
  2. * Copyright Facebook Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. *
  17. *
  18. * @provides fb.auth
  19. * @requires fb.prelude
  20. * fb.qs
  21. * fb.event
  22. * fb.frames
  23. * fb.json2
  24. */
  25. /**
  26. * Authentication, Authorization & Sessions.
  27. *
  28. * @class FB
  29. * @static
  30. * @access private
  31. */
  32. FB.copy('', {
  33. /**
  34. * Find out the current status from the server, and get a session if the user
  35. * is connected.
  36. *
  37. * The User's Status or the question of "who is the current user" is
  38. * the first thing you will typically start with. For the answer, we
  39. * ask facebook.com. Facebook will answer this question in one of
  40. * two ways:
  41. *
  42. * 1. Someone you don't know.
  43. * 2. Someone you know and have interacted with. Here's a session for them.
  44. *
  45. * Here's how you find out:
  46. *
  47. * FB.getLoginStatus(function(response) {
  48. * if (response.session) {
  49. * // logged in and connected user, someone you know
  50. * } else {
  51. * // no user session available, someone you dont know
  52. * }
  53. * });
  54. *
  55. * The example above will result in the callback being invoked once
  56. * on load based on the session from www.facebook.com. For more
  57. * advanced use, you may with to monitor for various events.
  58. *
  59. * **Events**
  60. *
  61. * - auth.login
  62. * - auth.logout
  63. * - auth.sessionChange
  64. * - auth.statusChange
  65. *
  66. * The [FB.Event.subscribe][subscribe] and
  67. * [FB.Event.unsubscribe][unsubscribe] functions are used to subscribe to
  68. * these events. For example:
  69. *
  70. * FB.Event.subscribe('auth.login', function(response) {
  71. * // do something with response
  72. * });
  73. *
  74. * The response object returned to all these events is the same as the
  75. * response from [FB.getLoginStatus][getLoginStatus], [FB.login][login] or
  76. * [FB.logout][logout]. This response object contains:
  77. *
  78. * status
  79. * : The status of the User. One of `connected`, `notConnected` or `unknown`.
  80. *
  81. * session
  82. * : The session object.
  83. *
  84. * perms
  85. * : The comma separated permissions string. This is specific to a
  86. * permissions call. It is not persistent.
  87. *
  88. * [subscribe]: /docs/?u=facebook.jslib-alpha.FB.Event.subscribe
  89. * [unsubscribe]: /docs/?u=facebook.jslib-alpha.FB.Event.unsubscribe
  90. * [getLoginStatus]: /docs/?u=facebook.jslib-alpha.FB.getLoginStatus
  91. * [login]: /docs/?u=facebook.jslib-alpha.FB.login
  92. * [logout]: /docs/?u=facebook.jslib-alpha.FB.logout
  93. *
  94. * @access public
  95. * @param cb {Function} the callback function
  96. * @param force {Boolean} force reloading the login status (default false)
  97. */
  98. getLoginStatus: function(cb, force) {
  99. if (!FB._apiKey) {
  100. FB.log('FB.getLoginStatus() called before calling FB.init().');
  101. return;
  102. }
  103. // we either invoke the callback right away if the status has already been
  104. // loaded, or queue it up for when the load is done.
  105. if (cb) {
  106. if (!force && FB.Auth._loadState == 'loaded') {
  107. cb({ status: FB._userStatus, session: FB._session });
  108. return;
  109. } else {
  110. FB.Auth._callbacks.push(cb);
  111. }
  112. }
  113. // if we're already loading, and this is not a force load, we're done
  114. if (!force && FB.Auth._loadState == 'loading') {
  115. return;
  116. }
  117. FB.Auth._loadState = 'loading';
  118. // invoke the queued sessionLoad callbacks
  119. var lsCb = function(response) {
  120. // done
  121. FB.Auth._loadState = 'loaded';
  122. // consume the current load queue and reset
  123. var waitingCb = FB.Auth._callbacks;
  124. FB.Auth._callbacks = [];
  125. for (var i=0, l=waitingCb.length; i<l; i++) {
  126. waitingCb[i](response);
  127. }
  128. };
  129. // finally make the call to login status
  130. var
  131. xdHandler = FB.Auth.xdHandler,
  132. g = FB.guid(),
  133. url = FB._domain.www + 'extern/login_status.php?' + FB.QS.encode({
  134. api_key : FB._apiKey,
  135. no_session : xdHandler(lsCb, g, 'parent', false, 'notConnected'),
  136. no_user : xdHandler(lsCb, g, 'parent', false, 'unknown'),
  137. ok_session : xdHandler(lsCb, g, 'parent', false, 'connected'),
  138. session_version : 2
  139. });
  140. FB.Frames.hidden(url, g);
  141. },
  142. /**
  143. * Accessor for the current Session.
  144. *
  145. * @access public
  146. * @return {Object} the current Session if available, `null` otherwise
  147. */
  148. getSession: function() {
  149. return FB._session;
  150. },
  151. /**
  152. * Login/Authorize/Permissions.
  153. *
  154. * Once you have determined the user's status, you may need to
  155. * prompt the user to login. It is best to delay this action to
  156. * reduce user friction when they first arrive at your site. You can
  157. * then prompt and show them the "Connect with Facebook" button
  158. * bound to an event handler which does the following:
  159. *
  160. * FB.login(function(response) {
  161. * if (response.session) {
  162. * // user successfully logged in
  163. * } else {
  164. * // user cancelled login
  165. * }
  166. * });
  167. *
  168. * You should **only** call this on a user event as it opens a
  169. * popup. Most browsers block popups, _unless_ they were initiated
  170. * from a user event, such as a click on a button or a link.
  171. *
  172. *
  173. * Depending on your application's needs, you may need additional
  174. * permissions from the user. A large number of calls do not require
  175. * any additional permissions, so you should first make sure you
  176. * need a permission. This is a good idea because this step
  177. * potentially adds friction to the user's process. Another point to
  178. * remember is that this call can be made even _after_ the user has
  179. * first connected. So you may want to delay asking for permissions
  180. * until as late as possible::
  181. *
  182. * FB.login(function(response) {
  183. * if (response.session) {
  184. * if (response.perms) {
  185. * // user is logged in and granted some permissions.
  186. * // perms is a comma separated list of granted permissions
  187. * } else {
  188. * // user is logged in, but did not grant any permissions
  189. * }
  190. * } else {
  191. * // user is not logged in
  192. * }
  193. * }, 'read_stream,publish_stream,offline_access');
  194. *
  195. * @access public
  196. * @param cb {Function} the callback function
  197. * @param perms {String} (_optional_) comma separated list of permissions
  198. * your application requires
  199. */
  200. login: function(cb, perms) {
  201. if (!FB._apiKey) {
  202. FB.log('FB.login() called before calling FB.init().');
  203. return;
  204. }
  205. // if we already have a session and permissions are not being requested, we
  206. // just fire the callback
  207. if (FB._session && !perms) {
  208. FB.log('FB.login() called when user is already connected.');
  209. cb && cb({ status: FB._userStatus, session: FB._session });
  210. return;
  211. }
  212. var
  213. xdHandler = FB.Auth.xdHandler,
  214. g = FB.guid(),
  215. cancel = xdHandler(cb, g, 'opener', true, FB._userStatus, FB._session),
  216. next = xdHandler(cb, g, 'opener', false, 'connected', FB._session),
  217. url = FB._domain.www + 'login.php?' + FB.QS.encode({
  218. api_key : FB._apiKey,
  219. cancel_url : cancel,
  220. channel_url : window.location.toString(),
  221. display : 'popup',
  222. fbconnect : 1,
  223. next : next,
  224. req_perms : perms,
  225. return_session : 1,
  226. session_version : 2,
  227. v : '1.0'
  228. });
  229. FB.Frames.popup(url, 450, 415, g);
  230. },
  231. /**
  232. * Logout the user in the background.
  233. *
  234. * Just like logging in is tied to facebook.com, so is logging out.
  235. * The status shared between your site and Facebook, and logging out
  236. * affects both sites. This is a simple call:
  237. *
  238. * FB.logout(function(response) {
  239. * // user is now logged out
  240. * });
  241. *
  242. * @access public
  243. * @param cb {Function} the callback function
  244. */
  245. logout: function(cb) {
  246. if (!FB._apiKey) {
  247. FB.log('FB.logout() called before calling FB.init().');
  248. return;
  249. }
  250. if (!FB._session) {
  251. FB.log('FB.logout() called without a session.');
  252. return;
  253. }
  254. var
  255. g = FB.guid(),
  256. url = FB._domain.www + 'logout.php?' + FB.QS.encode({
  257. api_key : FB._apiKey,
  258. next : FB.Auth.xdHandler(cb, g, 'parent', false, 'unknown'),
  259. session_key : FB._session.session_key
  260. });
  261. FB.Frames.hidden(url, g);
  262. }
  263. });
  264. /**
  265. * Internal Authentication implementation.
  266. *
  267. * @class FB.Auth
  268. * @static
  269. * @access private
  270. */
  271. FB.copy('Auth', {
  272. // pending callbacks for FB.getLoginStatus() calls
  273. _callbacks: [],
  274. /**
  275. * Set a new session value. Invokes all the registered subscribers
  276. * if needed.
  277. *
  278. * @access private
  279. * @param session {Object} the new Session
  280. * @param status {String} the new status
  281. * @return {Object} the "response" object
  282. */
  283. setSession: function(session, status) {
  284. // detect special changes before changing the internal session
  285. var
  286. login = !FB._session && session,
  287. logout = FB._session && !session,
  288. both = FB._session && session && FB._session.uid != session.uid,
  289. sessionChange = (FB._session && session &&
  290. FB._session.session_key != session.session_key),
  291. statusChange = status != FB._status;
  292. var response = {
  293. session : session,
  294. status : status
  295. };
  296. FB._session = session;
  297. FB._userStatus = status;
  298. // events
  299. if (statusChange) {
  300. /**
  301. * Fired when the status changes.
  302. *
  303. * @event auth.statusChange
  304. */
  305. FB.Event.fire('auth.statusChange', response);
  306. }
  307. if (logout || both) {
  308. /**
  309. * Fired when a logout action is performed.
  310. *
  311. * @event auth.logout
  312. */
  313. FB.Event.fire('auth.logout', response);
  314. }
  315. if (login || both) {
  316. /**
  317. * Fired when a login action is performed.
  318. *
  319. * @event auth.login
  320. */
  321. FB.Event.fire('auth.login', response);
  322. }
  323. if (login || logout || sessionChange) {
  324. /**
  325. * Fired when the session changes. This includes a session being
  326. * refreshed, or a login or logout action.
  327. *
  328. * @event auth.sessionChange
  329. */
  330. FB.Event.fire('auth.sessionChange', response);
  331. }
  332. return response;
  333. },
  334. /**
  335. * This handles receiving a session from:
  336. * - login_status.php
  337. * - login.php
  338. * - tos.php
  339. *
  340. * It also (optionally) handles the ``xxRESULTTOKENxx`` response from:
  341. * - prompt_permissions.php
  342. *
  343. * And calls the given callback with::
  344. *
  345. * {
  346. * session: session or null,
  347. * status: 'unknown' or 'notConnected' or 'connected',
  348. * perms: comma separated string of perm names
  349. * }
  350. *
  351. * @access private
  352. * @param cb {Function} the callback function
  353. * @param frame {String} the frame id for the callback is tied to
  354. * @param target {String} parent or opener to indicate window relation
  355. * @param isDefault {Boolean} is this the default callback for the frame
  356. * @param status {String} the connect status this handler will trigger
  357. * @param session {Object} backup session, if none is found in response
  358. * @return {String} the xd url bound to the callback
  359. */
  360. xdHandler: function(cb, frame, target, isDefault, status, session) {
  361. return FB.Frames.xdHandler(function(params) {
  362. // try to extract a session
  363. var response;
  364. try {
  365. response = FB.Auth.setSession(JSON.parse(params.session), status);
  366. } catch(x) {
  367. response = FB.Auth.setSession(session || null, status);
  368. }
  369. // incase we were granted some new permissions
  370. response.perms = (
  371. params.result != 'xxRESULTTOKENxx' && params.result || '');
  372. // user defined callback
  373. cb && cb(response);
  374. }, frame, target, isDefault) + '&result=xxRESULTTOKENxx';
  375. }
  376. });