From 7410c3be6f31d566451caca8650d8f4adea67273 Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Fri, 23 Jun 2023 17:44:21 +0200 Subject: [PATCH] [ticket/17010] Generate VAPID keys with javascript in ACP PHPBB3-17010 --- phpBB/adm/style/ajax.js | 62 +++++++++++++++++++++++++++++ phpBB/includes/acp/acp_board.php | 68 +++++++++++++++++++++----------- phpBB/language/en/acp/board.php | 1 + 3 files changed, 109 insertions(+), 22 deletions(-) diff --git a/phpBB/adm/style/ajax.js b/phpBB/adm/style/ajax.js index 5949c73920..25a6527481 100644 --- a/phpBB/adm/style/ajax.js +++ b/phpBB/adm/style/ajax.js @@ -157,6 +157,68 @@ phpbb.addAjaxCallback('row_delete', function(res) { } }); +/** + * This callback generates the VAPID keys for the web push notification service. + */ +phpbb.addAjaxCallback('generate_vapid_keys', (res) => { + function rawKeyToBase64(rawKey) { + const keyBuffer = new Uint8Array(rawKey); + let keyText = ''; + const keyLength = keyBuffer.byteLength; + for (let i = 0; i < keyLength; i++) { + keyText += String.fromCharCode(keyBuffer[i]); + } + + keyText = window.btoa(keyText); + return keyText; + } + + function base64SafeEncode(base64String) { + const base64URL = base64String.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); + return base64URL; + } + + async function generateVAPIDKeys() { + try { + // Generate a new key pair using the Subtle Crypto API + const keyPair = await crypto.subtle.generateKey( + { + name: 'ECDH', + namedCurve: 'P-256', + }, + true, + ['deriveKey', 'deriveBits'] + ); + + // Export the private key as a JWK (JSON Web Key) object + const privateKeyJwk = await crypto.subtle.exportKey('jwk', keyPair.privateKey); + console.log(privateKeyJwk.d); + + const privateKeyString = privateKeyJwk.d; + + // Export the public key as a JWK object + const publicKeyBuffer = await crypto.subtle.exportKey('raw', keyPair.publicKey); + const publicKeyString = base64SafeEncode(rawKeyToBase64(publicKeyBuffer)); + console.log(publicKeyString); + + return { + privateKey: privateKeyString, + publicKey: publicKeyString + }; + } catch (error) { + console.error('Error generating private key:', error); + return null; + } + } + + generateVAPIDKeys().then(keyPair => { + const publicKeyInput = document.querySelector('#webpush_vapid_public'); + const privateKeyInput = document.querySelector('#webpush_vapid_private'); + publicKeyInput.value = keyPair.publicKey; + privateKeyInput.value = keyPair.privateKey; + }) +}) + /** * Handler for submitting permissions form in chunks * This call will submit permissions forms in chunks of 5 fieldsets. diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php index ceb7f47d58..d0ced6788f 100644 --- a/phpBB/includes/acp/acp_board.php +++ b/phpBB/includes/acp/acp_board.php @@ -491,7 +491,7 @@ class acp_board 'title' => 'ACP_WEBPUSH_SETTINGS', 'vars' => [ 'legend1' => 'GENERAL_SETTINGS', - 'webpush_enable' => ['lang' => 'WEBPUSH_ENABLE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true], + 'webpush_enable' => ['lang' => 'WEBPUSH_ENABLE', 'validate' => 'bool', 'type' => 'custom', 'method' => 'webpush_enable', 'explain' => true], 'webpush_vapid_public' => ['lang' => 'WEBPUSH_VAPID_PUBLIC', 'validate' => 'string', 'type' => 'text:25:255', 'explain' => true], 'webpush_vapid_private' => ['lang' => 'WEBPUSH_VAPID_PRIVATE', 'validate' => 'string', 'type' => 'password:25:255', 'explain' => true], @@ -539,27 +539,6 @@ class acp_board } } - if ($mode == 'webpush') - { - // Create VAPID keys if keys are empty and web push is enabled - if ($submit && $cfg_array['webpush_enable'] && $cfg_array['webpush_enable'] != $config['webpush_enable'] - && empty($cfg_array['webpush_vapid_public']) && empty($cfg_array['webpush_vapid_private']) - && empty($config['webpush_vapid_public']) && empty($config['webpush_vapid_private'])) - { - try - { - $vapid_keys = VAPID::createVapidKeys(); - $cfg_array['webpush_vapid_public'] = $vapid_keys['publicKey']; - $cfg_array['webpush_vapid_private'] = $vapid_keys['privateKey']; - } - catch (\ErrorException $exception) - { - // Nothing we can do about this, user will have to follow the - // documentation and manually create these. - } - } - } - // We validate the complete config if wished validate_config_vars($display_vars['vars'], $cfg_array, $error); @@ -1383,4 +1362,49 @@ class acp_board return ' '; } + + /** + * Generate form data for web push enable + * + * @param string $value Webpush enable value + * @param string $key Webpush enable config key + * + * @return array[] Form data + */ + public function webpush_enable($value, $key): array + { + return [ + [ + 'tag' => 'radio', + 'buttons' => [ + [ + 'name' => "config[$key]", + 'label' => $this->language->lang('YES'), + 'type' => 'radio', + 'class' => 'radio', + 'value' => 1, + 'checked' => $value, + ], + [ + 'name' => "config[$key]", + 'label' => $this->language->lang('NO'), + 'type' => 'radio', + 'class' => 'radio', + 'value' => 0, + 'checked' => !$value, + ], + ], + ], + [ + 'tag' => 'input', + 'class' => 'button2', + 'name' => "config[$key]", + 'type' => 'button', + 'value' => $this->language->lang('WEBPUSH_GENERATE_VAPID_KEYS'), + 'data' => [ + 'ajax' => 'generate_vapid_keys', + ] + ], + ]; + } } diff --git a/phpBB/language/en/acp/board.php b/phpBB/language/en/acp/board.php index 8fe9f832f2..d2905d94e8 100644 --- a/phpBB/language/en/acp/board.php +++ b/phpBB/language/en/acp/board.php @@ -603,6 +603,7 @@ $lang = array_merge($lang, [ 'ACP_WEBPUSH_SETTINGS_EXPLAIN' => 'Here you can enable and control the use of Webpush for board notifications. Webpush is a simple protocol for the delivery of real-time events to user agents, more commonly known as push messages. It is supported by most modern browsers on desktop and mobile devices.', 'WEBPUSH_ENABLE' => 'Enable Webpush', 'WEBPUSH_ENABLE_EXPLAIN' => 'Allow receiving notifications via Webpush.
Note: If VAPID keys have not been set, phpBB will try to automatically create them when enabling Webpush.', + 'WEBPUSH_GENERATE_VAPID_KEYS' => 'Generate VAPID keys', 'WEBPUSH_VAPID_PUBLIC' => 'VAPID public key', 'WEBPUSH_VAPID_PUBLIC_EXPLAIN' => 'The VAPID public key will be shared to authenticate push messages sent by your site.
Warning: Changing the VAPID public key will automatically invalidate all webpush subscriptions.', 'WEBPUSH_VAPID_PRIVATE' => 'VAPID private key',