PageRenderTime 59ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/custom/include/social/facebook/facebook_sdk/tests/tests.php

https://github.com/BarnetikKoop/SuiteCRM
PHP | 2125 lines | 1837 code | 214 blank | 74 comment | 8 complexity | ae9cc21f0c90dd921e69f680334709b5 MD5 | raw file
Possible License(s): AGPL-3.0, LGPL-2.1, MPL-2.0-no-copyleft-exception
  1. <?php
  2. /**
  3. * Copyright 2011 Facebook, Inc.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License"); you may
  6. * not use this file except in compliance with the License. You may obtain
  7. * a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  13. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  14. * License for the specific language governing permissions and limitations
  15. * under the License.
  16. */
  17. class PHPSDKTestCase extends PHPUnit_Framework_TestCase {
  18. const APP_ID = '117743971608120';
  19. const SECRET = '9c8ea2071859659bea1246d33a9207cf';
  20. const MIGRATED_APP_ID = '174236045938435';
  21. const MIGRATED_SECRET = '0073dce2d95c4a5c2922d1827ea0cca6';
  22. const TEST_USER = 499834690;
  23. const TEST_USER_2 = 499835484;
  24. private static $kExpiredAccessToken = 'AAABrFmeaJjgBAIshbq5ZBqZBICsmveZCZBi6O4w9HSTkFI73VMtmkL9jLuWsZBZC9QMHvJFtSulZAqonZBRIByzGooCZC8DWr0t1M4BL9FARdQwPWPnIqCiFQ';
  25. private static function kValidSignedRequest($id = self::TEST_USER, $oauth_token = null) {
  26. $facebook = new FBPublic(array(
  27. 'appId' => self::APP_ID,
  28. 'secret' => self::SECRET,
  29. ));
  30. return $facebook->publicMakeSignedRequest(
  31. array(
  32. 'user_id' => $id,
  33. 'oauth_token' => $oauth_token
  34. )
  35. );
  36. }
  37. private static function kNonTosedSignedRequest() {
  38. $facebook = new FBPublic(array(
  39. 'appId' => self::APP_ID,
  40. 'secret' => self::SECRET,
  41. ));
  42. return $facebook->publicMakeSignedRequest(array());
  43. }
  44. private static function kSignedRequestWithEmptyValue() {
  45. return '';
  46. }
  47. private static function kSignedRequestWithBogusSignature() {
  48. $facebook = new FBPublic(array(
  49. 'appId' => self::APP_ID,
  50. 'secret' => 'bogus',
  51. ));
  52. return $facebook->publicMakeSignedRequest(
  53. array(
  54. 'algorithm' => 'HMAC-SHA256',
  55. )
  56. );
  57. }
  58. private static function kSignedRequestWithWrongAlgo() {
  59. $facebook = new FBPublic(array(
  60. 'appId' => self::APP_ID,
  61. 'secret' => self::SECRET,
  62. ));
  63. $data['algorithm'] = 'foo';
  64. $json = json_encode($data);
  65. $b64 = $facebook->publicBase64UrlEncode($json);
  66. $raw_sig = hash_hmac('sha256', $b64, self::SECRET, $raw = true);
  67. $sig = $facebook->publicBase64UrlEncode($raw_sig);
  68. return $sig.'.'.$b64;
  69. }
  70. public function testConstructor() {
  71. $facebook = new TransientFacebook(array(
  72. 'appId' => self::APP_ID,
  73. 'secret' => self::SECRET,
  74. ));
  75. $this->assertEquals($facebook->getAppId(), self::APP_ID,
  76. 'Expect the App ID to be set.');
  77. $this->assertEquals($facebook->getAppSecret(), self::SECRET,
  78. 'Expect the API secret to be set.');
  79. }
  80. public function testConstructorWithFileUpload() {
  81. $facebook = new TransientFacebook(array(
  82. 'appId' => self::APP_ID,
  83. 'secret' => self::SECRET,
  84. 'fileUpload' => true,
  85. ));
  86. $this->assertEquals($facebook->getAppId(), self::APP_ID,
  87. 'Expect the App ID to be set.');
  88. $this->assertEquals($facebook->getAppSecret(), self::SECRET,
  89. 'Expect the API secret to be set.');
  90. $this->assertTrue($facebook->getFileUploadSupport(),
  91. 'Expect file upload support to be on.');
  92. // alias (depricated) for getFileUploadSupport -- test until removed
  93. $this->assertTrue($facebook->useFileUploadSupport(),
  94. 'Expect file upload support to be on.');
  95. }
  96. public function testSetAppId() {
  97. $facebook = new TransientFacebook(array(
  98. 'appId' => self::APP_ID,
  99. 'secret' => self::SECRET,
  100. ));
  101. $facebook->setAppId('dummy');
  102. $this->assertEquals($facebook->getAppId(), 'dummy',
  103. 'Expect the App ID to be dummy.');
  104. }
  105. public function testSetAPISecret() {
  106. $facebook = new TransientFacebook(array(
  107. 'appId' => self::APP_ID,
  108. 'secret' => self::SECRET,
  109. ));
  110. $facebook->setApiSecret('dummy');
  111. $this->assertEquals($facebook->getApiSecret(), 'dummy',
  112. 'Expect the API secret to be dummy.');
  113. }
  114. public function testSetAPPSecret() {
  115. $facebook = new TransientFacebook(array(
  116. 'appId' => self::APP_ID,
  117. 'secret' => self::SECRET,
  118. ));
  119. $facebook->setAppSecret('dummy');
  120. $this->assertEquals($facebook->getAppSecret(), 'dummy',
  121. 'Expect the API secret to be dummy.');
  122. }
  123. public function testSetAccessToken() {
  124. $facebook = new TransientFacebook(array(
  125. 'appId' => self::APP_ID,
  126. 'secret' => self::SECRET,
  127. ));
  128. $facebook->setAccessToken('saltydog');
  129. $this->assertEquals($facebook->getAccessToken(), 'saltydog',
  130. 'Expect installed access token to remain \'saltydog\'');
  131. }
  132. public function testSetFileUploadSupport() {
  133. $facebook = new TransientFacebook(array(
  134. 'appId' => self::APP_ID,
  135. 'secret' => self::SECRET,
  136. ));
  137. $this->assertFalse($facebook->getFileUploadSupport(),
  138. 'Expect file upload support to be off.');
  139. // alias for getFileUploadSupport (depricated), testing until removed
  140. $this->assertFalse($facebook->useFileUploadSupport(),
  141. 'Expect file upload support to be off.');
  142. $facebook->setFileUploadSupport(true);
  143. $this->assertTrue($facebook->getFileUploadSupport(),
  144. 'Expect file upload support to be on.');
  145. // alias for getFileUploadSupport (depricated), testing until removed
  146. $this->assertTrue($facebook->useFileUploadSupport(),
  147. 'Expect file upload support to be on.');
  148. }
  149. public function testGetCurrentURL() {
  150. $facebook = new FBGetCurrentURLFacebook(array(
  151. 'appId' => self::APP_ID,
  152. 'secret' => self::SECRET,
  153. ));
  154. // fake the HPHP $_SERVER globals
  155. $_SERVER['HTTP_HOST'] = 'www.test.com';
  156. $_SERVER['REQUEST_URI'] = '/unit-tests.php?one=one&two=two&three=three';
  157. $current_url = $facebook->publicGetCurrentUrl();
  158. $this->assertEquals(
  159. 'http://www.test.com/unit-tests.php?one=one&two=two&three=three',
  160. $current_url,
  161. 'getCurrentUrl function is changing the current URL');
  162. // ensure structure of valueless GET params is retained (sometimes
  163. // an = sign was present, and sometimes it was not)
  164. // first test when equal signs are present
  165. $_SERVER['HTTP_HOST'] = 'www.test.com';
  166. $_SERVER['REQUEST_URI'] = '/unit-tests.php?one=&two=&three=';
  167. $current_url = $facebook->publicGetCurrentUrl();
  168. $this->assertEquals(
  169. 'http://www.test.com/unit-tests.php?one=&two=&three=',
  170. $current_url,
  171. 'getCurrentUrl function is changing the current URL');
  172. // now confirm that
  173. $_SERVER['HTTP_HOST'] = 'www.test.com';
  174. $_SERVER['REQUEST_URI'] = '/unit-tests.php?one&two&three';
  175. $current_url = $facebook->publicGetCurrentUrl();
  176. $this->assertEquals(
  177. 'http://www.test.com/unit-tests.php?one&two&three',
  178. $current_url,
  179. 'getCurrentUrl function is changing the current URL');
  180. }
  181. public function testGetLoginURL() {
  182. $facebook = new Facebook(array(
  183. 'appId' => self::APP_ID,
  184. 'secret' => self::SECRET,
  185. ));
  186. // fake the HPHP $_SERVER globals
  187. $_SERVER['HTTP_HOST'] = 'www.test.com';
  188. $_SERVER['REQUEST_URI'] = '/unit-tests.php';
  189. $login_url = parse_url($facebook->getLoginUrl());
  190. $this->assertEquals($login_url['scheme'], 'https');
  191. $this->assertEquals($login_url['host'], 'www.facebook.com');
  192. $this->assertEquals($login_url['path'], '/dialog/oauth');
  193. $expected_login_params =
  194. array('client_id' => self::APP_ID,
  195. 'redirect_uri' => 'http://www.test.com/unit-tests.php');
  196. $query_map = array();
  197. parse_str($login_url['query'], $query_map);
  198. $this->assertIsSubset($expected_login_params, $query_map);
  199. // we don't know what the state is, but we know it's an md5 and should
  200. // be 32 characters long.
  201. $this->assertEquals(strlen($query_map['state']), $num_characters = 32);
  202. }
  203. public function testGetLoginURLWithExtraParams() {
  204. $facebook = new Facebook(array(
  205. 'appId' => self::APP_ID,
  206. 'secret' => self::SECRET,
  207. ));
  208. // fake the HPHP $_SERVER globals
  209. $_SERVER['HTTP_HOST'] = 'www.test.com';
  210. $_SERVER['REQUEST_URI'] = '/unit-tests.php';
  211. $extra_params = array('scope' => 'email, sms',
  212. 'nonsense' => 'nonsense');
  213. $login_url = parse_url($facebook->getLoginUrl($extra_params));
  214. $this->assertEquals($login_url['scheme'], 'https');
  215. $this->assertEquals($login_url['host'], 'www.facebook.com');
  216. $this->assertEquals($login_url['path'], '/dialog/oauth');
  217. $expected_login_params =
  218. array_merge(
  219. array('client_id' => self::APP_ID,
  220. 'redirect_uri' => 'http://www.test.com/unit-tests.php'),
  221. $extra_params);
  222. $query_map = array();
  223. parse_str($login_url['query'], $query_map);
  224. $this->assertIsSubset($expected_login_params, $query_map);
  225. // we don't know what the state is, but we know it's an md5 and should
  226. // be 32 characters long.
  227. $this->assertEquals(strlen($query_map['state']), $num_characters = 32);
  228. }
  229. public function testGetLoginURLWithScopeParamsAsArray() {
  230. $facebook = new Facebook(array(
  231. 'appId' => self::APP_ID,
  232. 'secret' => self::SECRET,
  233. ));
  234. // fake the HPHP $_SERVER globals
  235. $_SERVER['HTTP_HOST'] = 'www.test.com';
  236. $_SERVER['REQUEST_URI'] = '/unit-tests.php';
  237. $scope_params_as_array = array('email','sms','read_stream');
  238. $extra_params = array('scope' => $scope_params_as_array,
  239. 'nonsense' => 'nonsense');
  240. $login_url = parse_url($facebook->getLoginUrl($extra_params));
  241. $this->assertEquals($login_url['scheme'], 'https');
  242. $this->assertEquals($login_url['host'], 'www.facebook.com');
  243. $this->assertEquals($login_url['path'], '/dialog/oauth');
  244. // expect api to flatten array params to comma separated list
  245. // should do the same here before asserting to make sure API is behaving
  246. // correctly;
  247. $extra_params['scope'] = implode(',', $scope_params_as_array);
  248. $expected_login_params =
  249. array_merge(
  250. array('client_id' => self::APP_ID,
  251. 'redirect_uri' => 'http://www.test.com/unit-tests.php'),
  252. $extra_params);
  253. $query_map = array();
  254. parse_str($login_url['query'], $query_map);
  255. $this->assertIsSubset($expected_login_params, $query_map);
  256. // we don't know what the state is, but we know it's an md5 and should
  257. // be 32 characters long.
  258. $this->assertEquals(strlen($query_map['state']), $num_characters = 32);
  259. }
  260. public function testGetCodeWithValidCSRFState() {
  261. $facebook = new FBCode(array(
  262. 'appId' => self::APP_ID,
  263. 'secret' => self::SECRET,
  264. ));
  265. $facebook->setCSRFStateToken();
  266. $code = $_REQUEST['code'] = $this->generateMD5HashOfRandomValue();
  267. $_REQUEST['state'] = $facebook->getCSRFStateToken();
  268. $this->assertEquals($code,
  269. $facebook->publicGetCode(),
  270. 'Expect code to be pulled from $_REQUEST[\'code\']');
  271. }
  272. public function testGetCodeWithInvalidCSRFState() {
  273. $facebook = new FBCode(array(
  274. 'appId' => self::APP_ID,
  275. 'secret' => self::SECRET,
  276. ));
  277. $facebook->setCSRFStateToken();
  278. $code = $_REQUEST['code'] = $this->generateMD5HashOfRandomValue();
  279. $_REQUEST['state'] = $facebook->getCSRFStateToken().'forgery!!!';
  280. $this->assertFalse($facebook->publicGetCode(),
  281. 'Expect getCode to fail, CSRF state should not match.');
  282. }
  283. public function testGetCodeWithMissingCSRFState() {
  284. $facebook = new FBCode(array(
  285. 'appId' => self::APP_ID,
  286. 'secret' => self::SECRET,
  287. ));
  288. $code = $_REQUEST['code'] = $this->generateMD5HashOfRandomValue();
  289. // intentionally don't set CSRF token at all
  290. $this->assertFalse($facebook->publicGetCode(),
  291. 'Expect getCode to fail, CSRF state not sent back.');
  292. }
  293. public function testPersistentCSRFState()
  294. {
  295. $facebook = new FBCode(array(
  296. 'appId' => self::APP_ID,
  297. 'secret' => self::SECRET,
  298. ));
  299. $facebook->setCSRFStateToken();
  300. $code = $facebook->getCSRFStateToken();
  301. $facebook = new FBCode(array(
  302. 'appId' => self::APP_ID,
  303. 'secret' => self::SECRET,
  304. ));
  305. $this->assertEquals($code, $facebook->publicGetState(),
  306. 'Persisted CSRF state token not loaded correctly');
  307. }
  308. public function testPersistentCSRFStateWithSharedSession()
  309. {
  310. $_SERVER['HTTP_HOST'] = 'fbrell.com';
  311. $facebook = new FBCode(array(
  312. 'appId' => self::APP_ID,
  313. 'secret' => self::SECRET,
  314. 'sharedSession' => true,
  315. ));
  316. $facebook->setCSRFStateToken();
  317. $code = $facebook->getCSRFStateToken();
  318. $facebook = new FBCode(array(
  319. 'appId' => self::APP_ID,
  320. 'secret' => self::SECRET,
  321. 'sharedSession' => true,
  322. ));
  323. $this->assertEquals($code, $facebook->publicGetState(),
  324. 'Persisted CSRF state token not loaded correctly with shared session');
  325. }
  326. public function testGetUserFromSignedRequest() {
  327. $facebook = new TransientFacebook(array(
  328. 'appId' => self::APP_ID,
  329. 'secret' => self::SECRET,
  330. ));
  331. $_REQUEST['signed_request'] = self::kValidSignedRequest();
  332. $this->assertEquals('499834690', $facebook->getUser(),
  333. 'Failed to get user ID from a valid signed request.');
  334. }
  335. public function testDisallowSignedRequest() {
  336. $facebook = new TransientFacebook(array(
  337. 'appId' => self::APP_ID,
  338. 'secret' => self::SECRET,
  339. 'allowSignedRequest' => false
  340. ));
  341. $_REQUEST['signed_request'] = self::kValidSignedRequest();
  342. $this->assertEquals(0, $facebook->getUser(),
  343. 'Should not have received valid user from signed_request.');
  344. }
  345. public function testSignedRequestRewrite(){
  346. $facebook = new FBRewrite(array(
  347. 'appId' => self::APP_ID,
  348. 'secret' => self::SECRET,
  349. ));
  350. $_REQUEST['signed_request'] = self::kValidSignedRequest(self::TEST_USER, 'Hello sweetie');
  351. $this->assertEquals(self::TEST_USER, $facebook->getUser(),
  352. 'Failed to get user ID from a valid signed request.');
  353. $this->assertEquals('Hello sweetie', $facebook->getAccessToken(),
  354. 'Failed to get access token from signed request');
  355. $facebook->uncache();
  356. $_REQUEST['signed_request'] = self::kValidSignedRequest(self::TEST_USER_2, 'spoilers');
  357. $this->assertEquals(self::TEST_USER_2, $facebook->getUser(),
  358. 'Failed to get user ID from a valid signed request.');
  359. $_REQUEST['signed_request'] = null;
  360. $facebook ->uncacheSignedRequest();
  361. $this->assertNotEquals('Hello sweetie', $facebook->getAccessToken(),
  362. 'Failed to clear access token');
  363. }
  364. public function testGetSignedRequestFromCookie() {
  365. $facebook = new FBPublicCookie(array(
  366. 'appId' => self::APP_ID,
  367. 'secret' => self::SECRET,
  368. ));
  369. $_COOKIE[$facebook->publicGetSignedRequestCookieName()] =
  370. self::kValidSignedRequest();
  371. $this->assertNotNull($facebook->publicGetSignedRequest());
  372. $this->assertEquals('499834690', $facebook->getUser(),
  373. 'Failed to get user ID from a valid signed request.');
  374. }
  375. public function testGetSignedRequestWithIncorrectSignature() {
  376. $facebook = new FBPublicCookie(array(
  377. 'appId' => self::APP_ID,
  378. 'secret' => self::SECRET,
  379. ));
  380. $_COOKIE[$facebook->publicGetSignedRequestCookieName()] =
  381. self::kSignedRequestWithBogusSignature();
  382. $this->assertNull($facebook->publicGetSignedRequest());
  383. }
  384. public function testNonUserAccessToken() {
  385. $facebook = new FBAccessToken(array(
  386. 'appId' => self::APP_ID,
  387. 'secret' => self::SECRET,
  388. ));
  389. // no cookies, and no request params, so no user or code,
  390. // so no user access token (even with cookie support)
  391. $this->assertEquals($facebook->publicGetApplicationAccessToken(),
  392. $facebook->getAccessToken(),
  393. 'Access token should be that for logged out users.');
  394. }
  395. public function testMissingMetadataCookie() {
  396. $fb = new FBPublicCookie(array(
  397. 'appId' => self::APP_ID,
  398. 'secret' => self::SECRET,
  399. ));
  400. $this->assertEmpty($fb->publicGetMetadataCookie());
  401. }
  402. public function testEmptyMetadataCookie() {
  403. $fb = new FBPublicCookie(array(
  404. 'appId' => self::APP_ID,
  405. 'secret' => self::SECRET,
  406. ));
  407. $_COOKIE[$fb->publicGetMetadataCookieName()] = '';
  408. $this->assertEmpty($fb->publicGetMetadataCookie());
  409. }
  410. public function testMetadataCookie() {
  411. $fb = new FBPublicCookie(array(
  412. 'appId' => self::APP_ID,
  413. 'secret' => self::SECRET,
  414. ));
  415. $key = 'foo';
  416. $val = '42';
  417. $_COOKIE[$fb->publicGetMetadataCookieName()] = "$key=$val";
  418. $this->assertEquals(array($key => $val), $fb->publicGetMetadataCookie());
  419. }
  420. public function testQuotedMetadataCookie() {
  421. $fb = new FBPublicCookie(array(
  422. 'appId' => self::APP_ID,
  423. 'secret' => self::SECRET,
  424. ));
  425. $key = 'foo';
  426. $val = '42';
  427. $_COOKIE[$fb->publicGetMetadataCookieName()] = "\"$key=$val\"";
  428. $this->assertEquals(array($key => $val), $fb->publicGetMetadataCookie());
  429. }
  430. public function testAPIForLoggedOutUsers() {
  431. $facebook = new TransientFacebook(array(
  432. 'appId' => self::APP_ID,
  433. 'secret' => self::SECRET,
  434. ));
  435. $response = $facebook->api(array(
  436. 'method' => 'fql.query',
  437. 'query' => 'SELECT name FROM user WHERE uid=4',
  438. ));
  439. $this->assertEquals(count($response), 1,
  440. 'Expect one row back.');
  441. $this->assertEquals($response[0]['name'], 'Mark Zuckerberg',
  442. 'Expect the name back.');
  443. }
  444. public function testAPIWithBogusAccessToken() {
  445. $facebook = new TransientFacebook(array(
  446. 'appId' => self::APP_ID,
  447. 'secret' => self::SECRET,
  448. ));
  449. $facebook->setAccessToken('this-is-not-really-an-access-token');
  450. // if we don't set an access token and there's no way to
  451. // get one, then the FQL query below works beautifully, handing
  452. // over Zuck's public data. But if you specify a bogus access
  453. // token as I have right here, then the FQL query should fail.
  454. // We could return just Zuck's public data, but that wouldn't
  455. // advertise the issue that the access token is at worst broken
  456. // and at best expired.
  457. try {
  458. $response = $facebook->api(array(
  459. 'method' => 'fql.query',
  460. 'query' => 'SELECT name FROM profile WHERE id=4',
  461. ));
  462. $this->fail('Should not get here.');
  463. } catch(FacebookApiException $e) {
  464. $result = $e->getResult();
  465. $this->assertTrue(is_array($result), 'expect a result object');
  466. $this->assertEquals('190', $result['error_code'], 'expect code');
  467. }
  468. }
  469. public function testAPIGraphPublicData() {
  470. $facebook = new TransientFacebook(array(
  471. 'appId' => self::APP_ID,
  472. 'secret' => self::SECRET,
  473. ));
  474. $response = $facebook->api('/jerry');
  475. $this->assertEquals(
  476. $response['id'], '214707', 'should get expected id.');
  477. }
  478. public function testGraphAPIWithBogusAccessToken() {
  479. $facebook = new TransientFacebook(array(
  480. 'appId' => self::APP_ID,
  481. 'secret' => self::SECRET,
  482. ));
  483. $facebook->setAccessToken('this-is-not-really-an-access-token');
  484. try {
  485. $response = $facebook->api('/me');
  486. $this->fail('Should not get here.');
  487. } catch(FacebookApiException $e) {
  488. // means the server got the access token and didn't like it
  489. $msg = 'OAuthException: Invalid OAuth access token.';
  490. $this->assertEquals($msg, (string) $e,
  491. 'Expect the invalid OAuth token message.');
  492. }
  493. }
  494. public function testGraphAPIWithExpiredAccessToken() {
  495. $facebook = new TransientFacebook(array(
  496. 'appId' => self::APP_ID,
  497. 'secret' => self::SECRET,
  498. ));
  499. $facebook->setAccessToken(self::$kExpiredAccessToken);
  500. try {
  501. $response = $facebook->api('/me');
  502. $this->fail('Should not get here.');
  503. } catch(FacebookApiException $e) {
  504. // means the server got the access token and didn't like it
  505. $error_msg_start = 'OAuthException: Error validating access token:';
  506. $this->assertTrue(strpos((string) $e, $error_msg_start) === 0,
  507. 'Expect the token validation error message.');
  508. }
  509. }
  510. public function testGraphAPIOAuthSpecError() {
  511. $facebook = new TransientFacebook(array(
  512. 'appId' => self::MIGRATED_APP_ID,
  513. 'secret' => self::MIGRATED_SECRET,
  514. ));
  515. try {
  516. $response = $facebook->api('/me', array(
  517. 'client_id' => self::MIGRATED_APP_ID));
  518. $this->fail('Should not get here.');
  519. } catch(FacebookApiException $e) {
  520. // means the server got the access token
  521. $msg = 'invalid_request: An active access token must be used '.
  522. 'to query information about the current user.';
  523. $this->assertEquals($msg, (string) $e,
  524. 'Expect the invalid session message.');
  525. }
  526. }
  527. public function testGraphAPIMethodOAuthSpecError() {
  528. $facebook = new TransientFacebook(array(
  529. 'appId' => self::MIGRATED_APP_ID,
  530. 'secret' => self::MIGRATED_SECRET,
  531. ));
  532. try {
  533. $response = $facebook->api('/daaku.shah', 'DELETE', array(
  534. 'client_id' => self::MIGRATED_APP_ID));
  535. $this->fail('Should not get here.');
  536. } catch(FacebookApiException $e) {
  537. $this->assertEquals(strpos($e, 'invalid_request'), 0);
  538. }
  539. }
  540. public function testCurlFailure() {
  541. $facebook = new TransientFacebook(array(
  542. 'appId' => self::APP_ID,
  543. 'secret' => self::SECRET,
  544. ));
  545. if (!defined('CURLOPT_TIMEOUT_MS')) {
  546. // can't test it if we don't have millisecond timeouts
  547. return;
  548. }
  549. $exception = null;
  550. try {
  551. // we dont expect facebook will ever return in 1ms
  552. Facebook::$CURL_OPTS[CURLOPT_TIMEOUT_MS] = 50;
  553. $facebook->api('/naitik');
  554. } catch(FacebookApiException $e) {
  555. $exception = $e;
  556. }
  557. unset(Facebook::$CURL_OPTS[CURLOPT_TIMEOUT_MS]);
  558. if (!$exception) {
  559. $this->fail('no exception was thrown on timeout.');
  560. }
  561. $code = $exception->getCode();
  562. if ($code != CURLE_OPERATION_TIMEOUTED && $code != CURLE_COULDNT_CONNECT) {
  563. $this->fail("Expected curl error code 7 or 28 but got: $code");
  564. }
  565. $this->assertEquals('CurlException', $exception->getType(), 'expect type');
  566. }
  567. public function testGraphAPIWithOnlyParams() {
  568. $facebook = new TransientFacebook(array(
  569. 'appId' => self::APP_ID,
  570. 'secret' => self::SECRET,
  571. ));
  572. $response = $facebook->api('/jerry');
  573. $this->assertTrue(isset($response['id']),
  574. 'User ID should be public.');
  575. $this->assertTrue(isset($response['name']),
  576. 'User\'s name should be public.');
  577. $this->assertTrue(isset($response['first_name']),
  578. 'User\'s first name should be public.');
  579. $this->assertTrue(isset($response['last_name']),
  580. 'User\'s last name should be public.');
  581. $this->assertFalse(isset($response['work']),
  582. 'User\'s work history should only be available with '.
  583. 'a valid access token.');
  584. $this->assertFalse(isset($response['education']),
  585. 'User\'s education history should only be '.
  586. 'available with a valid access token.');
  587. $this->assertFalse(isset($response['verified']),
  588. 'User\'s verification status should only be '.
  589. 'available with a valid access token.');
  590. }
  591. public function testLoginURLDefaults() {
  592. $_SERVER['HTTP_HOST'] = 'fbrell.com';
  593. $_SERVER['REQUEST_URI'] = '/examples';
  594. $facebook = new TransientFacebook(array(
  595. 'appId' => self::APP_ID,
  596. 'secret' => self::SECRET,
  597. ));
  598. $encodedUrl = rawurlencode('http://fbrell.com/examples');
  599. $this->assertNotNull(strpos($facebook->getLoginUrl(), $encodedUrl),
  600. 'Expect the current url to exist.');
  601. }
  602. public function testLoginURLDefaultsDropStateQueryParam() {
  603. $_SERVER['HTTP_HOST'] = 'fbrell.com';
  604. $_SERVER['REQUEST_URI'] = '/examples?state=xx42xx';
  605. $facebook = new TransientFacebook(array(
  606. 'appId' => self::APP_ID,
  607. 'secret' => self::SECRET,
  608. ));
  609. $expectEncodedUrl = rawurlencode('http://fbrell.com/examples');
  610. $this->assertTrue(strpos($facebook->getLoginUrl(), $expectEncodedUrl) > -1,
  611. 'Expect the current url to exist.');
  612. $this->assertFalse(strpos($facebook->getLoginUrl(), 'xx42xx'),
  613. 'Expect the session param to be dropped.');
  614. }
  615. public function testLoginURLDefaultsDropCodeQueryParam() {
  616. $_SERVER['HTTP_HOST'] = 'fbrell.com';
  617. $_SERVER['REQUEST_URI'] = '/examples?code=xx42xx';
  618. $facebook = new TransientFacebook(array(
  619. 'appId' => self::APP_ID,
  620. 'secret' => self::SECRET,
  621. ));
  622. $expectEncodedUrl = rawurlencode('http://fbrell.com/examples');
  623. $this->assertTrue(strpos($facebook->getLoginUrl(), $expectEncodedUrl) > -1,
  624. 'Expect the current url to exist.');
  625. $this->assertFalse(strpos($facebook->getLoginUrl(), 'xx42xx'),
  626. 'Expect the session param to be dropped.');
  627. }
  628. public function testLoginURLDefaultsDropSignedRequestParamButNotOthers() {
  629. $_SERVER['HTTP_HOST'] = 'fbrell.com';
  630. $_SERVER['REQUEST_URI'] =
  631. '/examples?signed_request=xx42xx&do_not_drop=xx43xx';
  632. $facebook = new TransientFacebook(array(
  633. 'appId' => self::APP_ID,
  634. 'secret' => self::SECRET,
  635. ));
  636. $expectEncodedUrl = rawurlencode('http://fbrell.com/examples');
  637. $this->assertFalse(strpos($facebook->getLoginUrl(), 'xx42xx'),
  638. 'Expect the session param to be dropped.');
  639. $this->assertTrue(strpos($facebook->getLoginUrl(), 'xx43xx') > -1,
  640. 'Expect the do_not_drop param to exist.');
  641. }
  642. public function testLoginURLCustomNext() {
  643. $_SERVER['HTTP_HOST'] = 'fbrell.com';
  644. $_SERVER['REQUEST_URI'] = '/examples';
  645. $facebook = new TransientFacebook(array(
  646. 'appId' => self::APP_ID,
  647. 'secret' => self::SECRET,
  648. ));
  649. $next = 'http://fbrell.com/custom';
  650. $loginUrl = $facebook->getLoginUrl(array(
  651. 'redirect_uri' => $next,
  652. 'cancel_url' => $next
  653. ));
  654. $currentEncodedUrl = rawurlencode('http://fbrell.com/examples');
  655. $expectedEncodedUrl = rawurlencode($next);
  656. $this->assertNotNull(strpos($loginUrl, $expectedEncodedUrl),
  657. 'Expect the custom url to exist.');
  658. $this->assertFalse(strpos($loginUrl, $currentEncodedUrl),
  659. 'Expect the current url to not exist.');
  660. }
  661. public function testLogoutURLDefaults() {
  662. $_SERVER['HTTP_HOST'] = 'fbrell.com';
  663. $_SERVER['REQUEST_URI'] = '/examples';
  664. $facebook = new TransientFacebook(array(
  665. 'appId' => self::APP_ID,
  666. 'secret' => self::SECRET,
  667. ));
  668. $encodedUrl = rawurlencode('http://fbrell.com/examples');
  669. $this->assertNotNull(strpos($facebook->getLogoutUrl(), $encodedUrl),
  670. 'Expect the current url to exist.');
  671. $this->assertFalse(strpos($facebook->getLogoutUrl(), self::SECRET));
  672. }
  673. public function testLoginStatusURLDefaults() {
  674. $_SERVER['HTTP_HOST'] = 'fbrell.com';
  675. $_SERVER['REQUEST_URI'] = '/examples';
  676. $facebook = new TransientFacebook(array(
  677. 'appId' => self::APP_ID,
  678. 'secret' => self::SECRET,
  679. ));
  680. $encodedUrl = rawurlencode('http://fbrell.com/examples');
  681. $this->assertNotNull(strpos($facebook->getLoginStatusUrl(), $encodedUrl),
  682. 'Expect the current url to exist.');
  683. }
  684. public function testLoginStatusURLCustom() {
  685. $_SERVER['HTTP_HOST'] = 'fbrell.com';
  686. $_SERVER['REQUEST_URI'] = '/examples';
  687. $facebook = new TransientFacebook(array(
  688. 'appId' => self::APP_ID,
  689. 'secret' => self::SECRET,
  690. ));
  691. $encodedUrl1 = rawurlencode('http://fbrell.com/examples');
  692. $okUrl = 'http://fbrell.com/here1';
  693. $encodedUrl2 = rawurlencode($okUrl);
  694. $loginStatusUrl = $facebook->getLoginStatusUrl(array(
  695. 'ok_session' => $okUrl,
  696. ));
  697. $this->assertNotNull(strpos($loginStatusUrl, $encodedUrl1),
  698. 'Expect the current url to exist.');
  699. $this->assertNotNull(strpos($loginStatusUrl, $encodedUrl2),
  700. 'Expect the custom url to exist.');
  701. }
  702. public function testNonDefaultPort() {
  703. $_SERVER['HTTP_HOST'] = 'fbrell.com:8080';
  704. $_SERVER['REQUEST_URI'] = '/examples';
  705. $facebook = new TransientFacebook(array(
  706. 'appId' => self::APP_ID,
  707. 'secret' => self::SECRET,
  708. ));
  709. $encodedUrl = rawurlencode('http://fbrell.com:8080/examples');
  710. $this->assertNotNull(strpos($facebook->getLoginUrl(), $encodedUrl),
  711. 'Expect the current url to exist.');
  712. }
  713. public function testSecureCurrentUrl() {
  714. $_SERVER['HTTP_HOST'] = 'fbrell.com';
  715. $_SERVER['REQUEST_URI'] = '/examples';
  716. $_SERVER['HTTPS'] = 'on';
  717. $facebook = new TransientFacebook(array(
  718. 'appId' => self::APP_ID,
  719. 'secret' => self::SECRET,
  720. ));
  721. $encodedUrl = rawurlencode('https://fbrell.com/examples');
  722. $this->assertNotNull(strpos($facebook->getLoginUrl(), $encodedUrl),
  723. 'Expect the current url to exist.');
  724. }
  725. public function testSecureCurrentUrlWithNonDefaultPort() {
  726. $_SERVER['HTTP_HOST'] = 'fbrell.com:8080';
  727. $_SERVER['REQUEST_URI'] = '/examples';
  728. $_SERVER['HTTPS'] = 'on';
  729. $facebook = new TransientFacebook(array(
  730. 'appId' => self::APP_ID,
  731. 'secret' => self::SECRET,
  732. ));
  733. $encodedUrl = rawurlencode('https://fbrell.com:8080/examples');
  734. $this->assertNotNull(strpos($facebook->getLoginUrl(), $encodedUrl),
  735. 'Expect the current url to exist.');
  736. }
  737. public function testBase64UrlEncode() {
  738. $input = 'Facebook rocks';
  739. $output = 'RmFjZWJvb2sgcm9ja3M';
  740. $this->assertEquals(FBPublic::publicBase64UrlDecode($output), $input);
  741. }
  742. public function testSignedToken() {
  743. $facebook = new FBPublic(array(
  744. 'appId' => self::APP_ID,
  745. 'secret' => self::SECRET
  746. ));
  747. $sr = self::kValidSignedRequest();
  748. $payload = $facebook->publicParseSignedRequest($sr);
  749. $this->assertNotNull($payload, 'Expected token to parse');
  750. $this->assertEquals($facebook->getSignedRequest(), null);
  751. $_REQUEST['signed_request'] = $sr;
  752. $this->assertEquals($facebook->getSignedRequest(), $payload);
  753. }
  754. public function testNonTossedSignedtoken() {
  755. $facebook = new FBPublic(array(
  756. 'appId' => self::APP_ID,
  757. 'secret' => self::SECRET
  758. ));
  759. $payload = $facebook->publicParseSignedRequest(
  760. self::kNonTosedSignedRequest());
  761. $this->assertNotNull($payload, 'Expected token to parse');
  762. $this->assertNull($facebook->getSignedRequest());
  763. $_REQUEST['signed_request'] = self::kNonTosedSignedRequest();
  764. $sr = $facebook->getSignedRequest();
  765. $this->assertTrue(isset($sr['algorithm']));
  766. }
  767. public function testSignedRequestWithEmptyValue() {
  768. $fb = new FBPublicCookie(array(
  769. 'appId' => self::APP_ID,
  770. 'secret' => self::SECRET
  771. ));
  772. $_REQUEST['signed_request'] = self::kSignedRequestWithEmptyValue();
  773. $this->assertNull($fb->getSignedRequest());
  774. $_COOKIE[$fb->publicGetSignedRequestCookieName()] =
  775. self::kSignedRequestWithEmptyValue();
  776. $this->assertNull($fb->getSignedRequest());
  777. }
  778. public function testSignedRequestWithWrongAlgo() {
  779. $fb = new FBPublic(array(
  780. 'appId' => self::APP_ID,
  781. 'secret' => self::SECRET
  782. ));
  783. $payload = $fb->publicParseSignedRequest(
  784. self::kSignedRequestWithWrongAlgo());
  785. $this->assertNull($payload, 'Expected nothing back.');
  786. }
  787. public function testMakeAndParse() {
  788. $fb = new FBPublic(array(
  789. 'appId' => self::APP_ID,
  790. 'secret' => self::SECRET
  791. ));
  792. $data = array('foo' => 42);
  793. $sr = $fb->publicMakeSignedRequest($data);
  794. $decoded = $fb->publicParseSignedRequest($sr);
  795. $this->assertEquals($data['foo'], $decoded['foo']);
  796. }
  797. /**
  798. * @expectedException InvalidArgumentException
  799. */
  800. public function testMakeSignedRequestExpectsArray() {
  801. $fb = new FBPublic(array(
  802. 'appId' => self::APP_ID,
  803. 'secret' => self::SECRET
  804. ));
  805. $sr = $fb->publicMakeSignedRequest('');
  806. }
  807. public function testBundledCACert() {
  808. $facebook = new TransientFacebook(array(
  809. 'appId' => self::APP_ID,
  810. 'secret' => self::SECRET
  811. ));
  812. // use the bundled cert from the start
  813. Facebook::$CURL_OPTS[CURLOPT_CAINFO] =
  814. dirname(__FILE__) . '/../src/fb_ca_chain_bundle.crt';
  815. $response = $facebook->api('/naitik');
  816. unset(Facebook::$CURL_OPTS[CURLOPT_CAINFO]);
  817. $this->assertEquals(
  818. $response['id'], '5526183', 'should get expected id.');
  819. }
  820. public function testVideoUpload() {
  821. $facebook = new FBRecordURL(array(
  822. 'appId' => self::APP_ID,
  823. 'secret' => self::SECRET
  824. ));
  825. $facebook->api(array('method' => 'video.upload'));
  826. $this->assertContains('//api-video.', $facebook->getRequestedURL(),
  827. 'video.upload should go against api-video');
  828. }
  829. public function testVideoUploadGraph() {
  830. $facebook = new FBRecordURL(array(
  831. 'appId' => self::APP_ID,
  832. 'secret' => self::SECRET
  833. ));
  834. $facebook->api('/me/videos', 'POST');
  835. $this->assertContains('//graph-video.', $facebook->getRequestedURL(),
  836. '/me/videos should go against graph-video');
  837. }
  838. public function testGetUserAndAccessTokenFromSession() {
  839. $facebook = new PersistentFBPublic(array(
  840. 'appId' => self::APP_ID,
  841. 'secret' => self::SECRET
  842. ));
  843. $facebook->publicSetPersistentData('access_token',
  844. self::$kExpiredAccessToken);
  845. $facebook->publicSetPersistentData('user_id', 12345);
  846. $this->assertEquals(self::$kExpiredAccessToken,
  847. $facebook->getAccessToken(),
  848. 'Get access token from persistent store.');
  849. $this->assertEquals('12345',
  850. $facebook->getUser(),
  851. 'Get user id from persistent store.');
  852. }
  853. public function testGetUserAndAccessTokenFromSignedRequestNotSession() {
  854. $facebook = new PersistentFBPublic(array(
  855. 'appId' => self::APP_ID,
  856. 'secret' => self::SECRET
  857. ));
  858. $_REQUEST['signed_request'] = self::kValidSignedRequest();
  859. $facebook->publicSetPersistentData('user_id', 41572);
  860. $facebook->publicSetPersistentData('access_token',
  861. self::$kExpiredAccessToken);
  862. $this->assertNotEquals('41572', $facebook->getUser(),
  863. 'Got user from session instead of signed request.');
  864. $this->assertEquals('499834690', $facebook->getUser(),
  865. 'Failed to get correct user ID from signed request.');
  866. $this->assertNotEquals(
  867. self::$kExpiredAccessToken,
  868. $facebook->getAccessToken(),
  869. 'Got access token from session instead of signed request.');
  870. $this->assertNotEmpty(
  871. $facebook->getAccessToken(),
  872. 'Failed to extract an access token from the signed request.');
  873. }
  874. public function testGetUserWithoutCodeOrSignedRequestOrSession() {
  875. $facebook = new PersistentFBPublic(array(
  876. 'appId' => self::APP_ID,
  877. 'secret' => self::SECRET
  878. ));
  879. // deliberately leave $_REQUEST and _$SESSION empty
  880. $this->assertEmpty($_REQUEST,
  881. 'GET, POST, and COOKIE params exist even though '.
  882. 'they should. Test cannot succeed unless all of '.
  883. '$_REQUEST is empty.');
  884. $this->assertEmpty($_SESSION,
  885. 'Session is carrying state and should not be.');
  886. $this->assertEmpty($facebook->getUser(),
  887. 'Got a user id, even without a signed request, '.
  888. 'access token, or session variable.');
  889. $this->assertEmpty($_SESSION,
  890. 'Session superglobal incorrectly populated by getUser.');
  891. }
  892. public function testGetAccessTokenUsingCodeInJsSdkCookie() {
  893. $code = 'code1';
  894. $access_token = 'at1';
  895. $methods_to_stub = array('getSignedRequest', 'getAccessTokenFromCode');
  896. $constructor_args = array(array(
  897. 'appId' => self::APP_ID,
  898. 'secret' => self::SECRET
  899. ));
  900. $stub = $this->getMock(
  901. 'TransientFacebook', $methods_to_stub, $constructor_args);
  902. $stub
  903. ->expects($this->once())
  904. ->method('getSignedRequest')
  905. ->will($this->returnValue(array('code' => $code)));
  906. $stub
  907. ->expects($this->once())
  908. ->method('getAccessTokenFromCode')
  909. ->will($this->returnValueMap(array(array($code, '', $access_token))));
  910. $this->assertEquals($stub->getAccessToken(), $access_token);
  911. }
  912. public function testSignedRequestWithoutAuthClearsData() {
  913. $methods_to_stub = array('getSignedRequest', 'clearAllPersistentData');
  914. $constructor_args = array(array(
  915. 'appId' => self::APP_ID,
  916. 'secret' => self::SECRET
  917. ));
  918. $stub = $this->getMock(
  919. 'TransientFacebook', $methods_to_stub, $constructor_args);
  920. $stub
  921. ->expects($this->once())
  922. ->method('getSignedRequest')
  923. ->will($this->returnValue(array('foo' => 1)));
  924. $stub
  925. ->expects($this->once())
  926. ->method('clearAllPersistentData');
  927. $this->assertEquals(self::APP_ID.'|'.self::SECRET, $stub->getAccessToken());
  928. }
  929. public function testInvalidCodeInSignedRequestWillClearData() {
  930. $code = 'code1';
  931. $methods_to_stub = array(
  932. 'getSignedRequest',
  933. 'getAccessTokenFromCode',
  934. 'clearAllPersistentData',
  935. );
  936. $constructor_args = array(array(
  937. 'appId' => self::APP_ID,
  938. 'secret' => self::SECRET
  939. ));
  940. $stub = $this->getMock(
  941. 'TransientFacebook', $methods_to_stub, $constructor_args);
  942. $stub
  943. ->expects($this->once())
  944. ->method('getSignedRequest')
  945. ->will($this->returnValue(array('code' => $code)));
  946. $stub
  947. ->expects($this->once())
  948. ->method('getAccessTokenFromCode')
  949. ->will($this->returnValue(null));
  950. $stub
  951. ->expects($this->once())
  952. ->method('clearAllPersistentData');
  953. $this->assertEquals(self::APP_ID.'|'.self::SECRET, $stub->getAccessToken());
  954. }
  955. public function testInvalidCodeWillClearData() {
  956. $code = 'code1';
  957. $methods_to_stub = array(
  958. 'getCode',
  959. 'getAccessTokenFromCode',
  960. 'clearAllPersistentData',
  961. );
  962. $constructor_args = array(array(
  963. 'appId' => self::APP_ID,
  964. 'secret' => self::SECRET
  965. ));
  966. $stub = $this->getMock(
  967. 'TransientFacebook', $methods_to_stub, $constructor_args);
  968. $stub
  969. ->expects($this->once())
  970. ->method('getCode')
  971. ->will($this->returnValue($code));
  972. $stub
  973. ->expects($this->once())
  974. ->method('getAccessTokenFromCode')
  975. ->will($this->returnValue(null));
  976. $stub
  977. ->expects($this->once())
  978. ->method('clearAllPersistentData');
  979. $this->assertEquals(self::APP_ID.'|'.self::SECRET, $stub->getAccessToken());
  980. }
  981. public function testValidCodeToToken() {
  982. $code = 'code1';
  983. $access_token = 'at1';
  984. $methods_to_stub = array(
  985. 'getSignedRequest',
  986. 'getCode',
  987. 'getAccessTokenFromCode',
  988. );
  989. $constructor_args = array(array(
  990. 'appId' => self::APP_ID,
  991. 'secret' => self::SECRET
  992. ));
  993. $stub = $this->getMock(
  994. 'TransientFacebook', $methods_to_stub, $constructor_args);
  995. $stub
  996. ->expects($this->once())
  997. ->method('getCode')
  998. ->will($this->returnValue($code));
  999. $stub
  1000. ->expects($this->once())
  1001. ->method('getAccessTokenFromCode')
  1002. ->will($this->returnValueMap(array(array($code, null, $access_token))));
  1003. $this->assertEquals($stub->getAccessToken(), $access_token);
  1004. }
  1005. public function testSignedRequestWithoutAuthClearsDataInAvailData() {
  1006. $methods_to_stub = array('getSignedRequest', 'clearAllPersistentData');
  1007. $constructor_args = array(array(
  1008. 'appId' => self::APP_ID,
  1009. 'secret' => self::SECRET
  1010. ));
  1011. $stub = $this->getMock(
  1012. 'TransientFacebook', $methods_to_stub, $constructor_args);
  1013. $stub
  1014. ->expects($this->once())
  1015. ->method('getSignedRequest')
  1016. ->will($this->returnValue(array('foo' => 1)));
  1017. $stub
  1018. ->expects($this->once())
  1019. ->method('clearAllPersistentData');
  1020. $this->assertEquals(0, $stub->getUser());
  1021. }
  1022. public function testFailedToGetUserFromAccessTokenClearsData() {
  1023. $methods_to_stub = array(
  1024. 'getAccessToken',
  1025. 'getUserFromAccessToken',
  1026. 'clearAllPersistentData',
  1027. );
  1028. $constructor_args = array(array(
  1029. 'appId' => self::APP_ID,
  1030. 'secret' => self::SECRET
  1031. ));
  1032. $stub = $this->getMock(
  1033. 'TransientFacebook', $methods_to_stub, $constructor_args);
  1034. $stub
  1035. ->expects($this->once())
  1036. ->method('getAccessToken')
  1037. ->will($this->returnValue('at1'));
  1038. $stub
  1039. ->expects($this->once())
  1040. ->method('getUserFromAccessToken');
  1041. $stub
  1042. ->expects($this->once())
  1043. ->method('clearAllPersistentData');
  1044. $this->assertEquals(0, $stub->getUser());
  1045. }
  1046. public function testUserFromAccessTokenIsStored() {
  1047. $methods_to_stub = array(
  1048. 'getAccessToken',
  1049. 'getUserFromAccessToken',
  1050. 'setPersistentData',
  1051. );
  1052. $constructor_args = array(array(
  1053. 'appId' => self::APP_ID,
  1054. 'secret' => self::SECRET
  1055. ));
  1056. $user = 42;
  1057. $stub = $this->getMock(
  1058. 'TransientFacebook', $methods_to_stub, $constructor_args);
  1059. $stub
  1060. ->expects($this->once())
  1061. ->method('getAccessToken')
  1062. ->will($this->returnValue('at1'));
  1063. $stub
  1064. ->expects($this->once())
  1065. ->method('getUserFromAccessToken')
  1066. ->will($this->returnValue($user));
  1067. $stub
  1068. ->expects($this->once())
  1069. ->method('setPersistentData');
  1070. $this->assertEquals($user, $stub->getUser());
  1071. }
  1072. public function testUserFromAccessTokenPullsID() {
  1073. $methods_to_stub = array(
  1074. 'getAccessToken',
  1075. 'api',
  1076. );
  1077. $constructor_args = array(array(
  1078. 'appId' => self::APP_ID,
  1079. 'secret' => self::SECRET
  1080. ));
  1081. $user = 42;
  1082. $stub = $this->getMock(
  1083. 'TransientFacebook', $methods_to_stub, $constructor_args);
  1084. $stub
  1085. ->expects($this->once())
  1086. ->method('getAccessToken')
  1087. ->will($this->returnValue('at1'));
  1088. $stub
  1089. ->expects($this->once())
  1090. ->method('api')
  1091. ->will($this->returnValue(array('id' => $user)));
  1092. $this->assertEquals($user, $stub->getUser());
  1093. }
  1094. public function testUserFromAccessTokenResetsOnApiException() {
  1095. $methods_to_stub = array(
  1096. 'getAccessToken',
  1097. 'clearAllPersistentData',
  1098. 'api',
  1099. );
  1100. $constructor_args = array(array(
  1101. 'appId' => self::APP_ID,
  1102. 'secret' => self::SECRET
  1103. ));
  1104. $stub = $this->getMock(
  1105. 'TransientFacebook', $methods_to_stub, $constructor_args);
  1106. $stub
  1107. ->expects($this->once())
  1108. ->method('getAccessToken')
  1109. ->will($this->returnValue('at1'));
  1110. $stub
  1111. ->expects($this->once())
  1112. ->method('api')
  1113. ->will($this->throwException(new FacebookApiException(false)));
  1114. $stub
  1115. ->expects($this->once())
  1116. ->method('clearAllPersistentData');
  1117. $this->assertEquals(0, $stub->getUser());
  1118. }
  1119. public function testEmptyCodeReturnsFalse() {
  1120. $fb = new FBPublicGetAccessTokenFromCode(array(
  1121. 'appId' => self::APP_ID,
  1122. 'secret' => self::SECRET
  1123. ));
  1124. $this->assertFalse($fb->publicGetAccessTokenFromCode(''));
  1125. $this->assertFalse($fb->publicGetAccessTokenFromCode(null));
  1126. $this->assertFalse($fb->publicGetAccessTokenFromCode(false));
  1127. }
  1128. public function testNullRedirectURIUsesCurrentURL() {
  1129. $methods_to_stub = array(
  1130. '_oauthRequest',
  1131. 'getCurrentUrl',
  1132. );
  1133. $constructor_args = array(array(
  1134. 'appId' => self::APP_ID,
  1135. 'secret' => self::SECRET
  1136. ));
  1137. $access_token = 'at1';
  1138. $stub = $this->getMock(
  1139. 'FBPublicGetAccessTokenFromCode', $methods_to_stub, $constructor_args);
  1140. $stub
  1141. ->expects($this->once())
  1142. ->method('_oauthRequest')
  1143. ->will($this->returnValue("access_token=$access_token"));
  1144. $stub
  1145. ->expects($this->once())
  1146. ->method('getCurrentUrl');
  1147. $this->assertEquals(
  1148. $access_token, $stub->publicGetAccessTokenFromCode('c'));
  1149. }
  1150. public function testNullRedirectURIAllowsEmptyStringForCookie() {
  1151. $methods_to_stub = array(
  1152. '_oauthRequest',
  1153. 'getCurrentUrl',
  1154. );
  1155. $constructor_args = array(array(
  1156. 'appId' => self::APP_ID,
  1157. 'secret' => self::SECRET
  1158. ));
  1159. $access_token = 'at1';
  1160. $stub = $this->getMock(
  1161. 'FBPublicGetAccessTokenFromCode', $methods_to_stub, $constructor_args);
  1162. $stub
  1163. ->expects($this->once())
  1164. ->method('_oauthRequest')
  1165. ->will($this->returnValue("access_token=$access_token"));
  1166. $stub
  1167. ->expects($this->never())
  1168. ->method('getCurrentUrl');
  1169. $this->assertEquals(
  1170. $access_token, $stub->publicGetAccessTokenFromCode('c', ''));
  1171. }
  1172. public function testAPIExceptionDuringCodeExchangeIsIgnored() {
  1173. $methods_to_stub = array(
  1174. '_oauthRequest',
  1175. );
  1176. $constructor_args = array(array(
  1177. 'appId' => self::APP_ID,
  1178. 'secret' => self::SECRET
  1179. ));
  1180. $stub = $this->getMock(
  1181. 'FBPublicGetAccessTokenFromCode', $methods_to_stub, $constructor_args);
  1182. $stub
  1183. ->expects($this->once())
  1184. ->method('_oauthRequest')
  1185. ->will($this->throwException(new FacebookApiException(false)));
  1186. $this->assertFalse($stub->publicGetAccessTokenFromCode('c', ''));
  1187. }
  1188. public function testEmptyResponseInCodeExchangeIsIgnored() {
  1189. $methods_to_stub = array(
  1190. '_oauthRequest',
  1191. );
  1192. $constructor_args = array(array(
  1193. 'appId' => self::APP_ID,
  1194. 'secret' => self::SECRET
  1195. ));
  1196. $stub = $this->getMock(
  1197. 'FBPublicGetAccessTokenFromCode', $methods_to_stub, $constructor_args);
  1198. $stub
  1199. ->expects($this->once())
  1200. ->method('_oauthRequest')
  1201. ->will($this->returnValue(''));
  1202. $this->assertFalse($stub->publicGetAccessTokenFromCode('c', ''));
  1203. }
  1204. public function testExistingStateRestoredInConstructor() {
  1205. $fb = new FBPublicState(array(
  1206. 'appId' => self::APP_ID,
  1207. 'secret' => self::SECRET
  1208. ));
  1209. $this->assertEquals(FBPublicState::STATE, $fb->publicGetState());
  1210. }
  1211. public function testMissingAccessTokenInCodeExchangeIsIgnored() {
  1212. $methods_to_stub = array(
  1213. '_oauthRequest',
  1214. );
  1215. $constructor_args = array(array(
  1216. 'appId' => self::APP_ID,
  1217. 'secret' => self::SECRET
  1218. ));
  1219. $stub = $this->getMock(
  1220. 'FBPublicGetAccessTokenFromCode', $methods_to_stub, $constructor_args);
  1221. $stub
  1222. ->expects($this->once())
  1223. ->method('_oauthRequest')
  1224. ->will($this->returnValue('foo=1'));
  1225. $this->assertFalse($stub->publicGetAccessTokenFromCode('c', ''));
  1226. }
  1227. public function testAppsecretProofNoParams() {
  1228. $fb = new FBRecordMakeRequest(array(
  1229. 'appId' => self::APP_ID,
  1230. 'secret' => self::SECRET,
  1231. ));
  1232. $token = $fb->getAccessToken();
  1233. $proof = $fb->publicGetAppSecretProof($token);
  1234. $params = array();
  1235. $fb->api('/mattynoce', $params);
  1236. $requests = $fb->publicGetRequests();
  1237. $this->assertEquals($proof, $requests[0]['params']['appsecret_proof']);
  1238. }
  1239. public function testAppsecretProofWithParams() {
  1240. $fb = new FBRecordMakeRequest(array(
  1241. 'appId' => self::APP_ID,
  1242. 'secret' => self::SECRET,
  1243. ));
  1244. $proof = 'foo';
  1245. $params = array('appsecret_proof' => $proof);
  1246. $fb->api('/mattynoce', $params);
  1247. $requests = $fb->publicGetRequests();
  1248. $this->assertEquals($proof, $requests[0]['params']['appsecret_proof']);
  1249. }
  1250. public function testExceptionConstructorWithErrorCode() {
  1251. $code = 404;
  1252. $e = new FacebookApiException(array('error_code' => $code));
  1253. $this->assertEquals($code, $e->getCode());
  1254. }
  1255. public function testExceptionConstructorWithInvalidErrorCode() {
  1256. $e = new FacebookApiException(array('error_code' => 'not an int'));
  1257. $this->assertEquals(0, $e->getCode());
  1258. }
  1259. // this happens often despite the fact that it is useless
  1260. public function testExceptionTypeFalse() {
  1261. $e = new FacebookApiException(false);
  1262. $this->assertEquals('Exception', $e->getType());
  1263. }
  1264. public function testExceptionTypeMixedDraft00() {
  1265. $e = new FacebookApiException(array('error' => array('message' => 'foo')));
  1266. $this->assertEquals('Exception', $e->getType());
  1267. }
  1268. public function testExceptionTypeDraft00() {
  1269. $error = 'foo';
  1270. $e = new FacebookApiException(
  1271. array('error' => array('type' => $error, 'message' => 'hello world')));
  1272. $this->assertEquals($error, $e->getType());
  1273. }
  1274. public function testExceptionTypeDraft10() {
  1275. $error = 'foo';
  1276. $e = new FacebookApiException(array('error' => $error));
  1277. $this->assertEquals($error, $e->getType());
  1278. }
  1279. public function testExceptionTypeDefault() {
  1280. $e = new FacebookApiException(array('error' => false));
  1281. $this->assertEquals('Exception', $e->getType());
  1282. }
  1283. public function testExceptionToString() {
  1284. $e = new FacebookApiException(array(
  1285. 'error_code' => 1,
  1286. 'error_description' => 'foo',
  1287. ));
  1288. $this->assertEquals('Exception: 1: foo', (string) $e);
  1289. }
  1290. public function testDestroyClearsCookie() {
  1291. $fb = new FBPublicCookie(array(
  1292. 'appId' => self::APP_ID,
  1293. 'secret' => self::SECRET,
  1294. ));
  1295. $_COOKIE[$fb->publicGetSignedRequestCookieName()] = 'foo';
  1296. $_COOKIE[$fb->publicGetMetadataCookieName()] = 'base_domain=fbrell.com';
  1297. $_SERVER['HTTP_HOST'] = 'fbrell.com';
  1298. $fb->destroySession();
  1299. $this->assertFalse(
  1300. array_key_exists($fb->publicGetSignedRequestCookieName(), $_COOKIE));
  1301. }
  1302. public function testAuthExpireSessionDestroysSession() {
  1303. $methods_to_stub = array(
  1304. '_oauthRequest',
  1305. 'destroySession',
  1306. );
  1307. $constructor_args = array(array(
  1308. 'appId' => self::APP_ID,
  1309. 'secret' => self::SECRET
  1310. ));
  1311. $key = 'foo';
  1312. $val = 42;
  1313. $stub = $this->getMock(
  1314. 'TransientFacebook', $methods_to_stub, $constructor_args);
  1315. $stub
  1316. ->expects($this->once())
  1317. ->method('_oauthRequest')
  1318. ->will($this->returnValue("{\"$key\":$val}"));
  1319. $stub
  1320. ->expects($this->once())
  1321. ->method('destroySession');
  1322. $this->assertEquals(
  1323. array($key => $val),
  1324. $stub->api(array('method' => 'auth.expireSession'))
  1325. );
  1326. }
  1327. public function testLowercaseAuthRevokeAuthDestroysSession() {
  1328. $methods_to_stub = array(
  1329. '_oauthRequest',
  1330. 'destroySession',
  1331. );
  1332. $constructor_args = array(array(
  1333. 'appId' => self::APP_ID,
  1334. 'secret' => self::SECRET
  1335. ));
  1336. $key = 'foo';
  1337. $val = 42;
  1338. $stub = $this->getMock(
  1339. 'TransientFacebook', $methods_to_stub, $constructor_args);
  1340. $stub
  1341. ->expects($this->once())
  1342. ->method('_oauthRequest')
  1343. ->will($this->returnValue("{\"$key\":$val}"));
  1344. $stub
  1345. ->expects($this->once())
  1346. ->method('destroySession');
  1347. $this->assertEquals(
  1348. array($key => $val),
  1349. $stub->api(array('method' => 'auth.revokeauthorization'))
  1350. );
  1351. }
  1352. /**
  1353. * @expectedException FacebookAPIException
  1354. */
  1355. public function testErrorCodeFromRestAPIThrowsException() {
  1356. $methods_to_stub = array(
  1357. '_oauthRequest',
  1358. );
  1359. $constructor_args = array(array(
  1360. 'appId' => self::APP_ID,
  1361. 'secret' => self::SECRET
  1362. ));
  1363. $stub = $this->getMock(
  1364. 'TransientFacebook', $methods_to_stub, $constructor_args);
  1365. $stub
  1366. ->expects($this->once())
  1367. ->method('_oauthRequest')
  1368. ->will($this->returnValue('{"error_code": 500}'));
  1369. $stub->api(array('method' => 'foo'));
  1370. }
  1371. public function testJsonEncodeOfNonStringParams() {
  1372. $foo = array(1, 2);
  1373. $params = array(
  1374. 'method' => 'get',
  1375. 'foo' => $foo,
  1376. );
  1377. $fb = new FBRecordMakeRequest(array(
  1378. 'appId' => self::APP_ID,
  1379. 'secret' => self::SECRET,
  1380. ));
  1381. $fb->api('/naitik', $params);
  1382. $requests = $fb->publicGetRequests();
  1383. $this->assertEquals(json_encode($foo), $requests[0]['params']['foo']);
  1384. }
  1385. public function testSessionBackedFacebook() {
  1386. $fb = new PersistentFBPublic(array(
  1387. 'appId' => self::APP_ID,
  1388. 'secret' => self::SECRET,
  1389. ));
  1390. $key = 'state';
  1391. $val = 'foo';
  1392. $fb->publicSetPersistentData($key, $val);
  1393. $this->assertEquals(
  1394. $val,
  1395. $_SESSION[sprintf('fb_%s_%s', self::APP_ID, $key)]
  1396. );
  1397. $this->assertEquals(
  1398. $val,
  1399. $fb->publicGetPersistentData($key)
  1400. );
  1401. }
  1402. public function testSessionBackedFacebookIgnoresUnsupportedKey() {
  1403. $fb = new PersistentFBPublic(array(
  1404. 'appId' => self::APP_ID,
  1405. 'secret' => self::SECRET,
  1406. ));
  1407. $key = '--invalid--';
  1408. $val = 'foo';
  1409. $fb->publicSetPersistentData($key, $val);
  1410. $this->assertFalse(
  1411. array_key_exists(
  1412. sprintf('fb_%s_%s', self::APP_ID, $key),
  1413. $_SESSION
  1414. )
  1415. );
  1416. $this->assertFalse($fb->publicGetPersistentData($key));
  1417. }
  1418. public function testClearSessionBackedFacebook() {
  1419. $fb = new PersistentFBPublic(array(
  1420. 'appId' => self::APP_ID,
  1421. 'secret' => self::SECRET,
  1422. ));
  1423. $key = 'state';
  1424. $val = 'foo';
  1425. $fb->publicSetPersistentData($key, $val);
  1426. $this->assertEquals(
  1427. $val,
  1428. $_SESSION[sprintf('fb_%s_%s', self::APP_ID, $key)]
  1429. );
  1430. $this->assertEquals(
  1431. $val,
  1432. $fb->publicGetPersistentData($key)
  1433. );
  1434. $fb->publicClearPersistentData($key);
  1435. $this->assertFalse(
  1436. array_key_exists(
  1437. sprintf('fb_%s_%s', self::APP_ID, $key),
  1438. $_SESSION
  1439. )
  1440. );
  1441. $this->assertFalse($fb->publicGetPersistentData($key));
  1442. }
  1443. public function testSessionBackedFacebookIgnoresUnsupportedKeyInClear() {
  1444. $fb = new PersistentFBPublic(array(
  1445. 'appId' => self::APP_ID,
  1446. 'secret' => self::SECRET,
  1447. ));
  1448. $key = '--invalid--';
  1449. $val = 'foo';
  1450. $session_var_name = sprintf('fb_%s_%s', self::APP_ID, $key);
  1451. $_SESSION[$session_var_name] = $val;
  1452. $fb->publicClearPersistentData($key);
  1453. $this->assertTrue(array_key_exists($session_var_name, $_SESSION));
  1454. $this->assertFalse($fb->publicGetPersistentData($key));
  1455. }
  1456. public function testClearAllSessionBackedFacebook() {
  1457. $fb = new PersistentFBPublic(array(
  1458. 'appId' => self::APP_ID,
  1459. 'secret' => self::SECRET,
  1460. ));
  1461. $key = 'state';
  1462. $val = 'foo';
  1463. $session_var_name = sprintf('fb_%s_%s', self::APP_ID, $key);
  1464. $fb->publicSetPersistentData($key, $val);
  1465. $this->assertEquals($val, $_SESSION[$session_var_name]);
  1466. $this->assertEquals($val, $fb->publicGetPersistentData($key));
  1467. $fb->publicClearAllPersistentData();
  1468. $this->assertFalse(array_key_exists($session_var_name, $_SESSION));
  1469. $this->assertFalse($fb->publicGetPersistentData($key));
  1470. }
  1471. public function testSharedSessionBackedFacebook() {
  1472. $_SERVER['HTTP_HOST'] = 'fbrell.com';
  1473. $fb = new PersistentFBPublic(array(
  1474. 'appId' => self::APP_ID,
  1475. 'secret' => self::SECRET,
  1476. 'sharedSession' => true,
  1477. ));
  1478. $key = 'state';
  1479. $val = 'foo';
  1480. $session_var_name = sprintf(
  1481. '%s_fb_%s_%s',
  1482. $fb->publicGetSharedSessionID(),
  1483. self::APP_ID,
  1484. $key
  1485. );
  1486. $fb->publicSetPersistentData($key, $val);
  1487. $this->assertEquals($val, $_SESSION[$session_var_name]);
  1488. $this->assertEquals($val, $fb->publicGetPersistentData($key));
  1489. }
  1490. public function testSharedSessionBackedFacebookIgnoresUnsupportedKey() {
  1491. $_SERVER['HTTP_HOST'] = 'fbrell.com';
  1492. $fb = new PersistentFBPublic(array(
  1493. 'appId' => self::APP_ID,
  1494. 'secret' => self::SECRET,
  1495. 'sharedSession' => true,
  1496. ));
  1497. $key = '--invalid--';
  1498. $val = 'foo';
  1499. $session_var_name = sprintf(
  1500. '%s_fb_%s_%s',
  1501. $fb->publicGetSharedSessionID(),
  1502. self::APP_ID,
  1503. $key
  1504. );
  1505. $fb->publicSetPersistentData($key, $val);
  1506. $this->assertFalse(array_key_exists($session_var_name, $_SESSION));
  1507. $this->assertFalse($fb->publicGetPersistentData($key));
  1508. }
  1509. public function testSharedClearSessionBackedFacebook() {
  1510. $_SERVER['HTTP_HOST'] = 'fbrell.com';
  1511. $fb = new PersistentFBPublic(array(
  1512. 'appId' => self::APP_ID,
  1513. 'secret' => self::SECRET,
  1514. 'sharedSession' => true,
  1515. ));
  1516. $key = 'state';
  1517. $val = 'foo';
  1518. $session_var_name = sprintf(
  1519. '%s_fb_%s_%s',
  1520. $fb->publicGetSharedSessionID(),
  1521. self::APP_ID,
  1522. $key
  1523. );
  1524. $fb->publicSetPersistentData($key, $val);
  1525. $this->assertEquals($val, $_SESSION[$session_var_name]);
  1526. $this->assertEquals($val, $fb->publicGetPersistentData($key));
  1527. $fb->publicClearPersistentData($key);
  1528. $this->assertFalse(array_key_exists($session_var_name, $_SESSION));
  1529. $this->assertFalse($fb->publicGetPersistentData($key));
  1530. }
  1531. public function testSharedSessionBackedFacebookIgnoresUnsupportedKeyInClear() {
  1532. $_SERVER['HTTP_HOST'] = 'fbrell.com';
  1533. $fb = new PersistentFBPublic(array(
  1534. 'appId' => self::APP_ID,
  1535. 'secret' => self::SECRET,
  1536. 'sharedSession' => true,
  1537. ));
  1538. $key = '--invalid--';
  1539. $val = 'foo';
  1540. $session_var_name = sprintf(
  1541. '%s_fb_%s_%s',
  1542. $fb->publicGetSharedSessionID(),
  1543. self::APP_ID,
  1544. $key
  1545. );
  1546. $_SESSION[$session_var_name] = $val;
  1547. $fb->publicClearPersistentData($key);
  1548. $this->assertTrue(array_key_exists($session_var_name, $_SESSION));
  1549. $this->assertFalse($fb->publicGetPersistentData($key));
  1550. }
  1551. public function testSharedClearAllSessionBackedFacebook() {
  1552. $_SERVER['HTTP_HOST'] = 'fbrell.com';
  1553. $fb = new PersistentFBPublic(array(
  1554. 'appId' => self::APP_ID,
  1555. 'secret' => self::SECRET,
  1556. 'sharedSession' => true,
  1557. ));
  1558. $key = 'state';
  1559. $val = 'foo';
  1560. $session_var_name = sprintf(
  1561. '%s_fb_%s_%s',
  1562. $fb->publicGetSharedSessionID(),
  1563. self::APP_ID,
  1564. $key
  1565. );
  1566. $fb->publicSetPersistentData($key, $val);
  1567. $this->assertEquals($val, $_SESSION[$session_var_name]);
  1568. $this->assertEquals($val, $fb->publicGetPersistentData($key));
  1569. $fb->publicClearAllPersistentData();
  1570. $this->assertFalse(array_key_exists($session_var_name, $_SESSION));
  1571. $this->assertFalse($fb->publicGetPersistentData($key));
  1572. }
  1573. public function testSharedSessionBackedFacebookIsRestored() {
  1574. $_SERVER['HTTP_HOST'] = 'fbrell.com';
  1575. $fb = new PersistentFBPublic(array(
  1576. 'appId' => self::APP_ID,
  1577. 'secret' => self::SECRET,
  1578. 'sharedSession' => true,
  1579. ));
  1580. $key = 'state';
  1581. $val = 'foo';
  1582. $shared_session_id = $fb->publicGetSharedSessionID();
  1583. $session_var_name = sprintf(
  1584. '%s_fb_%s_%s',
  1585. $shared_session_id,
  1586. self::APP_ID,
  1587. $key
  1588. );
  1589. $fb->publicSetPersistentData($key, $val);
  1590. $this->assertEquals($val, $_SESSION[$session_var_name]);
  1591. $this->assertEquals($val, $fb->publicGetPersistentData($key));
  1592. // check the new instance has the same data
  1593. $fb = new PersistentFBPublic(array(
  1594. 'appId' => self::APP_ID,
  1595. 'secret' => self::SECRET,
  1596. 'sharedSession' => true,
  1597. ));
  1598. $this->assertEquals(
  1599. $shared_session_id,
  1600. $fb->publicGetSharedSessionID()
  1601. );
  1602. $this->assertEquals($val, $fb->publicGetPersistentData($key));
  1603. }
  1604. public function testSharedSessionBackedFacebookIsNotRestoredWhenCorrupt() {
  1605. $_SERVER['HTTP_HOST'] = 'fbrell.com';
  1606. $fb = new PersistentFBPublic(array(
  1607. 'appId' => self::APP_ID,
  1608. 'secret' => self::SECRET,
  1609. 'sharedSession' => true,
  1610. ));
  1611. $key = 'state';
  1612. $val = 'foo';
  1613. $shared_session_id = $fb->publicGetSharedSessionID();
  1614. $session_var_name = sprintf(
  1615. '%s_fb_%s_%s',
  1616. $shared_session_id,
  1617. self::APP_ID,
  1618. $key
  1619. );
  1620. $fb->publicSetPersistentData($key, $val);
  1621. $this->assertEquals($val, $_SESSION[$session_var_name]);
  1622. $this->assertEquals($val, $fb->publicGetPersistentData($key));
  1623. // break the cookie
  1624. $cookie_name = $fb->publicGetSharedSessionCookieName();
  1625. $_COOKIE[$cookie_name] = substr($_COOKIE[$cookie_name], 1);
  1626. // check the new instance does not have the data
  1627. $fb = new PersistentFBPublic(array(
  1628. 'appId' => self::APP_ID,
  1629. 'secret' => self::SECRET,
  1630. 'sharedSession' => true,
  1631. ));
  1632. $this->assertFalse($fb->publicGetPersistentData($key));
  1633. $this->assertNotEquals(
  1634. $shared_session_id,
  1635. $fb->publicGetSharedSessionID()
  1636. );
  1637. }
  1638. public function testHttpHost() {
  1639. $real = 'foo.com';
  1640. $_SERVER['HTTP_HOST'] = $real;
  1641. $_SERVER['HTTP_X_FORWARDED_HOST'] = 'evil.com';
  1642. $fb = new PersistentFBPublic(array(
  1643. 'appId' => self::APP_ID,
  1644. 'secret' => self::SECRET,
  1645. ));
  1646. $this->assertEquals($real, $fb->publicGetHttpHost());
  1647. }
  1648. public function testHttpProtocol() {
  1649. $_SERVER['HTTPS'] = 'on';
  1650. $_SERVER['HTTP_X_FORWARDED_PROTO'] = 'http';
  1651. $fb = new PersistentFBPublic(array(
  1652. 'appId' => self::APP_ID,
  1653. 'secret' => self::SECRET,
  1654. ));
  1655. $this->assertEquals('https', $fb->publicGetHttpProtocol());
  1656. }
  1657. public function testHttpHostForwarded() {
  1658. $real = 'foo.com';
  1659. $_SERVER['HTTP_HOST'] = 'localhost';
  1660. $_SERVER['HTTP_X_FORWARDED_HOST'] = $real;
  1661. $fb = new PersistentFBPublic(array(
  1662. 'appId' => self::APP_ID,
  1663. 'secret' => self::SECRET,
  1664. 'trustForwarded' => true,
  1665. ));
  1666. $this->assertEquals($real, $fb->publicGetHttpHost());
  1667. }
  1668. public function testHttpProtocolForwarded() {
  1669. $_SERVER['HTTPS'] = 'on';
  1670. $_SERVER['HTTP_X_FORWARDED_PROTO'] = 'http';
  1671. $fb = new PersistentFBPublic(array(
  1672. 'appId' => self::APP_ID,
  1673. 'secret' => self::SECRET,
  1674. 'trustForwarded' => true,
  1675. ));
  1676. $this->assertEquals('http', $fb->publicGetHttpProtocol());
  1677. }
  1678. public function testHttpProtocolForwardedSecure() {
  1679. $_SERVER['HTTPS'] = 'on';
  1680. $_SERVER['HTTP_X_FORWARDED_PROTO'] = 'https';
  1681. $fb = new PersistentFBPublic(array(
  1682. 'appId' => self::APP_ID,
  1683. 'secret' => self::SECRET,
  1684. 'trustForwarded' => true,
  1685. ));
  1686. $this->assertEquals('https', $fb->publicGetHttpProtocol());
  1687. }
  1688. /**
  1689. * @dataProvider provideEndsWith
  1690. */
  1691. public function testEndsWith($big, $small, $result) {
  1692. $this->assertEquals(
  1693. $result,
  1694. PersistentFBPublic::publicEndsWith($big, $small)
  1695. );
  1696. }
  1697. public function provideEndsWith() {
  1698. return array(
  1699. array('', '', true),
  1700. array('', 'a', false),
  1701. array('a', '', true),
  1702. array('a', 'b', false),
  1703. array('a', 'a', true),
  1704. array('aa', 'a', true),
  1705. array('ab', 'a', false),
  1706. array('ba', 'a', true),
  1707. );
  1708. }
  1709. /**
  1710. * @dataProvider provideIsAllowedDomain
  1711. */
  1712. public function testIsAllowedDomain($big, $small, $result) {
  1713. $this->assertEquals(
  1714. $result,
  1715. PersistentFBPublic::publicIsAllowedDomain($big, $small)
  1716. );
  1717. }
  1718. public function provideIsAllowedDomain() {
  1719. return array(
  1720. array('fbrell.com', 'fbrell.com', true),
  1721. array('foo.fbrell.com', 'fbrell.com', true),
  1722. array('foofbrell.com', 'fbrell.com', false),
  1723. array('evil.com', 'fbrell.com', false),
  1724. array('foo.fbrell.com', 'bar.fbrell.com', false),
  1725. );
  1726. }
  1727. protected function generateMD5HashOfRandomValue() {
  1728. return md5(uniqid(mt_rand(), true));
  1729. }
  1730. protected function setUp() {
  1731. parent::setUp();
  1732. }
  1733. protected function tearDown() {
  1734. $this->clearSuperGlobals();
  1735. parent::tearDown();
  1736. }
  1737. protected function clearSuperGlobals() {
  1738. unset($_SERVER['HTTPS']);
  1739. unset($_SERVER['HTTP_HOST']);
  1740. unset($_SERVER['REQUEST_URI']);
  1741. $_SESSION = array();
  1742. $_COOKIE = array();
  1743. $_REQUEST = array();
  1744. $_POST = array();
  1745. $_GET = array();
  1746. if (session_id()) {
  1747. session_destroy();
  1748. }
  1749. }
  1750. /**
  1751. * Checks that the correct args are a subset of the returned obj
  1752. * @param array $correct The correct array values
  1753. * @param array $actual The values in practice
  1754. * @param string $message to be shown on failure
  1755. */
  1756. protected function assertIsSubset($correct, $actual, $msg='') {
  1757. foreach ($correct as $key => $value) {
  1758. $actual_value = $actual[$key];
  1759. $newMsg = (strlen($msg) ? ($msg.' ') : '').'Key: '.$key;
  1760. $this->assertEquals($value, $actual_value, $newMsg);
  1761. }
  1762. }
  1763. }
  1764. class TransientFacebook extends BaseFacebook {
  1765. protected function setPersistentData($key, $value) {}
  1766. protected function getPersistentData($key, $default = false) {
  1767. return $default;
  1768. }
  1769. protected function clearPersistentData($key) {}
  1770. protected function clearAllPersistentData() {}
  1771. }
  1772. class FBRecordURL extends TransientFacebook {
  1773. private $url;
  1774. protected function _oauthRequest($url, $params) {
  1775. $this->url = $url;
  1776. }
  1777. public function getRequestedURL() {
  1778. return $this->url;
  1779. }
  1780. }
  1781. class FBRecordMakeRequest extends TransientFacebook {
  1782. private $requests = array();
  1783. protected function makeRequest($url, $params, $ch=null) {
  1784. $this->requests[] = array(
  1785. 'url' => $url,
  1786. 'params' => $params,
  1787. );
  1788. return parent::makeRequest($url, $params, $ch);
  1789. }
  1790. public function publicGetRequests() {
  1791. return $this->requests;
  1792. }
  1793. public function publicGetAppSecretProof($access_token) {
  1794. return $this->getAppSecretProof($access_token);
  1795. }
  1796. }
  1797. class FBPublic extends TransientFacebook {
  1798. public static function publicBase64UrlDecode($input) {
  1799. return self::base64UrlDecode($input);
  1800. }
  1801. public static function publicBase64UrlEncode($input) {
  1802. return self::base64UrlEncode($input);
  1803. }
  1804. public function publicParseSignedRequest($input) {
  1805. return $this->parseSignedRequest($input);
  1806. }
  1807. public function publicMakeSignedRequest($data) {
  1808. return $this->makeSignedRequest($data);
  1809. }
  1810. }
  1811. class PersistentFBPublic extends Facebook {
  1812. public function publicParseSignedRequest($input) {
  1813. return $this->parseSignedRequest($input);
  1814. }
  1815. public function publicSetPersistentData($key, $value) {
  1816. $this->setPersistentData($key, $value);
  1817. }
  1818. public function publicGetPersistentData($key, $default = false) {
  1819. return $this->getPersistentData($key, $default);
  1820. }
  1821. public function publicClearPersistentData($key) {
  1822. return $this->clearPersistentData($key);
  1823. }
  1824. public function publicClearAllPersistentData() {
  1825. return $this->clearAllPersistentData();
  1826. }
  1827. public function publicGetSharedSessionID() {
  1828. return $this->sharedSessionID;
  1829. }
  1830. public static function publicIsAllowedDomain($big, $small) {
  1831. return self::isAllowedDomain($big, $small);
  1832. }
  1833. public static function publicEndsWith($big, $small) {
  1834. return self::endsWith($big, $small);
  1835. }
  1836. public function publicGetSharedSessionCookieName() {
  1837. return $this->getSharedSessionCookieName();
  1838. }
  1839. public function publicGetHttpHost() {
  1840. return $this->getHttpHost();
  1841. }
  1842. public function publicGetHttpProtocol() {
  1843. return $this->getHttpProtocol();
  1844. }
  1845. }
  1846. class FBCode extends Facebook {
  1847. public function publicGetCode() {
  1848. return $this->getCode();
  1849. }
  1850. public function publicGetState() {
  1851. return $this->state;
  1852. }
  1853. public function setCSRFStateToken() {
  1854. $this->establishCSRFTokenState();
  1855. }
  1856. public function getCSRFStateToken() {
  1857. return $this->getPersistentData('state');
  1858. }
  1859. }
  1860. class FBAccessToken extends TransientFacebook {
  1861. public function publicGetApplicationAccessToken() {
  1862. return $this->getApplicationAccessToken();
  1863. }
  1864. }
  1865. class FBGetCurrentURLFacebook extends TransientFacebook {
  1866. public function publicGetCurrentUrl() {
  1867. return $this->getCurrentUrl();
  1868. }
  1869. }
  1870. class FBPublicCookie extends TransientFacebook {
  1871. public function publicGetSignedRequest() {
  1872. return $this->getSignedRequest();
  1873. }
  1874. public function publicGetSignedRequestCookieName() {
  1875. return $this->getSignedRequestCookieName();
  1876. }
  1877. public function publicGetMetadataCookie() {
  1878. return $this->getMetadataCookie();
  1879. }
  1880. public function publicGetMetadataCookieName() {
  1881. return $this->getMetadataCookieName();
  1882. }
  1883. }
  1884. class FBRewrite extends Facebook{
  1885. public function uncacheSignedRequest(){
  1886. $this->signedRequest = null;
  1887. }
  1888. public function uncache()
  1889. {
  1890. $this->user = null;
  1891. $this->signedRequest = null;
  1892. $this->accessToken = null;
  1893. }
  1894. }
  1895. class FBPublicGetAccessTokenFromCode extends TransientFacebook {
  1896. public function publicGetAccessTokenFromCode($code, $redirect_uri = null) {
  1897. return $this->getAccessTokenFromCode($code, $redirect_uri);
  1898. }
  1899. }
  1900. class FBPublicState extends TransientFacebook {
  1901. const STATE = 'foo';
  1902. protected function getPersistentData($key, $default = false) {
  1903. if ($key === 'state') {
  1904. return self::STATE;
  1905. }
  1906. return parent::getPersistentData($key, $default);
  1907. }
  1908. public function publicGetState() {
  1909. return $this->state;
  1910. }
  1911. }