From 88a1d83323dd073e2200aee10023d4d640dd5442 Mon Sep 17 00:00:00 2001 From: Andrew Camilleri Date: Thu, 21 Mar 2024 10:30:23 +0100 Subject: [PATCH] Support bbqr psbts (#5852) * Support bbqr psbts https://bbqr.org/ @nvk * add js test for bbqr --- BTCPayServer.Tests/ThirdPartyTests.cs | 4 ++ .../Views/Shared/CameraScanner.cshtml | 53 +++++++++++++++++-- .../Views/UIStores/ImportWallet/Scan.cshtml | 1 + .../Views/UIWallets/WalletPSBT.cshtml | 6 ++- .../Views/UIWallets/WalletPSBTDecoded.cshtml | 5 +- BTCPayServer/wwwroot/vendor/bbqr/bbqr.iife.js | 8 +++ 6 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 BTCPayServer/wwwroot/vendor/bbqr/bbqr.iife.js diff --git a/BTCPayServer.Tests/ThirdPartyTests.cs b/BTCPayServer.Tests/ThirdPartyTests.cs index 19c7cf006..8e8f283f2 100644 --- a/BTCPayServer.Tests/ThirdPartyTests.cs +++ b/BTCPayServer.Tests/ThirdPartyTests.cs @@ -494,6 +494,10 @@ retry: version = Regex.Match(actual, "Original file: /npm/decimal\\.js@([0-9]+.[0-9]+.[0-9]+)/decimal\\.js").Groups[1].Value; expected = (await (await client.GetAsync($"https://cdn.jsdelivr.net/npm/decimal.js@{version}/decimal.min.js")).Content.ReadAsStringAsync()).Trim(); EqualJsContent(expected, actual); + + actual = GetFileContent("BTCPayServer", "wwwroot", "vendor", "bbqr", "bbqr.iife.js").Trim(); + expected = (await (await client.GetAsync($"https://cdn.jsdelivr.net/npm/bbqr@1.0.0/dist/bbqr.iife.js")).Content.ReadAsStringAsync()).Trim(); + EqualJsContent(expected, actual); } private void EqualJsContent(string expected, string actual) diff --git a/BTCPayServer/Views/Shared/CameraScanner.cshtml b/BTCPayServer/Views/Shared/CameraScanner.cshtml index 06725d814..f9154cf72 100644 --- a/BTCPayServer/Views/Shared/CameraScanner.cshtml +++ b/BTCPayServer/Views/Shared/CameraScanner.cshtml @@ -51,6 +51,12 @@
+
+
BBQR: {{bbqrDecoder.total}} parts, {{bbqrDecoder.progress * 100}}% completed
+
+
+
+
@@ -85,6 +91,7 @@ function initCameraScanningApp(title, onDataSubmit, modalId, submitOnScan = fals noStreamApiSupport: false, qrData: null, decoder: null, + bbqrDecoder: null, errorMessage: null, successMessage: null, camera: 0, @@ -135,6 +142,7 @@ function initCameraScanningApp(title, onDataSubmit, modalId, submitOnScan = fals this.successMessage = null; this.errorMessage = null; this.decoder = null; + this.bbqrDecoder = null; }, close() { if (this.modalId) { @@ -146,12 +154,51 @@ function initCameraScanningApp(title, onDataSubmit, modalId, submitOnScan = fals onDecode(content) { if (this.qrData) return; const isUR = content.toLowerCase().startsWith("ur:"); - console.debug(1, content); - + const isBBQr = content.startsWith("B$"); + console.debug(content); try { - if (!isUR) { + if (isBBQr){ + this.decoder = null; + const total = parseInt(content.substr(4, 2), 36); + const current = parseInt(content.substr(6, 2), 36); + const format = content.substr(2,1); + const type = content.substr(3, 1); + + if (!this.bbqrDecoder || + this.bbqrDecoder.total !== total || + this.bbqrDecoder.format !== format || + this.bbqrDecoder.type !== type) { + this.bbqrDecoder = { + total, + format, + type, + data: new Array(total), + progress: 1/total + }; + } + this.bbqrDecoder.data[current] = content; + + const progress = this.bbqrDecoder.data.filter(value => value !== undefined).length / total; + this.bbqrDecoder.progress = progress; + if (progress >= 1) { + try { + const joinResult = BBQr.joinQRs(this.bbqrDecoder.data); + function buf2hex(buffer) { // buffer is an ArrayBuffer + return [...new Uint8Array(buffer)] + .map(x => x.toString(16).padStart(2, '0')) + .join(''); + } + const result = buf2hex(joinResult.raw); + this.setQrData(result); + this.successMessage = `BBQr ${type} decoded`; + }catch (error){ + this.errorMessage = error.message; + } + } + } else if (!isUR) { this.setQrData(content); } else { + this.bbqrDecoder = null; this.decoder = this.decoder || new window.URlib.URRegistryDecoder(); if (this.decoder.receivePart(content)) { if (this.decoder.isComplete()) { diff --git a/BTCPayServer/Views/UIStores/ImportWallet/Scan.cshtml b/BTCPayServer/Views/UIStores/ImportWallet/Scan.cshtml index efd9f6f47..62c2a4e1f 100644 --- a/BTCPayServer/Views/UIStores/ImportWallet/Scan.cshtml +++ b/BTCPayServer/Views/UIStores/ImportWallet/Scan.cshtml @@ -78,6 +78,7 @@ + + +