diff options
author | Joas Schilling <coding@schilljs.com> | 2021-10-18 15:15:13 +0300 |
---|---|---|
committer | backportbot[bot] <backportbot[bot]@users.noreply.github.com> | 2021-10-19 12:35:27 +0300 |
commit | 292701479f3bf225fad6545a93be20c2c0c36c35 (patch) | |
tree | 9949803c038f26d125dcdee52a293a0d6b112847 | |
parent | b6167abff90e02d6b38c0e8c66fff23fb3647d30 (diff) |
Add an integration test for push registration
Signed-off-by: Joas Schilling <coding@schilljs.com>
-rw-r--r-- | tests/Integration/features/bootstrap/FeatureContext.php | 109 | ||||
-rw-r--r-- | tests/Integration/features/push-registration.feature | 64 |
2 files changed, 169 insertions, 4 deletions
diff --git a/tests/Integration/features/bootstrap/FeatureContext.php b/tests/Integration/features/bootstrap/FeatureContext.php index 51b66cb..6ecb6d9 100644 --- a/tests/Integration/features/bootstrap/FeatureContext.php +++ b/tests/Integration/features/bootstrap/FeatureContext.php @@ -56,6 +56,12 @@ class FeatureContext implements Context, SnippetAcceptingContext { /** @var string */ protected $lastEtag; + /** @var resource */ + protected $deviceKey; + + /** @var string[] */ + protected $appPasswords; + /** * FeatureContext constructor. */ @@ -239,6 +245,99 @@ class FeatureContext implements Context, SnippetAcceptingContext { } /** + * @Then /^user "([^"]*)" unregisters from push notifications/ + * + * @param string $user + */ + public function unregisterForPushNotifications(string $user) { + $currentUser = $this->currentUser; + $this->setCurrentUser($user); + $this->sendingToWith('DELETE', '/apps/notifications/api/v2/push?format=json'); + $this->setCurrentUser($currentUser); + } + + /** + * @Then /^user "([^"]*)" registers for push notifications with$/ + * + * @param string $user + * @param TableNode|null $formData + */ + public function registerForPushNotifications(string $user, TableNode $formData) { + $data = $formData->getRowsHash(); + + if ($data['devicePublicKey'] === 'VALID_KEY') { + $config = [ + 'digest_alg' => 'sha512', + 'private_key_bits' => 2048, + 'private_key_type' => OPENSSL_KEYTYPE_RSA, + ]; + $this->deviceKey = openssl_pkey_new($config); + $keyDetails = openssl_pkey_get_details($this->deviceKey); + $publicKey = $keyDetails['key']; + + $data['devicePublicKey'] = $publicKey; + } + + $currentUser = $this->currentUser; + $this->setCurrentUser($user); + $this->sendingToWith('POST', '/apps/notifications/api/v2/push?format=json', $data); + $this->setCurrentUser($currentUser); + } + + /** + * @Then /^can validate the response and signature$/ + */ + public function validateResponseAndSignature(): void { + $response = $this->getArrayOfNotificationsResponded($this->response); + + Assert::assertStringStartsWith('-----BEGIN PUBLIC KEY-----' . "\n", $response['publicKey']); + Assert::assertStringEndsWith('-----END PUBLIC KEY-----' . "\n", $response['publicKey']); + Assert::assertNotEmpty($response['deviceIdentifier'], 'Device identifier should not be empty'); + Assert::assertNotEmpty($response['signature'], 'Signature should not be empty'); + + $result = openssl_verify($response['deviceIdentifier'], base64_decode($response['signature']), $response['publicKey'], OPENSSL_ALGO_SHA512); + Assert::assertEquals(true, $result, 'Failed to verify the signature'); + } + + /** + * @Then /^user "([^"]*)" creates an app password$/ + * + * @param string $user + */ + public function createAppPassword(string $user) { + $currentUser = $this->currentUser; + $this->setCurrentUser($user); + $this->sendingToWith('GET', '/core/getapppassword?format=json'); + $this->setCurrentUser($currentUser); + + $response = $this->getArrayOfNotificationsResponded($this->response); + Assert::assertNotEquals('', $response['apppassword']); + $this->appPasswords[$user] = $response['apppassword']; + } + + /** + * @Then /^user "([^"]*)" forgets the app password$/ + * + * @param string $user + */ + public function removeAppPassword(string $user) { + unset($this->appPasswords[$user]); + } + + /** + * @Then /^error "([^"]*)" is expected with status code ([0-9]*)$/ + * + * @param string $error + * @param int $statusCode + */ + public function expectedErrorOnLastRequest(string $error, int $statusCode) { + $this->assertStatusCode($this->response, $statusCode); + $response = $this->getArrayOfNotificationsResponded($this->response); + + Assert::assertEquals($error, $response['message']); + } + + /** * @Then /^status code is ([0-9]*)$/ * * @param int $statusCode @@ -366,15 +465,17 @@ class FeatureContext implements Context, SnippetAcceptingContext { * @When /^sending "([^"]*)" to "([^"]*)" with$/ * @param string $verb * @param string $url - * @param TableNode $body + * @param TableNode|array|null $body * @param array $headers */ - public function sendingToWith(string $verb, string $url, TableNode $body = null, array $headers = []) { + public function sendingToWith(string $verb, string $url, $body = null, array $headers = []) { $fullUrl = $this->baseUrl . 'ocs/v2.php' . $url; $client = new Client(); $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = ['admin', 'admin']; + if (isset($this->appPasswords[$this->currentUser])) { + $options['auth'] = [$this->currentUser, $this->appPasswords[$this->currentUser]]; + } elseif ($this->currentUser === 'admin') { + $options['auth'] = [$this->currentUser, 'admin']; } else { $options['auth'] = [$this->currentUser, '123456']; } diff --git a/tests/Integration/features/push-registration.feature b/tests/Integration/features/push-registration.feature new file mode 100644 index 0000000..3d1eea9 --- /dev/null +++ b/tests/Integration/features/push-registration.feature @@ -0,0 +1,64 @@ +Feature: Push registration + Background: + Given user "test1" exists + Given as user "test1" + + Scenario: Invalid push token hash + Given user "test1" registers for push notifications with + | pushTokenHash | 12345 | + | devicePublicKey | INVALID_KEY | + | proxyServer | nextcloud | + Then error "INVALID_PUSHTOKEN_HASH" is expected with status code 400 + + Scenario: Invalid device key + Given user "test1" registers for push notifications with + | pushTokenHash | 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678 | + | devicePublicKey | INVALID_KEY | + | proxyServer | nextcloud | + Then error "INVALID_DEVICE_KEY" is expected with status code 400 + + Scenario: Invalid proxy server + Given user "test1" registers for push notifications with + | pushTokenHash | 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678 | + | devicePublicKey | VALID_KEY | + | proxyServer | nextcloud | + Then error "INVALID_PROXY_SERVER" is expected with status code 400 + + Scenario: Invalid session token: not using an app password + Given user "test1" registers for push notifications with + | pushTokenHash | 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678 | + | devicePublicKey | VALID_KEY | + | proxyServer | https://push-notifications.nextcloud.com/ | + Then error "INVALID_SESSION_TOKEN" is expected with status code 400 + + Scenario: Successful registration + Given user "test1" creates an app password + Given user "test1" registers for push notifications with + | pushTokenHash | 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678 | + | devicePublicKey | VALID_KEY | + | proxyServer | https://push-notifications.nextcloud.com/ | + Then status code is 201 + And can validate the response and signature + + Scenario: Unregistering from push notifications without app password + Given user "test1" forgets the app password + Given user "test1" unregisters from push notifications + Then error "INVALID_SESSION_TOKEN" is expected with status code 400 + + Scenario: Unregistering from push notifications successfully + Given user "test1" creates an app password + Given user "test1" registers for push notifications with + | pushTokenHash | 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678 | + | devicePublicKey | VALID_KEY | + | proxyServer | https://push-notifications.nextcloud.com/ | + Then status code is 201 + And can validate the response and signature + Given user "test1" unregisters from push notifications + Then status code is 202 + Given user "test1" unregisters from push notifications + Then status code is 200 + + Scenario: Unregistering from push notifications without registering + Given user "test1" creates an app password + Given user "test1" unregisters from push notifications + Then status code is 200 |