|
|
|
@ -16,14 +16,122 @@
|
|
|
|
|
|
|
|
|
|
package com.m2049r.xmrwallet.data;
|
|
|
|
|
|
|
|
|
|
import android.net.Uri;
|
|
|
|
|
|
|
|
|
|
import com.m2049r.xmrwallet.model.Wallet;
|
|
|
|
|
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
|
|
import timber.log.Timber;
|
|
|
|
|
|
|
|
|
|
public class BarcodeData {
|
|
|
|
|
public static final String XMR_SCHEME = "monero:";
|
|
|
|
|
public static final String XMR_PAYMENTID = "tx_payment_id";
|
|
|
|
|
public static final String XMR_AMOUNT = "tx_amount";
|
|
|
|
|
|
|
|
|
|
static final String BTC_SCHEME = "bitcoin:";
|
|
|
|
|
static final String BTC_AMOUNT = "amount";
|
|
|
|
|
|
|
|
|
|
public enum Asset {
|
|
|
|
|
XMR
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Asset asset = null;
|
|
|
|
|
public String address = null;
|
|
|
|
|
public String paymentId = null;
|
|
|
|
|
public long amount = -1;
|
|
|
|
|
public String amount = null;
|
|
|
|
|
|
|
|
|
|
public BarcodeData(Asset asset, String address) {
|
|
|
|
|
this.asset = asset;
|
|
|
|
|
this.address = address;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public BarcodeData(Asset asset, String address, String amount) {
|
|
|
|
|
this.asset = asset;
|
|
|
|
|
this.address = address;
|
|
|
|
|
this.amount = amount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public BarcodeData(String address, String paymentId, long amount) {
|
|
|
|
|
public BarcodeData(Asset asset, String address, String paymentId, String amount) {
|
|
|
|
|
this.asset = asset;
|
|
|
|
|
this.address = address;
|
|
|
|
|
this.paymentId = paymentId;
|
|
|
|
|
this.amount = amount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static public BarcodeData fromQrCode(String qrCode) {
|
|
|
|
|
// check for monero uri
|
|
|
|
|
BarcodeData bcData = parseMoneroUri(qrCode);
|
|
|
|
|
// check for naked monero address / integrated address
|
|
|
|
|
if (bcData == null) {
|
|
|
|
|
bcData = parseMoneroNaked(qrCode);
|
|
|
|
|
}
|
|
|
|
|
return bcData;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Parse and decode a monero scheme string. It is here because it needs to validate the data.
|
|
|
|
|
*
|
|
|
|
|
* @param uri String containing a monero URL
|
|
|
|
|
* @return BarcodeData object or null if uri not valid
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static public BarcodeData parseMoneroUri(String uri) {
|
|
|
|
|
Timber.d("parseMoneroUri=%s", uri);
|
|
|
|
|
|
|
|
|
|
if (uri == null) return null;
|
|
|
|
|
|
|
|
|
|
if (!uri.startsWith(XMR_SCHEME)) return null;
|
|
|
|
|
|
|
|
|
|
String noScheme = uri.substring(XMR_SCHEME.length());
|
|
|
|
|
Uri monero = Uri.parse(noScheme);
|
|
|
|
|
Map<String, String> parms = new HashMap<>();
|
|
|
|
|
String query = monero.getQuery();
|
|
|
|
|
if (query != null) {
|
|
|
|
|
String[] args = query.split("&");
|
|
|
|
|
for (String arg : args) {
|
|
|
|
|
String[] namevalue = arg.split("=");
|
|
|
|
|
if (namevalue.length == 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
parms.put(Uri.decode(namevalue[0]).toLowerCase(),
|
|
|
|
|
namevalue.length > 1 ? Uri.decode(namevalue[1]) : "");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
String address = monero.getPath();
|
|
|
|
|
String paymentId = parms.get(XMR_PAYMENTID);
|
|
|
|
|
String amount = parms.get(XMR_AMOUNT);
|
|
|
|
|
if (amount != null) {
|
|
|
|
|
try {
|
|
|
|
|
Double.parseDouble(amount);
|
|
|
|
|
} catch (NumberFormatException ex) {
|
|
|
|
|
Timber.d(ex.getLocalizedMessage());
|
|
|
|
|
return null; // we have an amount but its not a number!
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ((paymentId != null) && !Wallet.isPaymentIdValid(paymentId)) {
|
|
|
|
|
Timber.d("paymentId invalid");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Wallet.isAddressValid(address)) {
|
|
|
|
|
Timber.d("address invalid");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
return new BarcodeData(Asset.XMR, address, paymentId, amount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static public BarcodeData parseMoneroNaked(String address) {
|
|
|
|
|
Timber.d("parseMoneroNaked=%s", address);
|
|
|
|
|
|
|
|
|
|
if (address == null) return null;
|
|
|
|
|
|
|
|
|
|
if (!Wallet.isAddressValid(address)) {
|
|
|
|
|
Timber.d("address invalid");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new BarcodeData(Asset.XMR, address);
|
|
|
|
|
}
|
|
|
|
|
}
|