Add modern QR code library and update crypto checkout template

- Replace old insecure qrcodejs (v1.0.0 from 2013) with QRious v4.0.2 (2017)
- Update crypto checkout template to use QRious API instead of old QRCode.js
- QRious uses canvas element and modern security practices
This commit is contained in:
Russell Ballestrini 2025-09-24 11:40:20 -04:00
parent 5dc9b0d1bb
commit 93b807aab9
2 changed files with 60 additions and 3 deletions

File diff suppressed because one or more lines are too long

View file

@ -11,9 +11,16 @@
{% else %}
{% set amount_fmt = '%.8f' % amount_crypto %}
{% endif %}
<p>Send exactly <b id="crypto-amount">{{ amount_fmt }}</b> {{ coin_symbol }} to this address:</p>
<pre id="crypto-address" style="white-space:pre-wrap;word-wrap:break-word;">{{ address }}</pre>
<div style="display: grid; grid-template-columns: 1fr auto; gap: 20px; align-items: start; margin: 8px 0;">
<div>
<p>Send exactly <b id="crypto-amount">{{ amount_fmt }}</b> {{ coin_symbol }} to this address:</p>
<pre id="crypto-address" style="white-space:pre-wrap;word-wrap:break-word;">{{ address }}</pre>
</div>
<div style="text-align: center;">
<div id="payment-qr" style="margin-bottom: 8px;"></div>
<small style="color: #666;">Scan with wallet app</small>
</div>
</div>
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; margin: 8px 0;">
<button class="mps-button" id="copy-amt" style="background:#4c4; grid-row: 1;">Copy Amount</button>
@ -59,8 +66,37 @@
<div id="received" style="display:none;">
<small>Received: <span id="recv-piconero"></span> / <span id="exp-piconero"></span> piconero</small>
</div>
<!-- QR Code Library -->
<script src="{{ request.static_url('make_post_sell:static/js/qrcode.min.js') }}"></script>
<script>
(function(){
// Generate QR code for payment
const paymentUri = "{{ wallet_uri_scheme }}:{{ address }}?{% if coin_symbol == 'XMR' %}tx_amount{% else %}amount{% endif %}={{ amount_fmt }}";
const qrContainer = document.getElementById('payment-qr');
if (qrContainer && window.QRious) {
try {
// Clear any existing content
qrContainer.innerHTML = '';
// Create canvas element for QR code
const canvas = document.createElement('canvas');
qrContainer.appendChild(canvas);
// Create QR code using QRious library
const qr = new QRious({
element: canvas,
value: paymentUri,
size: 150,
background: '#ffffff',
foreground: '#000000'
});
} catch (error) {
console.error('QR Code generation failed:', error);
qrContainer.innerHTML = '<div style="width:150px;height:150px;background:#f0f0f0;display:flex;align-items:center;justify-content:center;font-size:12px;color:#666;border:1px solid #ddd;">QR unavailable</div>';
}
}
const paymentId = document.getElementById('payment-id')?.textContent;
const statusEl = document.getElementById('status');
const recvEl = document.getElementById('recv-piconero');
@ -81,6 +117,7 @@
const copyAddrBtn = document.getElementById('copy-addr');
const copyAmtBtn = document.getElementById('copy-amt');
const walletLink = document.querySelector('a[href^="monero:"], a[href^="bitcoin:"], a[href^="litecoin:"], a[href^="dogecoin:"]');
const qrContainer = document.getElementById('payment-qr');
[copyAddrBtn, copyAmtBtn].forEach(btn => {
if (btn) {
@ -96,11 +133,19 @@
walletLink.style.pointerEvents = 'none';
walletLink.style.background = '#ccc';
}
// Disable QR code
if (qrContainer) {
qrContainer.style.opacity = '0.5';
qrContainer.style.filter = 'grayscale(100%)';
}
}
// Replace action buttons with invoice link for non-pending statuses
function replaceButtonsWithInvoiceLink(invoiceUrl) {
const buttonGrid = document.querySelector('div[style*="grid-template-columns: 1fr 1fr 1fr"]');
const qrContainer = document.getElementById('payment-qr');
if (!buttonGrid) return;
// Clear all buttons
@ -116,6 +161,12 @@
invoiceLink.style.display = 'block';
invoiceLink.textContent = invoiceUrl ? 'View Invoice' : 'View Purchases';
buttonGrid.appendChild(invoiceLink);
// Disable QR code for completed payments
if (qrContainer) {
qrContainer.style.opacity = '0.5';
qrContainer.style.filter = 'grayscale(100%)';
}
}
// Add warning message for expired payments (only once)