Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/notifications.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoas Schilling <213943+nickvergessen@users.noreply.github.com>2021-10-20 17:36:20 +0300
committerGitHub <noreply@github.com>2021-10-20 17:36:20 +0300
commit3212b38ea9b445b34d0c6ae1f221bdfed36e9a08 (patch)
tree5dfe33e81677838356270de51edce6617a34d8d1
parentfa22583a7822593965c8a0b587d45980b51241ee (diff)
parent7ab9500d70bd69a4a1e6cb3a924e37b25cd46f73 (diff)
Merge pull request #1097 from nextcloud/backport/1094/stable20
[stable20] Add integration tests for push registration
-rw-r--r--lib/Controller/PushController.php2
-rw-r--r--tests/Integration/features/bootstrap/FeatureContext.php109
-rw-r--r--tests/Integration/features/push-registration.feature64
-rw-r--r--tests/Unit/Controller/PushControllerTest.php4
4 files changed, 172 insertions, 7 deletions
diff --git a/lib/Controller/PushController.php b/lib/Controller/PushController.php
index c1caae9..f1b20a0 100644
--- a/lib/Controller/PushController.php
+++ b/lib/Controller/PushController.php
@@ -118,8 +118,8 @@ class PushController extends OCSController {
$key = $this->identityProof->getKey($user);
$deviceIdentifier = json_encode([$user->getCloudId(), $token->getId()]);
- openssl_sign($deviceIdentifier, $signature, $key->getPrivate(), OPENSSL_ALGO_SHA512);
$deviceIdentifier = base64_encode(hash('sha512', $deviceIdentifier, true));
+ openssl_sign($deviceIdentifier, $signature, $key->getPrivate(), OPENSSL_ALGO_SHA512);
$appType = 'unknown';
if ($this->request->isUserAgent([
diff --git a/tests/Integration/features/bootstrap/FeatureContext.php b/tests/Integration/features/bootstrap/FeatureContext.php
index 893d470..b6e42c6 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.
*/
@@ -222,6 +228,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
@@ -347,15 +446,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
diff --git a/tests/Unit/Controller/PushControllerTest.php b/tests/Unit/Controller/PushControllerTest.php
index 9c84da2..3ac462f 100644
--- a/tests/Unit/Controller/PushControllerTest.php
+++ b/tests/Unit/Controller/PushControllerTest.php
@@ -302,7 +302,7 @@ FwIDAQAB
[
'publicKey' => $this->userPublicKey,
'deviceIdentifier' => 'XUCEZ1EHvTUcVhIvrQQQ1XcP0ZD2BFdFqw4EYbOhBfiEgXgirurR4x/ve4GSSyfivvbQOdOkZUM+g4m+tSb0Ew==',
- 'signature' => 'LRhbXO71WYX9qqDbQX7C+87YaaFfWoT/vG0DlaXdBz6+lhyOA0dw/1Ggz3fd7RerCQ0MfgnnTyxO+cSeRpUaPdA2yPjfoiPpfYA5SOJQGF3comS/HYna3fHiFDbOoM3BJOnjvqiSZdxA/ICdyl2mEEC5wO7AZ4OZKBTa5XfL7eSCXZLEv1YldqcLOStbXrI7voDQocTMJxoQZI/j8BVcf2i3D6F454aXIFDrYYzC2PQY+CKJoXZW0m0RMWaTM2B8tBmFFwrmaGLDqcjjpd33TsTtsV5DB7WimffLBPpOuGV4Z1Kiagp/mxpPLz2NImNV79mDX9gY3ZppCZTwChP5qQ==',
+ 'signature' => 'X9+J7NNLfG9Ft6C36zrYLVJ5aH5euIROzdV937hsU81jL7WvOwzBfc7bImzxU3Bnev5wEKwkw7Ts/2q/+UUkOxgtEZinp52s87S5obKtsVXsczHbsqg4p/ueoBPhF17VsP1e8kMtxZ4snk/iArX4Eu1cfaM3+OckmpO0MYXy0rUbYpQPAJo4VgRFKKjFvfEVOj8N74DTIJ+TjRsvvDhJbb9KpeFe3a6Rv9mIo0AqoK+deAbUkWY0aM+74noVXvPtNzExgK4mWJ02+JHEuQEUbCuQsgoBia0vC3fILbwVxHzrieWGEnE7vkRyFEzlkeo7ZSMawDPxsPN5HxwBs2SZig==',
],
Http::STATUS_CREATED,
],
@@ -317,7 +317,7 @@ FwIDAQAB
[
'publicKey' => $this->userPublicKey,
'deviceIdentifier' => 'x9vSImcGjhzR9BfZ/XbbUqqCCNC4bHKsX7vkQWNZRd1/MiY+OuF02fx8K08My0RpkNnwj/rQ/gVSU1oEdFwkww==',
- 'signature' => 'J9AcdJt5youJmMnBhS+Cc9ytArynIKtCRoNf/m0oOFO/e0hWHqs1NRdQBe81qzYIjf0+bj0Q97X9Xv1rnVJesPkQUbGaa4nAPt+viGSfvzTptjX4LKgqm8B3UkduBA262IcaWgM5P84gUqelkQIC1nIqq/MJTuC6oQ5lUwIV1a92ZurDjhwH4b3f7/ZLTTOTRD0DWN9W/yOyF1qECivgePR3eu+mkcBzXVU/TDZDJic9G7xhqcTnWV6qk+aKyzdNo1tu5W7mF+v5vF6rrGZrq55vPLWAHApTD7P+NFV01BnaCuN7/qGJNVs7m7EH03jpOw7y3jqNMmcmonYrJSMVqg==',
+ 'signature' => 'GFpnv3MO7mcBef2RJ4Ayrl6RQakGM7AvlKhoTr3DUWnv+iBzwGy8YV34HIPoArz4tyqonHRlLsxPYq4ENPfGO99KrIS16z4RUq0wiCBGf+S8/K8lM9cE9EBKE9yrkTsSvZGICEusvxQ+cTfVr30bnavvi1wL1UuxxDBlJebda9FJ9HfaS24j4rT7K78oMguqDVM+4hhr6BMhcpUVV+kTpOaBpluw5pRDwUP3jJBmkkOa57WRKFcu0Lr/XIx/G0c8Si+BAfM//CTMstwp5XDFn4W9EYSStjNrvsULdV+tOKFwnowqts+UFzEDvmZ1g4qIMWUUPBF4/pjaiDqtMojgrA==',
],
Http::STATUS_OK,
],