Fix false short URL integrity warning

This commit is contained in:
Alexander Schmidt
2026-03-26 13:22:34 +01:00
parent 09a5ef703c
commit f6edc4cb58
2 changed files with 8 additions and 35 deletions

35
app.js
View File

@@ -400,7 +400,7 @@
return true; return true;
} }
// Verify that short URL has not been tampered with by checking HMAC signature // Verify that the redirected hash still matches the stored short URL mapping.
function verifyShortUrlIntegrity(code, currentHash) { function verifyShortUrlIntegrity(code, currentHash) {
fetch('/api/check-short.php?code=' + encodeURIComponent(code)) fetch('/api/check-short.php?code=' + encodeURIComponent(code))
.then(function (res) { .then(function (res) {
@@ -408,47 +408,20 @@
return res.json(); return res.json();
}) })
.then(function (data) { .then(function (data) {
if (!data.signature) { if (!data.hash) {
// Old format without signature - no integrity check
return; return;
} }
// Verify HMAC signature client-side if (data.hash !== currentHash) {
verifyHmacSignature(data.hash, data.signature).then(function (valid) { console.warn('xmrpay: Short URL hash mismatch detected for code', code);
if (!valid) {
console.warn('xmrpay: Hash signature mismatch - possible server tampering detected');
showToast(I18n.t('toast_integrity_warning')); showToast(I18n.t('toast_integrity_warning'));
} }
});
}) })
.catch(function (e) { .catch(function (e) {
console.warn('xmrpay: Could not verify short URL integrity:', e); console.warn('xmrpay: Could not verify short URL integrity:', e);
}); });
} }
// Client-side HMAC-SHA256 verification
async function verifyHmacSignature(hash, expectedSignature) {
try {
// Use hostname as part of the secret (same as server-side)
const secret = await crypto.subtle.digest('SHA-256',
new TextEncoder().encode(location.hostname + 'xmrpay.link'));
const key = await crypto.subtle.importKey('raw', secret,
{ name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
const signature = await crypto.subtle.sign('HMAC', key,
new TextEncoder().encode(hash));
// Convert to hex string
const sigHex = Array.from(new Uint8Array(signature))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
return sigHex === expectedSignature;
} catch (e) {
console.warn('xmrpay: HMAC verification failed:', e);
return false;
}
}
function buildSummary(xmrAmount, desc, days) { function buildSummary(xmrAmount, desc, days) {
var html = ''; var html = '';
if (xmrAmount) { if (xmrAmount) {

2
app.min.js vendored

File diff suppressed because one or more lines are too long