mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-23 15:00:30 +01:00
Merge remote-tracking branch 'origin/Development' into issue544-api
Conflicts: pom.xml
This commit is contained in:
commit
cfade401bd
7 changed files with 331 additions and 15 deletions
|
@ -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",
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
17
pom.xml
|
@ -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-->
|
||||
|
|
Loading…
Add table
Reference in a new issue