[ticket/17010] Generate VAPID keys with javascript in ACP

PHPBB3-17010
This commit is contained in:
Marc Alexander 2023-06-23 17:44:21 +02:00
parent 3513c85ee6
commit 7410c3be6f
No known key found for this signature in database
GPG key ID: 50E0D2423696F995
3 changed files with 109 additions and 22 deletions

View file

@ -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.

View file

@ -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 '<input class="button2" type="submit" id="' . $key . '" name="' . $key . '" value="' . $user->lang('SEND_TEST_EMAIL') . '" />
<textarea id="' . $key . '_text" name="' . $key . '_text" placeholder="' . $user->lang('MESSAGE') . '"></textarea>';
}
/**
* 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',
]
],
];
}
}

View file

@ -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.<br><em><strong>Note:</strong></em> 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.<br><em><strong>Warning:</strong> Changing the VAPID public key will automatically invalidate all webpush subscriptions.</em>',
'WEBPUSH_VAPID_PRIVATE' => 'VAPID private key',