From 7212c0c51b0f406ae8c78df947774733530cade9 Mon Sep 17 00:00:00 2001 From: Fosco Marotto Date: Mon, 23 Mar 2015 16:51:51 -0700 Subject: [PATCH 1/4] Added ParseSession --- tests/IncrementTest.php | 2 +- tests/ParseCloudTest.php | 52 -------------------------------------- tests/ParseObjectTest.php | 2 +- tests/ParseSessionTest.php | 47 ++++++++++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 54 deletions(-) create mode 100644 tests/ParseSessionTest.php diff --git a/tests/IncrementTest.php b/tests/IncrementTest.php index 2e35f8db..5f5650db 100644 --- a/tests/IncrementTest.php +++ b/tests/IncrementTest.php @@ -211,7 +211,7 @@ public function testIncrementEmptyFieldAndTypeConflict() $obj->save(); $objAgain->increment('randomkey'); $this->setExpectedException('Parse\ParseException', - "can't increment a field that isn't a number" + "invalid type for key" ); $objAgain->save(); } diff --git a/tests/ParseCloudTest.php b/tests/ParseCloudTest.php index c8749acc..04dc573e 100644 --- a/tests/ParseCloudTest.php +++ b/tests/ParseCloudTest.php @@ -31,13 +31,6 @@ public function testFunctionsWithGeoPointParamsDoNotThrow() ParseCloud::run('unknown_function', $params); } - public function testExplicitFunctionFailure() - { - $params = array('key1' => 'value1'); - $this->setExpectedException('Parse\ParseException','bad stuff happened'); - ParseCloud::run('bar', $params); - } - public function testUnknownFunctionFailure() { $params = array('key1' => 'value1'); @@ -45,49 +38,4 @@ public function testUnknownFunctionFailure() ParseCloud::run('unknown_function', $params); } - public function testFunctions() - { - $params = array( - 'key1' => 'value1', - 'key2' => array(1,2,3) - ); - $response = ParseCloud::run('foo', $params); - $obj = $response['object']; - $this->assertTrue($obj instanceof ParseObject); - $this->assertEquals('Foo', $obj->className); - $this->assertEquals(2, $obj->get('x')); - $relation = $obj->get('relation'); - $this->assertTrue($relation instanceof ParseObject); - $this->assertEquals('Bar', $relation->className); - $this->assertEquals(3, $relation->get('x')); - $obj = $response['array'][0]; - $this->assertTrue($obj instanceof ParseObject); - $this->assertEquals('Bar', $obj->className); - $this->assertEquals(2, $obj->get('x')); - - $response = ParseCloud::run('foo', array('key1' => 'value1')); - $this->assertEquals(2, $response['a']); - - try { - $response = ParseCloud::run('bar', array('key1' => 'value1')); - $this->fail('Should have thrown an exception.'); - } catch(Parse\ParseException $ex) { - // A parse exception should occur. - } - - $response = ParseCloud::run('bar', array('key2' => 'value1')); - $this->assertEquals('Foo', $response); - - $obj = ParseObject::create('SomeClass'); - $obj->set('name', 'Zanzibar'); - $obj->save(); - - $params = array('key2' => 'value1', 'key1' => $obj); - try { - $response = ParseCloud::run('foo', $params); - $this->fail('Should have thrown an exception.'); - } catch (\Exception $ex) { - // An exception should occur. - } - } } \ No newline at end of file diff --git a/tests/ParseObjectTest.php b/tests/ParseObjectTest.php index 89921ad6..2262d5a0 100644 --- a/tests/ParseObjectTest.php +++ b/tests/ParseObjectTest.php @@ -271,7 +271,7 @@ public function testCanSetBoolean() public function testInvalidClassName() { $obj = ParseObject::create('Foo^bar'); - $this->setExpectedException('Parse\ParseException', 'Bad Request'); + $this->setExpectedException('Parse\ParseException', 'bad characters in classname'); $obj->save(); } diff --git a/tests/ParseSessionTest.php b/tests/ParseSessionTest.php new file mode 100644 index 00000000..22b5930a --- /dev/null +++ b/tests/ParseSessionTest.php @@ -0,0 +1,47 @@ +setUsername("username"); + $user->setPassword("password"); + $user->signUp(); + $session = ParseSession::getCurrentSession(); + $this->assertEquals($user->getSessionToken(), $session->getSessionToken()); + $this->assertTrue($session->isCurrentSessionRevocable()); + } + +} \ No newline at end of file From cbb38020336bd833b506972f8e4cfdf81893a48c Mon Sep 17 00:00:00 2001 From: Fosco Marotto Date: Mon, 23 Mar 2015 16:52:42 -0700 Subject: [PATCH 2/4] Added ParseSession --- src/Parse/ParseClient.php | 23 +++++++++- src/Parse/ParseObject.php | 4 +- src/Parse/ParseSession.php | 90 ++++++++++++++++++++++++++++++++++++++ src/Parse/ParseUser.php | 8 +++- 4 files changed, 121 insertions(+), 4 deletions(-) create mode 100644 src/Parse/ParseSession.php diff --git a/src/Parse/ParseClient.php b/src/Parse/ParseClient.php index d38d36f4..6e118751 100755 --- a/src/Parse/ParseClient.php +++ b/src/Parse/ParseClient.php @@ -44,6 +44,11 @@ final class ParseClient */ private static $storage; + /** + * @var - Boolean for enabling revocable sessions. + */ + private static $forceRevocableSession = false; + /** * Constant for version string to include with requests. * @ignore @@ -56,7 +61,7 @@ final class ParseClient * @param string $app_id Parse Application ID * @param string $rest_key Parse REST API Key * @param string $master_key Parse Master Key - * @param string $enableCurlExceptions Enable or disable Parse curl exceptions + * @param boolean $enableCurlExceptions Enable or disable Parse curl exceptions * * @return null */ @@ -65,6 +70,7 @@ public static function initialize($app_id, $rest_key, $master_key, $enableCurlEx ParseUser::registerSubclass(); ParseRole::registerSubclass(); ParseInstallation::registerSubclass(); + ParseSession::registerSubclass(); self::$applicationId = $app_id; self::$restKey = $rest_key; self::$masterKey = $master_key; @@ -341,6 +347,9 @@ public static function _getRequestHeaders($sessionToken, $useMasterKey) } else { $headers[] = 'X-Parse-REST-API-Key: ' . self::$restKey; } + if (self::$forceRevocableSession) { + $headers[] = 'X-Parse-Revocable-Session: 1'; + } /** * Set an empty Expect header to stop the 100-continue behavior for post * data greater than 1024 bytes. @@ -384,4 +393,16 @@ public static function getLocalPushDateFormat($value) $date = date_format($value, $dateFormatString); return $date; } + + /** + * Allows an existing application to start using revocable sessions, without forcing + * all requests for the app to use them. After calling this method, login & signup requests + * will be returned a unique and revocable session token. + * + */ + public static function enableRevocableSessions() + { + self::$forceRevocableSession = true; + } + } diff --git a/src/Parse/ParseObject.php b/src/Parse/ParseObject.php index 33e20d12..d701eeb9 100755 --- a/src/Parse/ParseObject.php +++ b/src/Parse/ParseObject.php @@ -532,7 +532,7 @@ public function _mergeAfterFetchWithSelectedKeys($result, $selectedKeys) private function mergeFromServer($data, $completeData = true) { $this->hasBeenFetched = ($this->hasBeenFetched || $completeData) ? true : false; - $this->mergeMagicFields($data); + $this->_mergeMagicFields($data); foreach ($data as $key => $value) { if ($key === '__type' && $value === 'className') { continue; @@ -567,7 +567,7 @@ private function mergeFromServer($data, $completeData = true) * * @return null */ - private function mergeMagicFields(&$data) + public function _mergeMagicFields(&$data) { if (isset($data['objectId'])) { $this->objectId = $data['objectId']; diff --git a/src/Parse/ParseSession.php b/src/Parse/ParseSession.php new file mode 100644 index 00000000..105f1b80 --- /dev/null +++ b/src/Parse/ParseSession.php @@ -0,0 +1,90 @@ + + */ +class ParseSession extends ParseObject +{ + + public static $parseClassName = "_Session"; + + private $_sessionToken = null; + + /** + * Returns the session token string. + * + * @return string + */ + public function getSessionToken() + { + return $this->_sessionToken; + } + + /** + * Retrieves the Session object for the currently logged in user. + * + * @param boolean $useMasterKey If the Master Key should be used to override security + * + * @return ParseSession + */ + public static function getCurrentSession($useMasterKey = false) + { + $session = new ParseSession(); + $token = ParseUser::getCurrentUser()->getSessionToken(); + $response = ParseClient::_request('GET', '/1/sessions/me', $token, null, $useMasterKey); + $session->_mergeAfterFetch($response); + $session->handleSaveResult(); + return $session; + } + + + /** + * Determines whether the current session token is revocable. + * This method is useful for migrating an existing app to use + * revocable sessions. + * + * @return boolean + */ + public static function isCurrentSessionRevocable() + { + $user = ParseUser::getCurrentUser(); + if ($user) { + return self::_isRevocable($user->getSessionToken()); + } + } + + /** + * Determines whether a session token is revocable. + * + * @param string $token The session token to check + * + * @return boolean + */ + public static function _isRevocable($token) + { + return strpos($token, "r:") === 0; + } + + /** + * After a save, perform Session object specific logic. + * + * @return null + */ + private function handleSaveResult() + { + if (isset($this->serverData['sessionToken'])) { + $this->_sessionToken = $this->serverData['sessionToken']; + unset($this->serverData['sessionToken']); + } + $this->rebuildEstimatedData(); + } + +} \ No newline at end of file diff --git a/src/Parse/ParseUser.php b/src/Parse/ParseUser.php index f357a927..fd72650c 100644 --- a/src/Parse/ParseUser.php +++ b/src/Parse/ParseUser.php @@ -162,13 +162,19 @@ public static function become($sessionToken) /** * Log out the current user. This will clear the storage and future calls - * to current will return null + * to current will return null. + * This will make a network request to /1/logout to invalidate the session * * @return null */ public static function logOut() { if (ParseUser::getCurrentUser()) { + try { + $result = ParseClient::_request('GET', '/1/logout'); + } catch (ParseException $ex) { + // If this fails, we're going to ignore it. + } static::$currentUser = null; } ParseClient::getStorage()->remove('user'); From bfc7c92d54877708663d077382c87a95cb05a8e4 Mon Sep 17 00:00:00 2001 From: Fosco Marotto Date: Mon, 23 Mar 2015 17:13:26 -0700 Subject: [PATCH 3/4] Updated per review. --- src/Parse/ParseClient.php | 1 + src/Parse/ParseSession.php | 6 +++--- src/Parse/ParseUser.php | 5 +++-- tests/ParseSessionTest.php | 16 +++++++++++++++- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/Parse/ParseClient.php b/src/Parse/ParseClient.php index 6e118751..995da461 100755 --- a/src/Parse/ParseClient.php +++ b/src/Parse/ParseClient.php @@ -399,6 +399,7 @@ public static function getLocalPushDateFormat($value) * all requests for the app to use them. After calling this method, login & signup requests * will be returned a unique and revocable session token. * + * @return null */ public static function enableRevocableSessions() { diff --git a/src/Parse/ParseSession.php b/src/Parse/ParseSession.php index 105f1b80..2c93f8c2 100644 --- a/src/Parse/ParseSession.php +++ b/src/Parse/ParseSession.php @@ -6,7 +6,7 @@ use Parse\ParseUser; /** - * ParseSession - Representation of an expiring user session + * ParseSession - Representation of an expiring user session. * * @package Parse * @author Fosco Marotto @@ -31,15 +31,15 @@ public function getSessionToken() /** * Retrieves the Session object for the currently logged in user. * - * @param boolean $useMasterKey If the Master Key should be used to override security + * @param boolean $useMasterKey If the Master Key should be used to override security. * * @return ParseSession */ public static function getCurrentSession($useMasterKey = false) { - $session = new ParseSession(); $token = ParseUser::getCurrentUser()->getSessionToken(); $response = ParseClient::_request('GET', '/1/sessions/me', $token, null, $useMasterKey); + $session = new ParseSession(); $session->_mergeAfterFetch($response); $session->handleSaveResult(); return $session; diff --git a/src/Parse/ParseUser.php b/src/Parse/ParseUser.php index fd72650c..f2f4d72c 100644 --- a/src/Parse/ParseUser.php +++ b/src/Parse/ParseUser.php @@ -169,9 +169,10 @@ public static function become($sessionToken) */ public static function logOut() { - if (ParseUser::getCurrentUser()) { + $user = ParseUser::getCurrentUser(); + if ($user) { try { - $result = ParseClient::_request('GET', '/1/logout'); + ParseClient::_request('POST', '/1/logout', $user->getSessionToken()); } catch (ParseException $ex) { // If this fails, we're going to ignore it. } diff --git a/tests/ParseSessionTest.php b/tests/ParseSessionTest.php index 22b5930a..42db1846 100644 --- a/tests/ParseSessionTest.php +++ b/tests/ParseSessionTest.php @@ -32,7 +32,7 @@ public static function tearDownAfterClass() ParseSession::_unregisterSubclass(); } - public function testGetCurrentSession() + public function testRevocableSession() { ParseClient::enableRevocableSessions(); $user = new ParseUser(); @@ -42,6 +42,20 @@ public function testGetCurrentSession() $session = ParseSession::getCurrentSession(); $this->assertEquals($user->getSessionToken(), $session->getSessionToken()); $this->assertTrue($session->isCurrentSessionRevocable()); + + ParseUser::logOut(); + + ParseUser::logIn("username", "password"); + $session = ParseSession::getCurrentSession(); + $this->assertEquals(ParseUser::getCurrentUser()->getSessionToken(), $session->getSessionToken()); + $this->assertTrue($session->isCurrentSessionRevocable()); + + $sessionToken = $session->getSessionToken(); + + ParseUser::logOut(); + + $this->setExpectedException('Parse\ParseException', 'invalid session token'); + ParseUser::become($sessionToken); } } \ No newline at end of file From 3ca3e9751f77c0746bc35a4fbcbb34125295676f Mon Sep 17 00:00:00 2001 From: Fosco Marotto Date: Wed, 25 Mar 2015 10:34:18 -0700 Subject: [PATCH 4/4] Updated to 1.1.0 --- README.md | 2 +- src/Parse/ParseClient.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e0f6dc36..514e7b6d 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Installation ```json { "require": { - "parse/php-sdk" : "1.0.*" + "parse/php-sdk" : "1.1.*" } } ``` diff --git a/src/Parse/ParseClient.php b/src/Parse/ParseClient.php index 995da461..d85742a1 100755 --- a/src/Parse/ParseClient.php +++ b/src/Parse/ParseClient.php @@ -53,7 +53,7 @@ final class ParseClient * Constant for version string to include with requests. * @ignore */ - const VERSION_STRING = 'php1.0.6'; + const VERSION_STRING = 'php1.1.0'; /** * Parse\Client::initialize, must be called before using Parse features.