From 1d74130a4a074ba93ef47deb3d19c12c7c3c1339 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Tue, 19 Oct 2021 17:01:26 +0200 Subject: [PATCH] Fair use of push notifications We want to keep offering our push notification service for free, but large users overload our infrastructure. For this reason we have to rate-limit the use of push notifications. If you need this feature, consider setting up your own push server or using Nextcloud Enterprise. Signed-off-by: Joas Schilling --- lib/Command/TestPush.php | 8 ++++ lib/Push.php | 10 +++++ tests/Unit/PushTest.php | 83 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+) diff --git a/lib/Command/TestPush.php b/lib/Command/TestPush.php index 11ca7ebc3..d4533a394 100644 --- a/lib/Command/TestPush.php +++ b/lib/Command/TestPush.php @@ -85,6 +85,14 @@ protected function configure(): void { * @return int */ protected function execute(InputInterface $input, OutputInterface $output): int { + if (!$this->notificationManager->isFairUseOfFreePushService()) { + $output->writeln('We want to keep offering our push notification service for free, but large'); + $output->writeln('users overload our infrastructure. For this reason we have to rate-limit the'); + $output->writeln('use of push notifications. If you need this feature, consider setting up your'); + $output->writeln('own push server or using Nextcloud Enterprise.'); + return 1; + } + $userId = $input->getArgument('user-id'); $subject = 'Testing push notifications'; diff --git a/lib/Push.php b/lib/Push.php index af3d0a250..1405297c7 100644 --- a/lib/Push.php +++ b/lib/Push.php @@ -295,6 +295,16 @@ protected function sendNotificationsToProxies(): void { return; } + if (!$this->notificationManager->isFairUseOfFreePushService()) { + /** + * We want to keep offering our push notification service for free, but large + * users overload our infrastructure. For this reason we have to rate-limit the + * use of push notifications. If you need this feature, consider setting up your + * own push server or using Nextcloud Enterprise. + */ + return; + } + $client = $this->clientService->newClient(); foreach ($pushNotifications as $proxyServer => $notifications) { try { diff --git a/tests/Unit/PushTest.php b/tests/Unit/PushTest.php index 22eb846b0..118ee9193 100644 --- a/tests/Unit/PushTest.php +++ b/tests/Unit/PushTest.php @@ -394,6 +394,83 @@ public function testPushToDeviceEncryptionError() { $push->pushToDevice(1970, $notification); } + public function testPushToDeviceNoFairUse() { + $push = $this->getPush(['getDevicesForUser', 'encryptAndSign', 'deletePushToken', 'validateToken', 'deletePushTokenByDeviceIdentifier']); + + /** @var INotification|MockObject $notification */ + $notification = $this->createMock(INotification::class); + $notification + ->method('getUser') + ->willReturn('valid'); + + /** @var IUser|MockObject $user */ + $user = $this->createMock(IUser::class); + + $this->userManager->expects($this->once()) + ->method('get') + ->with('valid') + ->willReturn($user); + + $push->expects($this->once()) + ->method('getDevicesForUser') + ->willReturn([ + [ + 'proxyserver' => 'proxyserver', + 'token' => 16, + 'apptype' => 'other', + ], + ]); + + $this->config + ->method('getSystemValue') + ->with('debug', false) + ->willReturn(false); + + $this->l10nFactory + ->method('getUserLanguage') + ->with($user) + ->willReturn('ru'); + + $this->notificationManager->expects($this->once()) + ->method('prepare') + ->with($notification, 'ru') + ->willReturnArgument(0); + + /** @var Key|MockObject $key */ + $key = $this->createMock(Key::class); + + $this->keyManager->expects($this->once()) + ->method('getKey') + ->with($user) + ->willReturn($key); + + $push->expects($this->exactly(1)) + ->method('validateToken') + ->willReturn(true); + + $push->expects($this->exactly(1)) + ->method('encryptAndSign') + ->willReturn(['Payload']); + + $push->expects($this->never()) + ->method('deletePushToken'); + + $this->clientService->expects($this->never()) + ->method('newClient'); + + $this->config->expects($this->once()) + ->method('getSystemValueBool') + ->with('has_internet_connection', true) + ->willReturn(true); + + $this->notificationManager->method('isFairUseOfFreePushService') + ->willReturn(false); + + $push->method('deletePushTokenByDeviceIdentifier') + ->with('123456'); + + $push->pushToDevice(207787, $notification); + } public function dataPushToDeviceSending() { return [ @@ -631,6 +708,9 @@ public function testPushToDeviceSending($isDebug) { ]) ->willThrowException($e); + $this->notificationManager->method('isFairUseOfFreePushService') + ->willReturn(true); + $push->method('deletePushTokenByDeviceIdentifier') ->with('123456'); @@ -762,6 +842,9 @@ public function testPushToDeviceTalkNotification(array $deviceTypes, $isTalkNoti ->with('has_internet_connection', true) ->willReturn(true); + $this->notificationManager->method('isFairUseOfFreePushService') + ->willReturn(true); + $push->pushToDevice(200718, $notification); } }