Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
e47a4b0e27 | |||
de51b66968 |
@ -21,8 +21,23 @@
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<script type="text/javascript">
|
||||
// https://developer.chrome.com/articles/nfc/
|
||||
<script>
|
||||
class NDEFReaderWrapper {
|
||||
constructor() {
|
||||
this.onreading = null;
|
||||
this.onreadingerror = null;
|
||||
}
|
||||
|
||||
async scan(opts) {
|
||||
if (opts && opts.signal){
|
||||
opts.signal.addEventListener('abort', () => {
|
||||
window.parent.postMessage('nfc:abort', '*');
|
||||
});
|
||||
}
|
||||
window.parent.postMessage('nfc:startScan', '*');
|
||||
}
|
||||
}
|
||||
|
||||
Vue.component("lnurl-withdraw-checkout", {
|
||||
template: "#lnurl-withdraw-template",
|
||||
props: {
|
||||
@ -69,7 +84,7 @@ Vue.component("lnurl-withdraw-checkout", {
|
||||
data () {
|
||||
return {
|
||||
url: @Safe.Json(Context.Request.GetAbsoluteUri(Url.Action("SubmitLNURLWithdrawForInvoice", "NFC"))),
|
||||
supported: 'NDEFReader' in window && window.self === window.top,
|
||||
supported: 'NDEFReader' in window,
|
||||
scanning: false,
|
||||
submitting: false,
|
||||
permissionGranted: false,
|
||||
@ -135,7 +150,8 @@ Vue.component("lnurl-withdraw-checkout", {
|
||||
this.submitting = false;
|
||||
this.scanning = true;
|
||||
try {
|
||||
const ndef = new NDEFReader()
|
||||
const inModal = window.self !== window.top;
|
||||
const ndef = inModal ? new NDEFReaderWrapper() : new NDEFReader();
|
||||
this.readerAbortController = new AbortController()
|
||||
this.readerAbortController.signal.onabort = () => {
|
||||
this.scanning = false;
|
||||
@ -143,17 +159,33 @@ Vue.component("lnurl-withdraw-checkout", {
|
||||
|
||||
await ndef.scan({ signal: this.readerAbortController.signal })
|
||||
|
||||
ndef.onreadingerror = () => {
|
||||
this.errorMessage = "Could not read NFC tag";
|
||||
}
|
||||
ndef.onreadingerror = this.reportNfcError
|
||||
|
||||
ndef.onreading = async ({ message, serialNumber }) => {
|
||||
ndef.onreading = async ({ message }) => {
|
||||
const record = message.records[0]
|
||||
const textDecoder = new TextDecoder('utf-8')
|
||||
const lnurl = textDecoder.decode(record.data)
|
||||
await this.sendData(lnurl)
|
||||
}
|
||||
|
||||
if (inModal) {
|
||||
// receive messages from iframe
|
||||
window.addEventListener('message', async event => {
|
||||
// deny messages from other origins
|
||||
if (event.origin !== window.location.origin) return
|
||||
|
||||
const { action, data } = event.data
|
||||
switch (action) {
|
||||
case 'nfc:data':
|
||||
await this.sendData(data)
|
||||
break;
|
||||
case 'nfc:error':
|
||||
this.reportNfcError()
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// we came here, so the user must have allowed NFC access
|
||||
this.permissionGranted = true;
|
||||
} catch (error) {
|
||||
@ -182,6 +214,9 @@ Vue.component("lnurl-withdraw-checkout", {
|
||||
this.errorMessage = error;
|
||||
}
|
||||
this.submitting = false;
|
||||
},
|
||||
reportNfcError() {
|
||||
this.errorMessage = 'Could not read NFC tag';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -48,7 +48,7 @@
|
||||
var scriptMatch = thisScript.match(scriptSrcRegex)
|
||||
if (scriptMatch) {
|
||||
// We can't just take the domain as btcpay can run under a sub path with RootPath
|
||||
origin = thisScript.substr(0, thisScript.length - scriptMatch[0].length);
|
||||
origin = thisScript.slice(0, thisScript.length - scriptMatch[0].length);
|
||||
}
|
||||
// urlPrefix should be site root without trailing slash
|
||||
function setApiUrlPrefix(urlPrefix) {
|
||||
@ -88,10 +88,36 @@
|
||||
function onModalReceiveMessage(customOnModalReceiveMessage) {
|
||||
onModalReceiveMessageMethod = customOnModalReceiveMessage;
|
||||
}
|
||||
var readerAbortController = null;
|
||||
|
||||
function startNfcScan() {
|
||||
const ndef = new NDEFReader();
|
||||
readerAbortController = new AbortController()
|
||||
readerAbortController.signal.onabort = () => {
|
||||
this.scanning = false;
|
||||
};
|
||||
ndef.scan({ signal:readerAbortController.signal }).then(() => {
|
||||
ndef.onreading = event => {
|
||||
const message = event.message;
|
||||
const record = message.records[0];
|
||||
const textDecoder = new TextDecoder('utf-8');
|
||||
const data = textDecoder.decode(record.data);
|
||||
|
||||
// Send NFC data back to the iframe
|
||||
if (iframe) {
|
||||
iframe.contentWindow.postMessage({ action: 'nfc:data', data }, '*');
|
||||
}
|
||||
};
|
||||
ndef.onreadingerror = () => {
|
||||
// Send error message back to the iframe
|
||||
if (iframe) {
|
||||
iframe.contentWindow.postMessage({ action: 'nfc:error' }, '*');
|
||||
}
|
||||
};
|
||||
}).catch(console.error);
|
||||
}
|
||||
|
||||
function receiveMessage(event) {
|
||||
var uri;
|
||||
|
||||
if (!origin.startsWith(event.origin) || !showingInvoice) {
|
||||
return;
|
||||
}
|
||||
@ -99,8 +125,14 @@
|
||||
hideFrame();
|
||||
} else if (event.data === 'loaded') {
|
||||
showFrame();
|
||||
} else if (event.data === 'nfc:startScan') {
|
||||
startNfcScan();
|
||||
} else if (event.data === 'nfc:abort') {
|
||||
if (readerAbortController) {
|
||||
readerAbortController.abort()
|
||||
}
|
||||
} else if (event.data && event.data.open) {
|
||||
uri = event.data.open;
|
||||
const uri = event.data.open;
|
||||
if (uri.indexOf('bitcoin:') === 0) {
|
||||
window.location = uri;
|
||||
}
|
||||
@ -149,5 +181,4 @@
|
||||
setApiUrlPrefix: setApiUrlPrefix,
|
||||
onModalReceiveMessage: onModalReceiveMessage
|
||||
};
|
||||
|
||||
})();
|
||||
|
Reference in New Issue
Block a user