mirror of
https://github.com/phpbb/phpbb.git
synced 2025-06-08 04:18:52 +00:00
[ticket/17339] Support receiving push notifications if not logged in
PHPBB-17339
This commit is contained in:
parent
e2ff7a7178
commit
d66d4a0c6a
4 changed files with 143 additions and 6 deletions
53
phpBB/phpbb/db/migration/data/v400/add_webpush_token.php
Normal file
53
phpBB/phpbb/db/migration/data/v400/add_webpush_token.php
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\migration\data\v400;
|
||||
|
||||
use phpbb\db\migration\migration;
|
||||
|
||||
class add_webpush_token extends migration
|
||||
{
|
||||
public static function depends_on(): array
|
||||
{
|
||||
return [
|
||||
'\phpbb\db\migration\data\v400\add_webpush',
|
||||
];
|
||||
}
|
||||
|
||||
public function effectively_installed(): bool
|
||||
{
|
||||
return $this->db_tools->sql_column_exists($this->table_prefix . 'notification_push', 'push_token');
|
||||
}
|
||||
|
||||
public function update_schema(): array
|
||||
{
|
||||
return [
|
||||
'add_columns' => [
|
||||
$this->table_prefix . 'notification_push' => [
|
||||
'push_token' => ['VCHAR', ''],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function revert_schema(): array
|
||||
{
|
||||
return [
|
||||
'drop_columns' => [
|
||||
$this->table_prefix . 'notification_push' => [
|
||||
'push_token',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -51,6 +51,9 @@ class webpush extends messenger_base implements extended_method_interface
|
|||
/** @var int Fallback size for padding if endpoint is mozilla, see https://github.com/web-push-libs/web-push-php/issues/108#issuecomment-2133477054 */
|
||||
const MOZILLA_FALLBACK_PADDING = 2820;
|
||||
|
||||
/** @var array Map for storing push token between db insertion and sending of notifications */
|
||||
private array $push_token_map = [];
|
||||
|
||||
/**
|
||||
* Notification Method Web Push constructor
|
||||
*
|
||||
|
@ -145,9 +148,11 @@ class webpush extends messenger_base implements extended_method_interface
|
|||
'avatar' => $notification->get_avatar(),
|
||||
]),
|
||||
'notification_time' => time(),
|
||||
'push_token' => hash('sha256', random_bytes(32))
|
||||
];
|
||||
$data = self::clean_data($data);
|
||||
$insert_buffer->insert($data);
|
||||
$this->push_token_map[$notification->notification_type_id][$notification->item_id] = $data['push_token'];
|
||||
}
|
||||
|
||||
$insert_buffer->flush();
|
||||
|
@ -221,7 +226,9 @@ class webpush extends messenger_base implements extended_method_interface
|
|||
$data = [
|
||||
'item_id' => $notification->item_id,
|
||||
'type_id' => $notification->notification_type_id,
|
||||
'user_id' => $notification->user_id,
|
||||
'version' => $this->config['assets_version'],
|
||||
'token' => hash('sha256', $user['user_form_salt'] . $this->push_token_map[$notification->notification_type_id][$notification->item_id]),
|
||||
];
|
||||
$json_data = json_encode($data);
|
||||
|
||||
|
@ -337,6 +344,7 @@ class webpush extends messenger_base implements extended_method_interface
|
|||
'item_parent_id' => null,
|
||||
'user_id' => null,
|
||||
'push_data' => null,
|
||||
'push_token' => null,
|
||||
'notification_time' => null,
|
||||
];
|
||||
|
||||
|
|
|
@ -100,10 +100,37 @@ class webpush
|
|||
* @return JsonResponse
|
||||
*/
|
||||
public function notification(): JsonResponse
|
||||
{
|
||||
if (!$this->request->is_ajax() || $this->user->data['is_bot'] || $this->user->data['user_type'] == USER_INACTIVE)
|
||||
{
|
||||
throw new http_exception(Response::HTTP_FORBIDDEN, 'Forbidden');
|
||||
}
|
||||
|
||||
if ($this->user->id() !== ANONYMOUS)
|
||||
{
|
||||
$notification_data = $this->get_user_notifications();
|
||||
}
|
||||
else
|
||||
{
|
||||
$notification_data = $this->get_anonymous_notifications();
|
||||
}
|
||||
|
||||
// Decode and return data if everything is fine
|
||||
$data = json_decode($notification_data, true);
|
||||
$data['url'] = isset($data['url']) ? $this->path_helper->update_web_root_path($data['url']) : '';
|
||||
|
||||
return new JsonResponse($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notification data for logged in user
|
||||
*
|
||||
* @return string Notification data
|
||||
*/
|
||||
private function get_user_notifications(): string
|
||||
{
|
||||
// Subscribe should only be available for logged-in "normal" users
|
||||
if (!$this->request->is_ajax() || $this->user->id() == ANONYMOUS || $this->user->data['is_bot']
|
||||
|| $this->user->data['user_type'] == USER_IGNORE || $this->user->data['user_type'] == USER_INACTIVE)
|
||||
if ($this->user->data['user_type'] == USER_IGNORE)
|
||||
{
|
||||
throw new http_exception(Response::HTTP_FORBIDDEN, 'Forbidden');
|
||||
}
|
||||
|
@ -119,10 +146,53 @@ class webpush
|
|||
$result = $this->db->sql_query($sql);
|
||||
$notification_data = $this->db->sql_fetchfield('push_data');
|
||||
$this->db->sql_freeresult($result);
|
||||
$data = json_decode($notification_data, true);
|
||||
$data['url'] = isset($data['url']) ? $this->path_helper->update_web_root_path($data['url']) : '';
|
||||
|
||||
return new JsonResponse($data);
|
||||
return $notification_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notification data for not logged in user via token
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_anonymous_notifications(): string
|
||||
{
|
||||
$token = $this->request->variable('token', '');
|
||||
|
||||
if ($token)
|
||||
{
|
||||
$item_id = $this->request->variable('item_id', 0);
|
||||
$type_id = $this->request->variable('type_id', 0);
|
||||
$user_id = $this->request->variable('user_id', 0);
|
||||
|
||||
$sql = 'SELECT push_data, push_token
|
||||
FROM ' . $this->notification_webpush_table . '
|
||||
WHERE user_id = ' . (int) $user_id . '
|
||||
AND notification_type_id = ' . (int) $type_id . '
|
||||
AND item_id = ' . (int) $item_id;
|
||||
$result = $this->db->sql_query($sql);
|
||||
$notification_row = $this->db->sql_fetchrow($result);
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
$notification_data = $notification_row['push_data'];
|
||||
$push_token = $notification_row['push_token'];
|
||||
|
||||
// Check if passed push token is valid
|
||||
$sql = 'SELECT user_form_salt
|
||||
FROM ' . USERS_TABLE . '
|
||||
WHERE user_id = ' . (int) $user_id;
|
||||
$result = $this->db->sql_query($sql);
|
||||
$user_form_token = $this->db->sql_fetchfield('user_form_salt');
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
$expected_push_token = hash('sha256', $user_form_token . $push_token);
|
||||
if ($expected_push_token === $token)
|
||||
{
|
||||
return $notification_data;
|
||||
}
|
||||
}
|
||||
|
||||
throw new http_exception(Response::HTTP_FORBIDDEN, 'Forbidden');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -23,12 +23,16 @@ self.addEventListener('push', event => {
|
|||
|
||||
let itemId = 0;
|
||||
let typeId = 0;
|
||||
let notificationVersion = 5;
|
||||
let userId = 0;
|
||||
let notificationVersion = 0;
|
||||
let pushToken = '';
|
||||
try {
|
||||
const notificationData = event.data.json();
|
||||
itemId = notificationData.item_id;
|
||||
typeId = notificationData.type_id;
|
||||
userId = notificationData.user_id;
|
||||
notificationVersion = parseInt(notificationData.version, 10);
|
||||
pushToken = notificationData.token;
|
||||
} catch {
|
||||
self.registration.showNotification(event.data.text());
|
||||
return;
|
||||
|
@ -45,6 +49,8 @@ self.addEventListener('push', event => {
|
|||
const formData = new FormData();
|
||||
formData.append('item_id', itemId.toString(10));
|
||||
formData.append('type_id', typeId.toString(10));
|
||||
formData.append('user_id', userId.toString(10));
|
||||
formData.append('token', pushToken);
|
||||
|
||||
fetch(getNotificationUrl, {
|
||||
method: 'POST',
|
||||
|
|
Loading…
Add table
Reference in a new issue