diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php index adb896100..81b02b287 100644 --- a/lib/Controller/SettingsController.php +++ b/lib/Controller/SettingsController.php @@ -61,16 +61,18 @@ public function personal(int $batchSetting, string $soundNotification, string $s * @param int $batchSetting How often E-mails about missed notifications should be sent (hourly: 1; every three hours: 2; daily: 3; weekly: 4) * @param string $soundNotification Enable sound for notifications ('yes' or 'no') * @param string $soundTalk Enable sound for Talk notifications ('yes' or 'no') + * @param string $webpushEnabled Enable web push notifications ('yes' or 'no') * @return DataResponse, array{}> * * 200: Admin settings updated */ #[OpenAPI(scope: OpenAPI::SCOPE_ADMINISTRATION)] #[ApiRoute(verb: 'POST', url: '/api/{apiVersion}/settings/admin', requirements: ['apiVersion' => '(v2)'])] - public function admin(int $batchSetting, string $soundNotification, string $soundTalk): DataResponse { + public function admin(int $batchSetting, string $soundNotification, string $soundTalk, string $webpushEnabled): DataResponse { $this->appConfig->setAppValueInt('setting_batchtime', $batchSetting); $this->appConfig->setAppValueBool('sound_notification', $soundNotification === 'yes'); $this->appConfig->setAppValueBool('sound_talk', $soundTalk === 'yes'); + $this->appConfig->setAppValueBool('webpush_enabled', $webpushEnabled === 'yes'); return new DataResponse(); } diff --git a/lib/Controller/WebPushController.php b/lib/Controller/WebPushController.php index a93a3796e..cc2c5bc6b 100644 --- a/lib/Controller/WebPushController.php +++ b/lib/Controller/WebPushController.php @@ -78,16 +78,21 @@ public function getVapid(): DataResponse { * @param string $uaPublicKey Public key of the device, uncompress base64url encoded (RFC8291) * @param string $auth Authentication tag, base64url encoded (RFC8291) * @param string $appTypes comma seperated list of types used to filter incoming notifications - appTypes are alphanum - use "all" to get all notifications, prefix with `-` to exclude (eg. 'all,-talk') - * @return DataResponse, array{}>|DataResponse + * @return DataResponse, array{}>|DataResponse * * 200: A subscription was already registered and activated * 201: New subscription registered successfully * 400: Registering is not possible * 401: Missing permissions to register + * 403: Web push is disabled by the administrator */ #[NoAdminRequired] #[ApiRoute(verb: 'POST', url: '/api/{apiVersion}/webpush', requirements: ['apiVersion' => '(v2)'])] public function registerWP(string $endpoint, string $uaPublicKey, string $auth, string $appTypes): DataResponse { + if (!$this->appConfig->getAppValueBool('webpush_enabled')) { + return new DataResponse(['message' => 'WEBPUSH_DISABLED'], Http::STATUS_FORBIDDEN); + } + $user = $this->userSession->getUser(); if (!$user instanceof IUser) { return new DataResponse([], Http::STATUS_UNAUTHORIZED); @@ -142,17 +147,22 @@ public function registerWP(string $endpoint, string $uaPublicKey, string $auth, * Activate subscription for push notifications * * @param string $activationToken Random token sent via a push notification during registration to enable the subscription - * @return DataResponse, array{}>|DataResponse + * @return DataResponse, array{}>|DataResponse * * 200: Subscription was already activated * 202: Subscription activated successfully * 400: Activating subscription is not possible, may be because of a wrong activation token * 401: Missing permissions to activate subscription + * 403: Web push is disabled by the administrator * 404: No subscription found for the device */ #[NoAdminRequired] #[ApiRoute(verb: 'POST', url: '/api/{apiVersion}/webpush/activate', requirements: ['apiVersion' => '(v2)'])] public function activateWP(string $activationToken): DataResponse { + if (!$this->appConfig->getAppValueBool('webpush_enabled')) { + return new DataResponse(['message' => 'WEBPUSH_DISABLED'], Http::STATUS_FORBIDDEN); + } + $user = $this->userSession->getUser(); if (!$user instanceof IUser) { return new DataResponse([], Http::STATUS_UNAUTHORIZED); diff --git a/lib/Push.php b/lib/Push.php index 80d7f47b8..637dbbaae 100644 --- a/lib/Push.php +++ b/lib/Push.php @@ -1048,6 +1048,10 @@ protected function getProxyDevicesForUsers(array $userIds): array { * @return list */ protected function getWebPushDevicesForUser(string $uid): array { + if (!$this->appConfig->getAppValueBool('webpush_enabled')) { + return []; + } + $query = $this->db->getQueryBuilder(); $query->select('*') ->from('notifications_webpush') @@ -1066,6 +1070,10 @@ protected function getWebPushDevicesForUser(string $uid): array { * @return array> */ protected function getWebPushDevicesForUsers(array $userIds): array { + if (!$this->appConfig->getAppValueBool('webpush_enabled')) { + return []; + } + $query = $this->db->getQueryBuilder(); $query->select('*') ->from('notifications_webpush') diff --git a/lib/Settings/Admin.php b/lib/Settings/Admin.php index 2c9bb31d3..4c25a3d02 100644 --- a/lib/Settings/Admin.php +++ b/lib/Settings/Admin.php @@ -31,6 +31,7 @@ public function getForm(): TemplateResponse { $defaultSoundNotification = $this->appConfig->getAppValueBool('sound_notification'); $defaultSoundTalk = $this->appConfig->getAppValueBool('sound_talk'); $defaultBatchtime = $this->appConfig->getAppValueInt('setting_batchtime'); + $webpushEnabled = $this->appConfig->getAppValueBool('webpush_enabled'); if ($defaultBatchtime !== Settings::EMAIL_SEND_WEEKLY && $defaultBatchtime !== Settings::EMAIL_SEND_DAILY @@ -45,6 +46,7 @@ public function getForm(): TemplateResponse { 'setting_batchtime' => $defaultBatchtime, 'sound_notification' => $defaultSoundNotification, 'sound_talk' => $defaultSoundTalk, + 'webpush_enabled' => $webpushEnabled, ]); return new TemplateResponse('notifications', 'settings/admin'); diff --git a/src/views/AdminSettings.vue b/src/views/AdminSettings.vue index 3147494a7..6f6e063e8 100644 --- a/src/views/AdminSettings.vue +++ b/src/views/AdminSettings.vue @@ -23,14 +23,33 @@ {{ t('notifications', 'Play sound when a new notification arrives') }} {{ t('notifications', 'Play sound when a call started (requires Nextcloud Talk)') }} + +

{{ t('notifications', 'Web push settings') }}

+ + {{ t('notifications', 'Web push notifications are encrypted but routed through services provided by Microsoft, Apple, and Google. While the content is protected, metadata such as timing and frequency of notifications may be exposed to these providers.') }} + + + {{ t('notifications', 'Enable web push notifications') }} + + + {{ t('notifications', 'Enable web push notifications') }} + @@ -40,8 +59,10 @@ import { showError, showSuccess } from '@nextcloud/dialogs' import { loadState } from '@nextcloud/initial-state' import { t } from '@nextcloud/l10n' import { generateOcsUrl } from '@nextcloud/router' -import { computed, reactive } from 'vue' +import { computed, reactive, ref } from 'vue' +import NcButton from '@nextcloud/vue/components/NcButton' import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch' +import NcNoteCard from '@nextcloud/vue/components/NcNoteCard' import NcSelect from '@nextcloud/vue/components/NcSelect' import NcSettingsSection from '@nextcloud/vue/components/NcSettingsSection' @@ -64,13 +85,16 @@ const BATCHTIME_OPTIONS = [ export default { name: 'AdminSettings', components: { - NcSelect, + NcButton, NcCheckboxRadioSwitch, + NcNoteCard, + NcSelect, NcSettingsSection, }, setup() { const config = reactive(loadState('notifications', 'config', {})) + const showWebpushSwitch = ref(config.webpush_enabled) const currentBatchTime = computed({ get() { @@ -85,6 +109,7 @@ export default { BATCHTIME_OPTIONS, config, currentBatchTime, + showWebpushSwitch, } }, @@ -97,6 +122,7 @@ export default { form.append('batchSetting', this.config.setting_batchtime) form.append('soundNotification', this.config.sound_notification ? 'yes' : 'no') form.append('soundTalk', this.config.sound_talk ? 'yes' : 'no') + form.append('webpushEnabled', this.config.webpush_enabled ? 'yes' : 'no') await axios.post(generateOcsUrl('apps/notifications/api/v2/settings/admin'), form) showSuccess(t('notifications', 'Your settings have been updated.')) } catch (error) { diff --git a/src/views/UserSettings.vue b/src/views/UserSettings.vue index c22140cd8..241fdb3a4 100644 --- a/src/views/UserSettings.vue +++ b/src/views/UserSettings.vue @@ -24,11 +24,13 @@ {{ t('notifications', 'Play sound when a new notification arrives') }} {{ t('notifications', 'Play sound when a call started (requires Nextcloud Talk)') }} @@ -36,7 +38,7 @@