Merge remote-tracking branch 'origin/Development' into issue544-api

Conflicts:
	pom.xml
This commit is contained in:
Mike Rosseel 2016-12-20 21:02:35 +01:00
commit cfade401bd
7 changed files with 331 additions and 15 deletions

View file

@ -137,6 +137,9 @@ public class CountryUtil {
final Country country = new Country(locale.getCountry(), locale.getDisplayCountry(), region);
allCountries.add(country);
}
allCountries.add(new Country("GE", "Georgia", new Region("AS", getRegionName("AS"))));
final List<Country> allCountriesList = new ArrayList<>(allCountries);
allCountriesList.sort((locale1, locale2) -> locale1.name.compareTo(locale2.name));
return allCountriesList;
@ -162,7 +165,7 @@ public class CountryUtil {
// other source of countries: https://developers.braintreepayments.com/reference/general/countries/java
private static final String[] countryCodes = new String[]{"AE", "AL", "AR", "AT", "AU", "BA", "BE", "BG", "BH",
"BO", "BR", "BY", "CA", "CH", "CL", "CN", "CO", "CR", "CS", "CU", "CY", "CZ", "DE", "DK", "DO", "DZ",
"EC", "EE", "EG", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HR", "HU", "ID", "IE", "IL", "IN",
"EC", "EE", "EG", "ES", "FI", "FR", "GE", "GB", "GR", "GT", "HK", "HN", "HR", "HU", "ID", "IE", "IL", "IN",
"IQ", "IS", "IT", "JO", "JP", "KE", "KH", "KR", "KW", "KZ", "LB", "LT", "LU", "LV", "LY", "MA", "MD", "ME", "MK", "MT", "MX",
"MY", "NI", "NL", "NO", "NZ", "OM", "PA", "PE", "PH", "PL", "PR", "PT", "PY", "QA", "RO", "RS", "RU",
"SA", "SD", "SE", "SG", "SI", "SK", "SV", "SY", "TH", "TN", "TR", "TW", "UA", "US", "UY", "VE", "VN",
@ -171,7 +174,7 @@ public class CountryUtil {
private static final List<String> countryCodeList = Arrays.asList(countryCodes);
private static final String[] regionCodes = new String[]{"AS", "EU", "SA", "EU", "OC", "EU", "EU", "EU", "AS",
"SA", "SA", "EU", "NA", "EU", "SA", "AS", "SA", "NA", "EU", "NA", "EU", "EU", "EU", "EU", "NA", "AF",
"SA", "EU", "AF", "EU", "EU", "EU", "EU", "EU", "NA", "AS", "NA", "EU", "EU", "AS", "EU", "AS", "AS",
"SA", "EU", "AF", "EU", "EU", "EU", "AS", "EU", "EU", "NA", "AS", "NA", "EU", "EU", "AS", "EU", "AS", "AS",
"AS", "EU", "EU", "AS", "AS", "AF", "AS", "AS", "AS", "AS", "AS", "EU", "EU", "EU", "AF", "AF", "EU", "EU", "EU", "EU", "NA",
"AS", "NA", "EU", "EU", "OC", "AS", "NA", "SA", "AS", "EU", "NA", "EU", "SA", "AS", "EU", "EU", "EU",
"AS", "AF", "EU", "AS", "EU", "EU", "NA", "AS", "AS", "AF", "AS", "AS", "EU", "NA", "SA", "SA", "AS",

View file

@ -132,6 +132,7 @@ public class CurrencyUtil {
result.add(new CryptoCurrency("HODL", "HOdlcoin"));
result.add(new CryptoCurrency("HNC", "HunCoin"));
result.add(new CryptoCurrency("IOC", "I/O Coin"));
result.add(new CryptoCurrency("IOP", "Fermat"));
result.add(new CryptoCurrency("JPYT", "JPY Tether"));
result.add(new CryptoCurrency("JBS", "Jumbucks"));
result.add(new CryptoCurrency("LBC", "LBRY Credits"));

View file

@ -18,6 +18,12 @@
package io.bitsquare.gui.util.validation;
import io.bitsquare.gui.util.validation.altcoins.ByteballAddressValidator;
import io.bitsquare.gui.util.validation.params.IOPParams;
import org.bitcoinj.core.Address;
import org.bitcoinj.core.AddressFormatException;
import org.bitcoinj.params.MainNetParams;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -46,7 +52,7 @@ public final class AltCoinAddressValidator extends InputValidator {
// 2: If the address contains a checksum, verify the checksum
ValidationResult wrongChecksum = new ValidationResult(false, "Address validation failed because checksum was not correct.");
ValidationResult wrongStructure = new ValidationResult(false, "Address validation failed because it does not match the structure of a " + currencyCode + " address.");
ValidationResult regexTestFailed = new ValidationResult(false, "Address validation failed because it does not match the structure of a " + currencyCode + " address.");
switch (currencyCode) {
// Example for BTC, though for BTC we use the BitcoinJ library address check
@ -55,11 +61,31 @@ public final class AltCoinAddressValidator extends InputValidator {
// taken form: https://stackoverflow.com/questions/21683680/regex-to-match-bitcoin-addresses
if (input.matches("^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$")) {
if (verifyChecksum(input))
return new ValidationResult(true);
try {
new Address(MainNetParams.get(), input);
return new ValidationResult(true);
} catch (AddressFormatException e) {
return new ValidationResult(false, getErrorMessage(e));
}
else
return wrongStructure;
return wrongChecksum;
} else {
return wrongChecksum;
return regexTestFailed;
}
case "IOP":
if (input.matches("^[p][a-km-zA-HJ-NP-Z1-9]{25,34}$")) {
if (verifyChecksum(input)) {
try {
new Address(IOPParams.get(), input);
return new ValidationResult(true);
} catch (AddressFormatException e) {
return new ValidationResult(false, getErrorMessage(e));
}
} else {
return wrongChecksum;
}
} else {
return regexTestFailed;
}
case "ZEC":
// We only support t addresses (transparent transactions)
@ -67,6 +93,8 @@ public final class AltCoinAddressValidator extends InputValidator {
return validationResult;
else
return new ValidationResult(false, "ZEC address need to start with t. Addresses starting with z are not supported.");
case "GBYTE":
return ByteballAddressValidator.validate(input);
default:
log.debug("Validation for AltCoinAddress not implemented yet. currencyCode:" + currencyCode);
return validationResult;
@ -74,6 +102,11 @@ public final class AltCoinAddressValidator extends InputValidator {
}
}
@NotNull
private String getErrorMessage(AddressFormatException e) {
return "Address is not a valid " + currencyCode + " address! " + e.getMessage();
}
private boolean verifyChecksum(String input) {
// TODO
return true;

View file

@ -0,0 +1,178 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.util.validation.altcoins;
import io.bitsquare.gui.util.validation.InputValidator;
import org.apache.commons.codec.binary.Base32;
import org.apache.commons.codec.binary.Base64;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Created by DevAlexey on 19.12.2016.
*/
public class ByteballAddressValidator {
private static final Base32 base32 = new Base32();
private static final Base64 base64 = new Base64();
private static final String PI = "14159265358979323846264338327950288419716939937510";
private static final String[] arrRelativeOffsets = PI.split("");
private static Integer[] arrOffsets160, arrOffsets288;
static {
try {
arrOffsets160 = calcOffsets(160);
} catch (Exception e) {
e.printStackTrace();
}
try {
arrOffsets288 = calcOffsets(288);
} catch (Exception e) {
e.printStackTrace();
}
}
public static InputValidator.ValidationResult validate(String input) {
return new InputValidator.ValidationResult(isValidAddress(input));
}
private static boolean isValidAddress(String address) {
return isValidChash(address, 32);
}
private static boolean isValidChash(String str, int len) {
return (isStringOfLength(str, len) && isChashValid(str));
}
private static boolean isStringOfLength(String str, int len) {
return str.length() == len;
}
private static void checkLength(int chash_length) throws Exception {
if (chash_length != 160 && chash_length != 288)
throw new Exception("unsupported c-hash length: " + chash_length);
}
private static Integer[] calcOffsets(int chash_length) throws Exception {
checkLength(chash_length);
List<Integer> arrOffsets = new ArrayList<>(chash_length);
int offset = 0;
int index = 0;
for (int i = 0; offset < chash_length; i++) {
int relative_offset = Integer.parseInt(arrRelativeOffsets[i]);
if (relative_offset == 0)
continue;
offset += relative_offset;
if (chash_length == 288)
offset += 4;
if (offset >= chash_length)
break;
arrOffsets.add(offset);
//console.log("index="+index+", offset="+offset);
index++;
}
if (index != 32)
throw new Exception("wrong number of checksum bits");
return arrOffsets.toArray(new Integer[0]);
}
private static SeparatedData separateIntoCleanDataAndChecksum(String bin) throws Exception {
int len = bin.length();
Integer[] arrOffsets;
if (len == 160)
arrOffsets = arrOffsets160;
else if (len == 288)
arrOffsets = arrOffsets288;
else
throw new Exception("bad length");
StringBuilder arrFrags = new StringBuilder();
StringBuilder arrChecksumBits = new StringBuilder();
int start = 0;
for (int i = 0; i < arrOffsets.length; i++) {
arrFrags.append(bin.substring(start, arrOffsets[i]));
arrChecksumBits.append(bin.substring(arrOffsets[i], arrOffsets[i] + 1));
start = arrOffsets[i] + 1;
}
// add last frag
if (start < bin.length())
arrFrags.append(bin.substring(start));
String binCleanData = arrFrags.toString();
String binChecksum = arrChecksumBits.toString();
return new SeparatedData(binCleanData, binChecksum);
}
private static String buffer2bin(byte[] buf) {
StringBuffer bytes = new StringBuffer();
for (int i = 0; i < buf.length; i++) {
String bin = String.format("%8s", Integer.toBinaryString(buf[i] & 0xFF)).replace(' ', '0');
bytes.append(bin);
}
return bytes.toString();
}
private static byte[] bin2buffer(String bin) {
int len = bin.length() / 8;
byte[] buf = new byte[len];
for (int i = 0; i < len; i++)
buf[i] = (byte) Integer.parseInt(bin.substring(i * 8, (i + 1) * 8), 2);
return buf;
}
private static boolean isChashValid(String encoded) {
int encoded_len = encoded.length();
if (encoded_len != 32 && encoded_len != 48) // 160/5 = 32, 288/6 = 48
return false;
byte[] chash = (encoded_len == 32) ? base32.decode(encoded) : base64.decode(encoded);
String binChash = buffer2bin(chash);
SeparatedData separated = null;
try {
separated = separateIntoCleanDataAndChecksum(binChash);
} catch (Exception e) {
return false;
}
byte[] clean_data = bin2buffer(separated.clean_data);
byte[] checksum = bin2buffer(separated.checksum);
return Arrays.equals(getChecksum(clean_data), checksum);
}
private static byte[] getChecksum(byte[] clean_data) {
try {
byte[] full_checksum = MessageDigest.getInstance("SHA-256").digest(clean_data);
byte[] checksum = {full_checksum[5], full_checksum[13], full_checksum[21], full_checksum[29]};
return checksum;
} catch (NoSuchAlgorithmException e) {
return null;
}
}
private static class SeparatedData {
String clean_data, checksum;
public SeparatedData(String clean_data, String checksum) {
this.clean_data = clean_data;
this.checksum = checksum;
}
}
}

View file

@ -0,0 +1,78 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.util.validation.params;
import org.bitcoinj.core.*;
import org.bitcoinj.store.BlockStore;
import org.bitcoinj.store.BlockStoreException;
import org.bitcoinj.utils.MonetaryFormat;
public class IOPParams extends NetworkParameters {
private static IOPParams instance;
public static synchronized IOPParams get() {
if (instance == null) {
instance = new IOPParams();
}
return instance;
}
// We only use the properties needed for address validation
public IOPParams() {
super();
addressHeader = 117;
p2shHeader = 174;
acceptableAddressCodes = new int[]{addressHeader, p2shHeader};
}
// default dummy implementations, not used...
@Override
public String getPaymentProtocolId() {
return PAYMENT_PROTOCOL_ID_MAINNET;
}
@Override
public void checkDifficultyTransitions(StoredBlock storedPrev, Block next, BlockStore blockStore) throws VerificationException, BlockStoreException {
}
@Override
public Coin getMaxMoney() {
return null;
}
@Override
public Coin getMinNonDustOutput() {
return null;
}
@Override
public MonetaryFormat getMonetaryFormat() {
return null;
}
@Override
public String getUriScheme() {
return null;
}
@Override
public boolean hasMaxMoney() {
return false;
}
}

View file

@ -39,4 +39,28 @@ public class AltCoinAddressValidatorTest {
assertFalse(validator.validate("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhek#").isValid);
}
@Test
public void testIOP() {
AltCoinAddressValidator validator = new AltCoinAddressValidator();
validator.setCurrencyCode("IOP");
assertTrue(validator.validate("pKbz7iRUSiUaTgh4UuwQCnc6pWZnyCGWxM").isValid);
assertTrue(validator.validate("pAubDQFjUMaR93V4RjHYFh1YW1dzJ9YPW1").isValid);
assertFalse(validator.validate("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem").isValid);
}
@Test
public void testGBYTE() {
AltCoinAddressValidator validator = new AltCoinAddressValidator();
validator.setCurrencyCode("GBYTE");
assertTrue(validator.validate("BN7JXKXWEG4BVJ7NW6Q3Z7SMJNZJYM3G").isValid);
assertTrue(validator.validate("XGKZODTTTRXIUA75TKONWHFDCU6634DE").isValid);
assertFalse(validator.validate("XGKZODTGTRXIUA75TKONWHFDCU6634DE").isValid);
assertFalse(validator.validate("XGKZODTTTRXIUA75TKONWHFDCU6634D").isValid);
assertFalse(validator.validate("XGKZODTTTRXIUA75TKONWHFDCU6634DZ").isValid);
}
}

17
pom.xml
View file

@ -38,7 +38,6 @@
</properties>
<modules>
<module>api</module>
<module>common</module>
<module>core</module>
<module>jsocks</module>
@ -151,32 +150,32 @@
<artifactId>annotations</artifactId>
<version>13.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
<!--logging-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.1.7</version>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.7</version>
<version>1.1.3</version>
</dependency>
<!--unit test-->