mirror of
https://github.com/m2049r/xmrwallet
synced 2024-11-24 14:37:14 +01:00
OpenAlias support for XMR & BTC (#404)
* with support for OpenAlias QR Codes
This commit is contained in:
parent
8b28e3ea1e
commit
9f9bc4793d
@ -82,6 +82,11 @@ dependencies {
|
||||
|
||||
implementation 'com.nulab-inc:zxcvbn:1.2.3'
|
||||
|
||||
implementation 'dnsjava:dnsjava:2.1.8'
|
||||
//implementation "org.minidns:minidns-hla:0.3.2"
|
||||
implementation 'org.jitsi:dnssecjava:1.1.3'
|
||||
implementation 'org.slf4j:slf4j-nop:1.7.25'
|
||||
|
||||
testImplementation "junit:junit:$rootProject.ext.junitVersion"
|
||||
testImplementation "org.mockito:mockito-all:$rootProject.ext.mockitoVersion"
|
||||
testImplementation "com.squareup.okhttp3:mockwebserver:$rootProject.ext.okHttpVersion"
|
||||
|
@ -3,6 +3,7 @@
|
||||
package="com.m2049r.xmrwallet">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
@ -273,6 +273,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
||||
break;
|
||||
case Toolbar.BUTTON_CANCEL:
|
||||
onDisposeRequest();
|
||||
Helper.hideKeyboard(WalletActivity.this);
|
||||
WalletActivity.super.onBackPressed();
|
||||
break;
|
||||
case Toolbar.BUTTON_CLOSE:
|
||||
@ -920,7 +921,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
||||
drawer.closeDrawer(GravityCompat.START);
|
||||
return;
|
||||
}
|
||||
|
||||
final Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
|
||||
if (fragment instanceof OnBackPressedListener) {
|
||||
if (!((OnBackPressedListener) fragment).onBackPressed()) {
|
||||
|
@ -20,6 +20,7 @@ import android.net.Uri;
|
||||
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.util.BitcoinAddressValidator;
|
||||
import com.m2049r.xmrwallet.util.OpenAliasHelper;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -32,6 +33,9 @@ public class BarcodeData {
|
||||
public static final String XMR_AMOUNT = "tx_amount";
|
||||
public static final String XMR_DESCRIPTION = "tx_description";
|
||||
|
||||
public static final String OA_XMR_ASSET = "xmr";
|
||||
public static final String OA_BTC_ASSET = "btc";
|
||||
|
||||
static final String BTC_SCHEME = "bitcoin:";
|
||||
static final String BTC_AMOUNT = "amount";
|
||||
|
||||
@ -40,10 +44,12 @@ public class BarcodeData {
|
||||
}
|
||||
|
||||
public Asset asset = null;
|
||||
public String addressName = null;
|
||||
public String address = null;
|
||||
public String paymentId = null;
|
||||
public String amount = null;
|
||||
public String description = null;
|
||||
public boolean isSecure = true;
|
||||
|
||||
public BarcodeData(String uri) {
|
||||
this.asset = asset;
|
||||
@ -76,6 +82,14 @@ public class BarcodeData {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public void setAddressName(String name) {
|
||||
addressName = name;
|
||||
}
|
||||
|
||||
public void isSecure(boolean isSecure) {
|
||||
this.isSecure = isSecure;
|
||||
}
|
||||
|
||||
public Uri getUri() {
|
||||
return Uri.parse(getUriString());
|
||||
}
|
||||
@ -95,7 +109,7 @@ public class BarcodeData {
|
||||
first = false;
|
||||
sb.append(BarcodeData.XMR_DESCRIPTION).append('=').append(Uri.encode(description));
|
||||
}
|
||||
if (!amount.isEmpty()) {
|
||||
if ((amount != null) && !amount.isEmpty()) {
|
||||
sb.append(first ? "?" : "&");
|
||||
sb.append(BarcodeData.XMR_AMOUNT).append('=').append(amount);
|
||||
}
|
||||
@ -113,10 +127,14 @@ public class BarcodeData {
|
||||
if (bcData == null) {
|
||||
bcData = parseBitcoinUri(qrCode);
|
||||
}
|
||||
// check for naked btc addres
|
||||
// check for naked btc address
|
||||
if (bcData == null) {
|
||||
bcData = parseBitcoinNaked(qrCode);
|
||||
}
|
||||
// check for OpenAlias
|
||||
if (bcData == null) {
|
||||
bcData = parseOpenAlias(qrCode);
|
||||
}
|
||||
return bcData;
|
||||
}
|
||||
|
||||
@ -238,4 +256,61 @@ public class BarcodeData {
|
||||
|
||||
return new BarcodeData(BarcodeData.Asset.BTC, address);
|
||||
}
|
||||
|
||||
static public BarcodeData parseOpenAlias(String oaString) {
|
||||
Timber.d("parseOpenAlias=%s", oaString);
|
||||
if (oaString == null) return null;
|
||||
|
||||
Map<String, String> oaAttrs = OpenAliasHelper.parse(oaString);
|
||||
if (oaAttrs == null) return null;
|
||||
|
||||
String oaAsset = oaAttrs.get(OpenAliasHelper.OA1_ASSET);
|
||||
if (oaAsset == null) return null;
|
||||
|
||||
String address = oaAttrs.get(OpenAliasHelper.OA1_ADDRESS);
|
||||
if (address == null) return null;
|
||||
|
||||
Asset asset;
|
||||
if (OA_XMR_ASSET.equals(oaAsset)) {
|
||||
if (!Wallet.isAddressValid(address)) {
|
||||
Timber.d("XMR address invalid");
|
||||
return null;
|
||||
}
|
||||
asset = Asset.XMR;
|
||||
} else if (OA_BTC_ASSET.equals(oaAsset)) {
|
||||
if (!BitcoinAddressValidator.validate(address)) {
|
||||
Timber.d("BTC address invalid");
|
||||
return null;
|
||||
}
|
||||
asset = Asset.BTC;
|
||||
} else {
|
||||
Timber.i("Unsupported OpenAlias asset %s", oaAsset);
|
||||
return null;
|
||||
}
|
||||
|
||||
String paymentId = oaAttrs.get(OpenAliasHelper.OA1_PAYMENTID);
|
||||
String description = oaAttrs.get(OpenAliasHelper.OA1_DESCRIPTION);
|
||||
if (description == null) {
|
||||
description = oaAttrs.get(OpenAliasHelper.OA1_NAME);
|
||||
}
|
||||
String amount = oaAttrs.get(OpenAliasHelper.OA1_AMOUNT);
|
||||
String addressName = oaAttrs.get(OpenAliasHelper.OA1_NAME);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
BarcodeData bc = new BarcodeData(asset, address, paymentId, description, amount);
|
||||
bc.setAddressName(addressName);
|
||||
return bc;
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@ import android.text.Editable;
|
||||
import android.text.Html;
|
||||
import android.text.InputType;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Patterns;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@ -41,8 +42,11 @@ import com.m2049r.xmrwallet.data.TxDataBtc;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.util.BitcoinAddressValidator;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.OpenAliasHelper;
|
||||
import com.m2049r.xmrwallet.util.UserNotes;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
public class SendAddressWizardFragment extends SendWizardFragment {
|
||||
@ -83,6 +87,8 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
||||
private TextView tvXmrTo;
|
||||
private View llXmrTo;
|
||||
|
||||
private boolean resolvingOA = false;
|
||||
|
||||
OnScanListener onScanListener;
|
||||
|
||||
public interface OnScanListener {
|
||||
@ -108,7 +114,11 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN))
|
||||
|| (actionId == EditorInfo.IME_ACTION_NEXT)) {
|
||||
if (checkAddress()) {
|
||||
String dnsOA = dnsFromOpenAlias(etAddress.getEditText().getText().toString());
|
||||
Timber.d("OpenAlias is %s", dnsOA);
|
||||
if (dnsOA != null) {
|
||||
processOpenAlias(dnsOA);
|
||||
} else if (checkAddress()) {
|
||||
if (llPaymentId.getVisibility() == View.VISIBLE) {
|
||||
etPaymentId.requestFocus();
|
||||
} else {
|
||||
@ -230,6 +240,38 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
||||
return view;
|
||||
}
|
||||
|
||||
private void processOpenAlias(String dnsOA) {
|
||||
if (resolvingOA) return; // already resolving - just wait
|
||||
if (dnsOA != null) {
|
||||
resolvingOA = true;
|
||||
etAddress.setError(getString(R.string.send_address_resolve_openalias));
|
||||
OpenAliasHelper.resolve(dnsOA, new OpenAliasHelper.OnResolvedListener() {
|
||||
@Override
|
||||
public void onResolved(Map<BarcodeData.Asset, BarcodeData> dataMap) {
|
||||
resolvingOA = false;
|
||||
BarcodeData barcodeData = dataMap.get(BarcodeData.Asset.XMR);
|
||||
if (barcodeData == null) barcodeData = dataMap.get(BarcodeData.Asset.BTC);
|
||||
if (barcodeData != null) {
|
||||
Timber.d("DNSSEC=%b, %s", barcodeData.isSecure, barcodeData.address);
|
||||
processScannedData(barcodeData);
|
||||
etDummy.requestFocus();
|
||||
Helper.hideKeyboard(getActivity());
|
||||
} else {
|
||||
etAddress.setError(getString(R.string.send_address_not_openalias));
|
||||
Timber.d("NO XMR OPENALIAS TXT FOUND");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure() {
|
||||
resolvingOA = false;
|
||||
etAddress.setError(getString(R.string.send_address_not_openalias));
|
||||
Timber.e("OA FAILED");
|
||||
}
|
||||
});
|
||||
} // else ignore
|
||||
}
|
||||
|
||||
private boolean checkAddressNoError() {
|
||||
String address = etAddress.getEditText().getText().toString();
|
||||
return Wallet.isAddressValid(address)
|
||||
@ -276,12 +318,21 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
||||
return ok;
|
||||
}
|
||||
|
||||
private void shakeAddress() {
|
||||
etAddress.startAnimation(Helper.getShakeAnimation(getContext()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onValidateFields() {
|
||||
boolean ok = true;
|
||||
if (!checkAddressNoError()) {
|
||||
etAddress.startAnimation(Helper.getShakeAnimation(getContext()));
|
||||
shakeAddress();
|
||||
ok = false;
|
||||
String dnsOA = dnsFromOpenAlias(etAddress.getEditText().getText().toString());
|
||||
Timber.d("OpenAlias is %s", dnsOA);
|
||||
if (dnsOA != null) {
|
||||
processOpenAlias(dnsOA);
|
||||
}
|
||||
}
|
||||
if (!checkPaymentId()) {
|
||||
etPaymentId.startAnimation(Helper.getShakeAnimation(getContext()));
|
||||
@ -336,7 +387,12 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
||||
String scannedAddress = barcodeData.address;
|
||||
if (scannedAddress != null) {
|
||||
etAddress.getEditText().setText(scannedAddress);
|
||||
checkAddress();
|
||||
if (checkAddress()) {
|
||||
if (!barcodeData.isSecure)
|
||||
etAddress.setError(getString(R.string.send_address_no_dnssec));
|
||||
else
|
||||
etAddress.setError(getString(R.string.send_address_openalias));
|
||||
}
|
||||
} else {
|
||||
etAddress.getEditText().getText().clear();
|
||||
etAddress.setError(null);
|
||||
@ -367,4 +423,14 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
||||
Helper.hideKeyboard(getActivity());
|
||||
etDummy.requestFocus();
|
||||
}
|
||||
|
||||
String dnsFromOpenAlias(String openalias) {
|
||||
Timber.d("checking openalias candidate %s", openalias);
|
||||
if (Patterns.DOMAIN_NAME.matcher(openalias).matches()) return openalias;
|
||||
if (Patterns.EMAIL_ADDRESS.matcher(openalias).matches()) {
|
||||
openalias = openalias.replaceFirst("@", ".");
|
||||
if (Patterns.DOMAIN_NAME.matcher(openalias).matches()) return openalias;
|
||||
}
|
||||
return null; // not an openalias
|
||||
}
|
||||
}
|
||||
|
245
app/src/main/java/com/m2049r/xmrwallet/util/OpenAliasHelper.java
Normal file
245
app/src/main/java/com/m2049r/xmrwallet/util/OpenAliasHelper.java
Normal file
@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright (c) 2018 m2049r
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Specs from https://openalias.org/
|
||||
|
||||
package com.m2049r.xmrwallet.util;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import com.m2049r.xmrwallet.data.BarcodeData;
|
||||
|
||||
import org.jitsi.dnssec.validator.ValidatingResolver;
|
||||
import org.xbill.DNS.DClass;
|
||||
import org.xbill.DNS.Flags;
|
||||
import org.xbill.DNS.Message;
|
||||
import org.xbill.DNS.Name;
|
||||
import org.xbill.DNS.RRset;
|
||||
import org.xbill.DNS.Rcode;
|
||||
import org.xbill.DNS.Record;
|
||||
import org.xbill.DNS.Section;
|
||||
import org.xbill.DNS.SimpleResolver;
|
||||
import org.xbill.DNS.TXTRecord;
|
||||
import org.xbill.DNS.Type;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
public class OpenAliasHelper {
|
||||
public static final String OA1_SCHEME = "oa1:";
|
||||
public static final String OA1_ASSET = "asset";
|
||||
public static final String OA1_ADDRESS = "recipient_address";
|
||||
public static final String OA1_NAME = "recipient_name";
|
||||
public static final String OA1_DESCRIPTION = "tx_description";
|
||||
public static final String OA1_AMOUNT = "tx_amount";
|
||||
public static final String OA1_PAYMENTID = "tx_payment_id";
|
||||
|
||||
public static final int DNS_LOOKUP_TIMEOUT = 2500; // ms
|
||||
|
||||
public static void resolve(String name, OnResolvedListener resolvedListener) {
|
||||
new DnsTxtResolver(resolvedListener).execute(name);
|
||||
}
|
||||
|
||||
public static Map<String, String> parse(String oaString) {
|
||||
return new OpenAliasParser(oaString).parse();
|
||||
}
|
||||
|
||||
public interface OnResolvedListener {
|
||||
void onResolved(Map<BarcodeData.Asset, BarcodeData> dataMap);
|
||||
|
||||
void onFailure();
|
||||
}
|
||||
|
||||
private static class DnsTxtResolver extends AsyncTask<String, Void, Boolean> {
|
||||
List<String> txts = new ArrayList<>();
|
||||
boolean dnssec = false;
|
||||
|
||||
private final OnResolvedListener resolvedListener;
|
||||
|
||||
private DnsTxtResolver(OnResolvedListener resolvedListener) {
|
||||
this.resolvedListener = resolvedListener;
|
||||
}
|
||||
|
||||
// trust anchor of the root zone
|
||||
// http://data.iana.org/root-anchors/root-anchors.xml
|
||||
final String ROOT =
|
||||
". IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5\n" +
|
||||
". IN DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D";
|
||||
final String[] DNSSEC_SERVERS = {
|
||||
"4.2.2.1", // Level3
|
||||
"4.2.2.2", // Level3
|
||||
"4.2.2.6", // Level3
|
||||
"1.1.1.1", // cloudflare
|
||||
"9.9.9.9", // quad9
|
||||
"8.8.4.4", // google
|
||||
"8.8.8.8" // google
|
||||
};
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(String... args) {
|
||||
//main();
|
||||
if (args.length != 1) return false;
|
||||
String name = args[0];
|
||||
if ((name == null) || (name.isEmpty()))
|
||||
return false; //pointless trying to lookup nothing
|
||||
Timber.d("Resolving %s", name);
|
||||
try {
|
||||
SimpleResolver sr = new SimpleResolver(DNSSEC_SERVERS[new Random().nextInt(DNSSEC_SERVERS.length)]);
|
||||
ValidatingResolver vr = new ValidatingResolver(sr);
|
||||
vr.setTimeout(0, DNS_LOOKUP_TIMEOUT);
|
||||
vr.loadTrustAnchors(new ByteArrayInputStream(ROOT.getBytes("ASCII")));
|
||||
Record qr = Record.newRecord(Name.fromConstantString(name + "."), Type.TXT, DClass.IN);
|
||||
Message response = vr.send(Message.newQuery(qr));
|
||||
final int rcode = response.getRcode();
|
||||
if (rcode != Rcode.NOERROR) {
|
||||
Timber.i("Rcode: %s", Rcode.string(rcode));
|
||||
for (RRset set : response.getSectionRRsets(Section.ADDITIONAL)) {
|
||||
if (set.getName().equals(Name.root) && set.getType() == Type.TXT
|
||||
&& set.getDClass() == ValidatingResolver.VALIDATION_REASON_QCLASS) {
|
||||
Timber.i("Reason: %s", ((TXTRecord) set.first()).getStrings().get(0));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
dnssec = response.getHeader().getFlag(Flags.AD);
|
||||
for (Record record : response.getSectionArray(Section.ANSWER)) {
|
||||
if (record.getType() == Type.TXT) {
|
||||
txts.addAll(((TXTRecord) record).getStrings());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException | IllegalArgumentException ex) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostExecute(Boolean success) {
|
||||
if (resolvedListener != null)
|
||||
if (success) {
|
||||
Map<BarcodeData.Asset, BarcodeData> dataMap = new HashMap<>();
|
||||
for (String txt : txts) {
|
||||
BarcodeData bc = BarcodeData.parseOpenAlias(txt);
|
||||
if (bc != null) {
|
||||
bc.isSecure(dnssec);
|
||||
if (!dataMap.containsKey(bc.asset)) {
|
||||
dataMap.put(bc.asset, bc);
|
||||
}
|
||||
}
|
||||
}
|
||||
resolvedListener.onResolved(dataMap);
|
||||
} else {
|
||||
resolvedListener.onFailure();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class OpenAliasParser {
|
||||
int currentPos = 0;
|
||||
final String oaString;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
OpenAliasParser(String oaString) {
|
||||
this.oaString = oaString;
|
||||
}
|
||||
|
||||
Map<String, String> parse() {
|
||||
if ((oaString == null) || !oaString.startsWith(OA1_SCHEME)) return null;
|
||||
if (oaString.charAt(oaString.length() - 1) != ';') return null;
|
||||
|
||||
Map<String, String> oaAttributes = new HashMap<>();
|
||||
|
||||
final int assetEnd = oaString.indexOf(' ');
|
||||
if (assetEnd > 20) return null; // random sanity check
|
||||
String asset = oaString.substring(OA1_SCHEME.length(), assetEnd);
|
||||
oaAttributes.put(OA1_ASSET, asset);
|
||||
|
||||
boolean inQuote = false;
|
||||
boolean inKey = true;
|
||||
String key = null;
|
||||
for (currentPos = assetEnd; currentPos < oaString.length() - 1; currentPos++) {
|
||||
char c = currentChar();
|
||||
if (inKey) {
|
||||
if ((sb.length() == 0) && Character.isWhitespace(c)) continue;
|
||||
if ((c == '\\') || (c == ';')) return null;
|
||||
if (c == '=') {
|
||||
key = sb.toString();
|
||||
if (oaAttributes.containsKey(key)) return null; // no duplicate keys allowed
|
||||
sb.setLength(0);
|
||||
inKey = false;
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// now we are in the value
|
||||
if ((sb.length() == 0) && (c == '"')) {
|
||||
inQuote = true;
|
||||
continue;
|
||||
}
|
||||
if ((!inQuote || ((sb.length() > 0) && (c == '"'))) && (nextChar() == ';')) {
|
||||
if (!inQuote) appendCurrentEscapedChar();
|
||||
oaAttributes.put(key, sb.toString());
|
||||
sb.setLength(0);
|
||||
currentPos++; // skip the next ;
|
||||
inQuote = false;
|
||||
inKey = true;
|
||||
key = null;
|
||||
continue;
|
||||
}
|
||||
appendCurrentEscapedChar();
|
||||
}
|
||||
if (inQuote) return null;
|
||||
|
||||
if (key != null) {
|
||||
oaAttributes.put(key, sb.toString());
|
||||
}
|
||||
|
||||
return oaAttributes;
|
||||
}
|
||||
|
||||
char currentChar() {
|
||||
return oaString.charAt(currentPos);
|
||||
}
|
||||
|
||||
char nextChar() throws IndexOutOfBoundsException {
|
||||
int pos = currentPos;
|
||||
char c = oaString.charAt(pos);
|
||||
if (c == '\\') {
|
||||
pos++;
|
||||
}
|
||||
return oaString.charAt(pos + 1);
|
||||
}
|
||||
|
||||
void appendCurrentEscapedChar() throws IndexOutOfBoundsException {
|
||||
char c = oaString.charAt(currentPos);
|
||||
if (c == '\\') {
|
||||
c = oaString.charAt(++currentPos);
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -222,7 +222,6 @@
|
||||
|
||||
<string name="send_amount_btc_xmr">%1$s (Anhaltswert)</string>
|
||||
|
||||
<string name="send_address_hint">XMR oder BTC Adresse des Empfängers</string>
|
||||
<string name="send_paymentid_hint">Zahlungs-ID (optional)</string>
|
||||
<string name="send_amount_hint">0.00</string>
|
||||
<string name="send_notes_hint">Private Notizen (optional)</string>
|
||||
@ -338,6 +337,14 @@
|
||||
<string name="toast_ledger_attached">%1$s angesteckt</string>
|
||||
<string name="toast_ledger_detached">%1$s abgesteckt</string>
|
||||
|
||||
<string name="receive_desc_hint">Beschreibung (optional)</string>
|
||||
|
||||
<string name="send_address_not_openalias">OpenAlias nicht aufgelöst - Adresse nicht verfügbar</string>
|
||||
<string name="send_address_openalias">OpenAlias sicher ✔</string>
|
||||
<string name="send_address_resolve_openalias">Löse OpenAlias auf…</string>
|
||||
<string name="send_address_no_dnssec">OpenAlias ohne DNSSEC - Adresse kann gefälscht sein!</string>
|
||||
<string name="send_address_hint">Empfänger XMR/BTC Adresse oder OpenAlias</string>
|
||||
|
||||
<string name="progress_nfc_write">Writing Tag</string>
|
||||
<string name="nfc_write_failed">Writing Tag failed!</string>
|
||||
<string name="nfc_write_successful">Writing Tag successful</string>
|
||||
@ -347,6 +354,4 @@
|
||||
<string name="nfc_tag_read_what">I don\'t know what you want!</string>
|
||||
<string name="nfc_tag_read_success">Reading Tag successful</string>
|
||||
<string name="nfc_tag_tap">NFC Available!</string>
|
||||
|
||||
<string name="receive_desc_hint">Beschreibung (optional)</string>
|
||||
</resources>
|
||||
|
@ -196,7 +196,6 @@
|
||||
|
||||
<string name="send_amount_btc_xmr">%1$s (ενδεικτικό)</string>
|
||||
|
||||
<string name="send_address_hint">Διεύθυνση XMR ή BTC παραλήπτη</string>
|
||||
<string name="send_paymentid_hint">ID Πληρωμής(Payment ID)(προαιρετικό)</string>
|
||||
<string name="send_amount_hint">0.00</string>
|
||||
<string name="send_notes_hint">Προσωπικές σημειώσεις (προαιρετικό)</string>
|
||||
@ -348,4 +347,10 @@
|
||||
<string name="nfc_tag_tap">NFC Available!</string>
|
||||
|
||||
<string name="receive_desc_hint">Description (optional)</string>
|
||||
|
||||
<string name="send_address_not_openalias">OpenAlias not resolved - address not available</string>
|
||||
<string name="send_address_openalias">OpenAlias secure ✔</string>
|
||||
<string name="send_address_resolve_openalias">Resolving OpenAlias…</string>
|
||||
<string name="send_address_no_dnssec">OpenAlias without DNSSEC - address may be spoofed</string>
|
||||
<string name="send_address_hint">Receiver\'s XMR/BTC Address or OpenAlias</string>
|
||||
</resources>
|
||||
|
@ -164,7 +164,6 @@
|
||||
<string name="generate_check_address">Introduce una dirección válida</string>
|
||||
<string name="generate_check_mnemonic">Introduce tu semilla de 25 palabras</string>
|
||||
|
||||
<string name="send_address_hint">Dirección XMR o BTC del Destinatario</string>
|
||||
<string name="send_paymentid_hint">ID de Pago (opcional)</string>
|
||||
<string name="send_amount_hint">0.00</string>
|
||||
<string name="send_notes_hint">Notas Privadas (opcional)</string>
|
||||
@ -335,4 +334,10 @@
|
||||
<string name="nfc_tag_tap">NFC Available!</string>
|
||||
|
||||
<string name="receive_desc_hint">Description (optional)</string>
|
||||
|
||||
<string name="send_address_not_openalias">OpenAlias not resolved - address not available</string>
|
||||
<string name="send_address_openalias">OpenAlias secure ✔</string>
|
||||
<string name="send_address_resolve_openalias">Resolving OpenAlias…</string>
|
||||
<string name="send_address_no_dnssec">OpenAlias without DNSSEC - address may be spoofed</string>
|
||||
<string name="send_address_hint">Receiver\'s XMR/BTC Address or OpenAlias</string>
|
||||
</resources>
|
||||
|
@ -224,7 +224,6 @@
|
||||
|
||||
<string name="send_amount_btc_xmr">%1$s (indicatif)</string>
|
||||
|
||||
<string name="send_address_hint">Adresse XMR ou BTC du Destinataire</string>
|
||||
<string name="send_paymentid_hint">ID de Paiement (optionnel)</string>
|
||||
<string name="send_amount_hint">0.00</string>
|
||||
<string name="send_notes_hint">Notes Privées (optionnelles)</string>
|
||||
@ -351,4 +350,10 @@
|
||||
<string name="language_system_default">Use System Language</string>
|
||||
|
||||
<string name="receive_desc_hint">Description (optional)</string>
|
||||
|
||||
<string name="send_address_not_openalias">OpenAlias not resolved - address not available</string>
|
||||
<string name="send_address_openalias">OpenAlias secure ✔</string>
|
||||
<string name="send_address_resolve_openalias">Resolving OpenAlias…</string>
|
||||
<string name="send_address_no_dnssec">OpenAlias without DNSSEC - address may be spoofed</string>
|
||||
<string name="send_address_hint">Receiver\'s XMR/BTC Address or OpenAlias</string>
|
||||
</resources>
|
||||
|
@ -222,7 +222,6 @@
|
||||
|
||||
<string name="send_amount_btc_xmr">%1$s (előrejelzés)</string>
|
||||
|
||||
<string name="send_address_hint">Kedvezményezett XMR vagy BTC címe</string>
|
||||
<string name="send_paymentid_hint">Fizetési azonosító (opcionális)</string>
|
||||
<string name="send_amount_hint">0.00</string>
|
||||
<string name="send_notes_hint">Privát közlemény (opcionális)</string>
|
||||
@ -349,4 +348,10 @@
|
||||
<string name="nfc_tag_tap">NFC elérhető!</string>
|
||||
|
||||
<string name="receive_desc_hint">Description (optional)</string>
|
||||
|
||||
<string name="send_address_not_openalias">OpenAlias not resolved - address not available</string>
|
||||
<string name="send_address_openalias">OpenAlias secure ✔</string>
|
||||
<string name="send_address_resolve_openalias">Resolving OpenAlias…</string>
|
||||
<string name="send_address_no_dnssec">OpenAlias without DNSSEC - address may be spoofed</string>
|
||||
<string name="send_address_hint">Receiver\'s XMR/BTC Address or OpenAlias</string>
|
||||
</resources>
|
||||
|
@ -223,7 +223,6 @@
|
||||
|
||||
<string name="send_amount_btc_xmr">%1$s (indicativo)</string>
|
||||
|
||||
<string name="send_address_hint">Indirizzo XMR o BTC del ricevente</string>
|
||||
<string name="send_paymentid_hint">ID pagamento (opzionale)</string>
|
||||
<string name="send_amount_hint">0,00</string>
|
||||
<string name="send_notes_hint">Note private (opzionali)</string>
|
||||
@ -350,4 +349,10 @@
|
||||
<string name="nfc_tag_tap">NFC Available!</string>
|
||||
|
||||
<string name="receive_desc_hint">Description (optional)</string>
|
||||
|
||||
<string name="send_address_not_openalias">OpenAlias not resolved - address not available</string>
|
||||
<string name="send_address_openalias">OpenAlias secure ✔</string>
|
||||
<string name="send_address_resolve_openalias">Resolving OpenAlias…</string>
|
||||
<string name="send_address_no_dnssec">OpenAlias without DNSSEC - address may be spoofed</string>
|
||||
<string name="send_address_hint">Receiver\'s XMR/BTC Address or OpenAlias</string>
|
||||
</resources>
|
||||
|
@ -221,7 +221,6 @@
|
||||
|
||||
<string name="send_amount_btc_xmr">%1$s (veiledende)</string>
|
||||
|
||||
<string name="send_address_hint">Mottakers BTC eller XMR adresse</string>
|
||||
<string name="send_paymentid_hint">Betalings-ID (valgfritt)</string>
|
||||
<string name="send_amount_hint">0,00</string>
|
||||
<string name="send_notes_hint">Privat notat (valgfritt)</string>
|
||||
@ -348,4 +347,10 @@
|
||||
<string name="nfc_tag_tap">NFC Available!</string>
|
||||
|
||||
<string name="receive_desc_hint">Description (optional)</string>
|
||||
|
||||
<string name="send_address_not_openalias">OpenAlias not resolved - address not available</string>
|
||||
<string name="send_address_openalias">OpenAlias secure ✔</string>
|
||||
<string name="send_address_resolve_openalias">Resolving OpenAlias…</string>
|
||||
<string name="send_address_no_dnssec">OpenAlias without DNSSEC - address may be spoofed</string>
|
||||
<string name="send_address_hint">Receiver\'s XMR/BTC Address or OpenAlias</string>
|
||||
</resources>
|
||||
|
@ -221,7 +221,6 @@
|
||||
|
||||
<string name="send_amount_btc_xmr">%1$s (indicativo)</string>
|
||||
|
||||
<string name="send_address_hint">Endereço de destino XMR ou BTC</string>
|
||||
<string name="send_paymentid_hint">ID do pagamento (opcional)</string>
|
||||
<string name="send_amount_hint">0.00</string>
|
||||
<string name="send_notes_hint">Notas privadas (opcional)</string>
|
||||
@ -351,4 +350,10 @@
|
||||
<string name="nfc_tag_tap">NFC Available!</string>
|
||||
|
||||
<string name="receive_desc_hint">Description (optional)</string>
|
||||
|
||||
<string name="send_address_not_openalias">OpenAlias not resolved - address not available</string>
|
||||
<string name="send_address_openalias">OpenAlias secure ✔</string>
|
||||
<string name="send_address_resolve_openalias">Resolving OpenAlias…</string>
|
||||
<string name="send_address_no_dnssec">OpenAlias without DNSSEC - address may be spoofed</string>
|
||||
<string name="send_address_hint">Receiver\'s XMR/BTC Address or OpenAlias</string>
|
||||
</resources>
|
||||
|
@ -196,7 +196,6 @@
|
||||
|
||||
<string name="send_amount_btc_xmr">%1$s (indicativ)</string>
|
||||
|
||||
<string name="send_address_hint">Adresa XMR sau BTC a destinatarului</string>
|
||||
<string name="send_paymentid_hint">Payment ID (facultativ)</string>
|
||||
<string name="send_amount_hint">0.00</string>
|
||||
<string name="send_notes_hint">Notițe private (facultativ)</string>
|
||||
@ -348,4 +347,10 @@
|
||||
<string name="nfc_tag_tap">NFC Available!</string>
|
||||
|
||||
<string name="receive_desc_hint">Description (optional)</string>
|
||||
|
||||
<string name="send_address_not_openalias">OpenAlias not resolved - address not available</string>
|
||||
<string name="send_address_openalias">OpenAlias secure ✔</string>
|
||||
<string name="send_address_resolve_openalias">Resolving OpenAlias…</string>
|
||||
<string name="send_address_no_dnssec">OpenAlias without DNSSEC - address may be spoofed</string>
|
||||
<string name="send_address_hint">Receiver\'s XMR/BTC Address or OpenAlias</string>
|
||||
</resources>
|
||||
|
@ -223,7 +223,6 @@
|
||||
|
||||
<string name="send_amount_btc_xmr">%1$s (приблизительно)</string>
|
||||
|
||||
<string name="send_address_hint">XMR или BTC адрес получателя</string>
|
||||
<string name="send_paymentid_hint">ID платежа (необязательно)</string>
|
||||
<string name="send_amount_hint">0.00</string>
|
||||
<string name="send_notes_hint">Персональная заметка (необязательно)</string>
|
||||
@ -350,4 +349,10 @@
|
||||
<string name="nfc_tag_tap">NFC Available!</string>
|
||||
|
||||
<string name="receive_desc_hint">Description (optional)</string>
|
||||
|
||||
<string name="send_address_not_openalias">OpenAlias not resolved - address not available</string>
|
||||
<string name="send_address_openalias">OpenAlias secure ✔</string>
|
||||
<string name="send_address_resolve_openalias">Resolving OpenAlias…</string>
|
||||
<string name="send_address_no_dnssec">OpenAlias without DNSSEC - address may be spoofed</string>
|
||||
<string name="send_address_hint">Receiver\'s XMR/BTC Address or OpenAlias</string>
|
||||
</resources>
|
||||
|
@ -220,7 +220,6 @@
|
||||
|
||||
<string name="send_amount_btc_xmr">%1$s (indikatív)</string>
|
||||
|
||||
<string name="send_address_hint">XMR alebo BTC Adresa Príjemcu</string>
|
||||
<string name="send_paymentid_hint">ID Platby (voliteľné)</string>
|
||||
<string name="send_amount_hint">0.00</string>
|
||||
<string name="send_notes_hint">Súkromné Poznámky (voliteľné)</string>
|
||||
@ -347,4 +346,10 @@
|
||||
<string name="nfc_tag_tap">NFC je dostupné!</string>
|
||||
|
||||
<string name="receive_desc_hint">Description (optional)</string>
|
||||
|
||||
<string name="send_address_not_openalias">OpenAlias not resolved - address not available</string>
|
||||
<string name="send_address_openalias">OpenAlias secure ✔</string>
|
||||
<string name="send_address_resolve_openalias">Resolving OpenAlias…</string>
|
||||
<string name="send_address_no_dnssec">OpenAlias without DNSSEC - address may be spoofed</string>
|
||||
<string name="send_address_hint">Receiver\'s XMR/BTC Address or OpenAlias</string>
|
||||
</resources>
|
||||
|
@ -202,7 +202,6 @@
|
||||
|
||||
<string name="send_amount_btc_xmr">%1$s (ungefärlig)</string>
|
||||
|
||||
<string name="send_address_hint">Mottagarens XMR- eller BTC-adress</string>
|
||||
<string name="send_paymentid_hint">Betalnings-ID (valfritt)</string>
|
||||
<string name="send_amount_hint">0,00</string>
|
||||
<string name="send_notes_hint">Privat anteckning (valfri)</string>
|
||||
@ -332,4 +331,10 @@
|
||||
<string name="nfc_tag_tap">NFC Available!</string>
|
||||
|
||||
<string name="receive_desc_hint">Description (optional)</string>
|
||||
|
||||
<string name="send_address_not_openalias">OpenAlias not resolved - address not available</string>
|
||||
<string name="send_address_openalias">OpenAlias secure ✔</string>
|
||||
<string name="send_address_resolve_openalias">Resolving OpenAlias…</string>
|
||||
<string name="send_address_no_dnssec">OpenAlias without DNSSEC - address may be spoofed</string>
|
||||
<string name="send_address_hint">Receiver\'s XMR/BTC Address or OpenAlias</string>
|
||||
</resources>
|
||||
|
@ -219,7 +219,6 @@
|
||||
|
||||
<string name="send_amount_btc_xmr">%1$s (参考价)</string>
|
||||
|
||||
<string name="send_address_hint">收款者的 XMR 或 BTC 地址</string>
|
||||
<string name="send_paymentid_hint">付款ID (选填)</string>
|
||||
<string name="send_amount_hint">0.00</string>
|
||||
<string name="send_notes_hint">注记 (选填)</string>
|
||||
@ -346,4 +345,10 @@
|
||||
<string name="nfc_tag_tap">NFC Available!</string>
|
||||
|
||||
<string name="receive_desc_hint">Description (optional)</string>
|
||||
|
||||
<string name="send_address_not_openalias">OpenAlias not resolved - address not available</string>
|
||||
<string name="send_address_openalias">OpenAlias secure ✔</string>
|
||||
<string name="send_address_resolve_openalias">Resolving OpenAlias…</string>
|
||||
<string name="send_address_no_dnssec">OpenAlias without DNSSEC - address may be spoofed</string>
|
||||
<string name="send_address_hint">Receiver\'s XMR/BTC Address or OpenAlias</string>
|
||||
</resources>
|
||||
|
@ -220,7 +220,6 @@
|
||||
|
||||
<string name="send_amount_btc_xmr">%1$s (參考價)</string>
|
||||
|
||||
<string name="send_address_hint">收款者的 XMR 或 BTC 地址</string>
|
||||
<string name="send_paymentid_hint">付款 ID (選填)</string>
|
||||
<string name="send_amount_hint">0.00</string>
|
||||
<string name="send_notes_hint">註記 (選填)</string>
|
||||
@ -347,4 +346,10 @@
|
||||
<string name="nfc_tag_tap">可使用 NFC 標籤</string>
|
||||
|
||||
<string name="receive_desc_hint">Description (optional)</string>
|
||||
|
||||
<string name="send_address_not_openalias">OpenAlias not resolved - address not available</string>
|
||||
<string name="send_address_openalias">OpenAlias secure ✔</string>
|
||||
<string name="send_address_resolve_openalias">Resolving OpenAlias…</string>
|
||||
<string name="send_address_no_dnssec">OpenAlias without DNSSEC - address may be spoofed</string>
|
||||
<string name="send_address_hint">Receiver\'s XMR/BTC Address or OpenAlias</string>
|
||||
</resources>
|
||||
|
@ -228,7 +228,7 @@
|
||||
|
||||
<string name="send_amount_btc_xmr">%1$s (indicative)</string>
|
||||
|
||||
<string name="send_address_hint">Receiver\'s XMR or BTC Address</string>
|
||||
<string name="send_address_hint">Receiver\'s XMR/BTC Address or OpenAlias</string>
|
||||
<string name="send_paymentid_hint">Payment ID (optional)</string>
|
||||
<string name="send_amount_hint">0.00</string>
|
||||
<string name="send_notes_hint">Private Notes (optional)</string>
|
||||
@ -239,6 +239,10 @@
|
||||
<string name="send_qr_invalid">Not a QR Code</string>
|
||||
<string name="send_qr_address_invalid">Not a valid payment QR code</string>
|
||||
<string name="send_address_invalid">Not a valid address</string>
|
||||
<string name="send_address_not_openalias">OpenAlias not resolved - address not available</string>
|
||||
<string name="send_address_openalias">OpenAlias secure ✔</string>
|
||||
<string name="send_address_resolve_openalias">Resolving OpenAlias…</string>
|
||||
<string name="send_address_no_dnssec">OpenAlias without DNSSEC - address may be spoofed</string>
|
||||
<string name="send_title">Send</string>
|
||||
<string name="send_available">Balance: %1$s XMR</string>
|
||||
<string name="send_address_title">Address</string>
|
||||
|
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (c) 2018 m2049r
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.util;
|
||||
|
||||
import com.m2049r.xmrwallet.data.BarcodeData;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class OpenAliasHelperTest {
|
||||
|
||||
private final static String MONERUJO = "oa1:xmr recipient_address=4AdkPJoxn7JCvAby9szgnt93MSEwdnxdhaASxbTBm6x5dCwmsDep2UYN4FhStDn5i11nsJbpU7oj59ahg8gXb1Mg3viqCuk; recipient_name=Monerujo Development; tx_description=Donation to Monerujo Core Team;";
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void asset() {
|
||||
Map<String, String> attrs = OpenAliasHelper.parse(MONERUJO);
|
||||
assertNotNull(attrs);
|
||||
assertTrue(BarcodeData.OA_XMR_ASSET.equals(attrs.get(OpenAliasHelper.OA1_ASSET)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void quotedSemicolon() {
|
||||
Map<String, String> attrs = OpenAliasHelper.parse("oa1:xmr abc=\";\";def=99;");
|
||||
assertNotNull(attrs);
|
||||
assertTrue(attrs.get("abc").equals(";"));
|
||||
assertTrue(attrs.get("def").equals("99"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void space() {
|
||||
Map<String, String> attrs = OpenAliasHelper.parse("oa1:xmr abc=\\ ;def=99;");
|
||||
assertNotNull(attrs);
|
||||
assertTrue(attrs.get("abc").equals(" "));
|
||||
assertTrue(attrs.get("def").equals("99"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void quotaedSpace() {
|
||||
Map<String, String> attrs = OpenAliasHelper.parse("oa1:xmr abc=\" \";def=99;");
|
||||
assertNotNull(attrs);
|
||||
assertTrue(attrs.get("abc").equals(" "));
|
||||
assertTrue(attrs.get("def").equals("99"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void quotes() {
|
||||
Map<String, String> attrs;
|
||||
attrs = OpenAliasHelper.parse("oa1:xmr abc=\"def\";");
|
||||
assertNotNull(attrs);
|
||||
assertTrue(attrs.get("abc").equals("def"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simple() {
|
||||
Map<String, String> attrs;
|
||||
attrs = OpenAliasHelper.parse("oa1:xmr abc=def;");
|
||||
assertNotNull(attrs);
|
||||
assertTrue(attrs.get("abc").equals("def"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void duplex() {
|
||||
Map<String, String> attrs;
|
||||
attrs = OpenAliasHelper.parse("oa1:xmr abc=def;ghi=jkl;");
|
||||
assertNotNull(attrs);
|
||||
assertTrue(attrs.get("abc").equals("def"));
|
||||
assertTrue(attrs.get("ghi").equals("jkl"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void duplexQ() {
|
||||
Map<String, String> attrs;
|
||||
attrs = OpenAliasHelper.parse("oa1:xmr abc=def;ghi=jkl;");
|
||||
assertNotNull(attrs);
|
||||
assertTrue(attrs.get("abc").equals("def"));
|
||||
assertTrue(attrs.get("ghi").equals("jkl"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simple_unterminated() {
|
||||
Map<String, String> attrs;
|
||||
attrs = OpenAliasHelper.parse("oa1:xmr abc=def;ghi=jkl");
|
||||
assertNull(attrs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unterminatedQuotes() {
|
||||
Map<String, String> attrs;
|
||||
attrs = OpenAliasHelper.parse("oa1:xmr abc=\"def;ghi=jkl;");
|
||||
assertNull(attrs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void quoteEnd() {
|
||||
Map<String, String> attrs;
|
||||
attrs = OpenAliasHelper.parse("oa1:xmr abc=def\";ghi=jkl;");
|
||||
assertNotNull(attrs);
|
||||
assertTrue(attrs.get("abc").equals("def\""));
|
||||
assertTrue(attrs.get("ghi").equals("jkl"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void quoteMiddle() {
|
||||
Map<String, String> attrs;
|
||||
attrs = OpenAliasHelper.parse("oa1:xmr abc=d\"ef;ghi=jkl;");
|
||||
assertNotNull(attrs);
|
||||
assertTrue(attrs.get("abc").equals("d\"ef"));
|
||||
assertTrue(attrs.get("ghi").equals("jkl"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void quoteMultiple() {
|
||||
Map<String, String> attrs;
|
||||
attrs = OpenAliasHelper.parse("oa1:xmr abc=d\"ef\";ghi=jkl;");
|
||||
assertNotNull(attrs);
|
||||
assertTrue(attrs.get("abc").equals("d\"ef\""));
|
||||
assertTrue(attrs.get("ghi").equals("jkl"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void quoteMalformedValue() {
|
||||
Map<String, String> attrs;
|
||||
attrs = OpenAliasHelper.parse("oa1:xmr abc=d\"e;f\";ghi=jkl;");
|
||||
assertNull(attrs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void quotedSemicolon2() {
|
||||
Map<String, String> attrs;
|
||||
attrs = OpenAliasHelper.parse("oa1:xmr abc=\"d;ef\";ghi=jkl;");
|
||||
assertNotNull(attrs);
|
||||
assertTrue(attrs.get("abc").equals("d;ef"));
|
||||
assertTrue(attrs.get("ghi").equals("jkl"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void quotedQuote() {
|
||||
Map<String, String> attrs;
|
||||
attrs = OpenAliasHelper.parse("oa1:xmr abc=\"d\"ef\";ghi=jkl;");
|
||||
assertNotNull(attrs);
|
||||
assertTrue(attrs.get("abc").equals("d\"ef"));
|
||||
assertTrue(attrs.get("ghi").equals("jkl"));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user